PostgreSQL Source Code  git master
spccache.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * spccache.c
4  * Tablespace cache management.
5  *
6  * We cache the parsed version of spcoptions for each tablespace to avoid
7  * needing to reparse on every lookup. Right now, there doesn't appear to
8  * be a measurable performance gain from doing this, but that might change
9  * in the future as we add more options.
10  *
11  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
12  * Portions Copyright (c) 1994, Regents of the University of California
13  *
14  * IDENTIFICATION
15  * src/backend/utils/cache/spccache.c
16  *
17  *-------------------------------------------------------------------------
18  */
19 #include "postgres.h"
20 
21 #include "access/reloptions.h"
22 #include "catalog/pg_tablespace.h"
23 #include "commands/tablespace.h"
24 #include "miscadmin.h"
25 #include "optimizer/optimizer.h"
26 #include "storage/bufmgr.h"
27 #include "utils/catcache.h"
28 #include "utils/hsearch.h"
29 #include "utils/inval.h"
30 #include "utils/spccache.h"
31 #include "utils/syscache.h"
32 #include "varatt.h"
33 
34 
35 /* Hash table for information about each tablespace */
36 static HTAB *TableSpaceCacheHash = NULL;
37 
38 typedef struct
39 {
40  Oid oid; /* lookup key - must be first */
41  TableSpaceOpts *opts; /* options, or NULL if none */
43 
44 
45 /*
46  * InvalidateTableSpaceCacheCallback
47  * Flush all cache entries when pg_tablespace is updated.
48  *
49  * When pg_tablespace is updated, we must flush the cache entry at least
50  * for that tablespace. Currently, we just flush them all. This is quick
51  * and easy and doesn't cost much, since there shouldn't be terribly many
52  * tablespaces, nor do we expect them to be frequently modified.
53  */
54 static void
56 {
57  HASH_SEQ_STATUS status;
59 
61  while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
62  {
63  if (spc->opts)
64  pfree(spc->opts);
66  &spc->oid,
68  NULL) == NULL)
69  elog(ERROR, "hash table corrupted");
70  }
71 }
72 
73 /*
74  * InitializeTableSpaceCache
75  * Initialize the tablespace cache.
76  */
77 static void
79 {
80  HASHCTL ctl;
81 
82  /* Initialize the hash table. */
83  ctl.keysize = sizeof(Oid);
84  ctl.entrysize = sizeof(TableSpaceCacheEntry);
86  hash_create("TableSpace cache", 16, &ctl,
88 
89  /* Make sure we've initialized CacheMemoryContext. */
90  if (!CacheMemoryContext)
92 
93  /* Watch for invalidation events. */
94  CacheRegisterSyscacheCallback(TABLESPACEOID,
96  (Datum) 0);
97 }
98 
99 /*
100  * get_tablespace
101  * Fetch TableSpaceCacheEntry structure for a specified table OID.
102  *
103  * Pointers returned by this function should not be stored, since a cache
104  * flush will invalidate them.
105  */
106 static TableSpaceCacheEntry *
108 {
110  HeapTuple tp;
112 
113  /*
114  * Since spcid is always from a pg_class tuple, InvalidOid implies the
115  * default.
116  */
117  if (spcid == InvalidOid)
118  spcid = MyDatabaseTableSpace;
119 
120  /* Find existing cache entry, if any. */
121  if (!TableSpaceCacheHash)
124  &spcid,
125  HASH_FIND,
126  NULL);
127  if (spc)
128  return spc;
129 
130  /*
131  * Not found in TableSpace cache. Check catcache. If we don't find a
132  * valid HeapTuple, it must mean someone has managed to request tablespace
133  * details for a non-existent tablespace. We'll just treat that case as
134  * if no options were specified.
135  */
136  tp = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spcid));
137  if (!HeapTupleIsValid(tp))
138  opts = NULL;
139  else
140  {
141  Datum datum;
142  bool isNull;
143 
144  datum = SysCacheGetAttr(TABLESPACEOID,
145  tp,
146  Anum_pg_tablespace_spcoptions,
147  &isNull);
148  if (isNull)
149  opts = NULL;
150  else
151  {
152  bytea *bytea_opts = tablespace_reloptions(datum, false);
153 
155  memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
156  }
157  ReleaseSysCache(tp);
158  }
159 
160  /*
161  * Now create the cache entry. It's important to do this only after
162  * reading the pg_tablespace entry, since doing so could cause a cache
163  * flush.
164  */
166  &spcid,
167  HASH_ENTER,
168  NULL);
169  spc->opts = opts;
170  return spc;
171 }
172 
173 /*
174  * get_tablespace_page_costs
175  * Return random and/or sequential page costs for a given tablespace.
176  *
177  * This value is not locked by the transaction, so this value may
178  * be changed while a SELECT that has used these values for planning
179  * is still executing.
180  */
181 void
183  double *spc_random_page_cost,
184  double *spc_seq_page_cost)
185 {
186  TableSpaceCacheEntry *spc = get_tablespace(spcid);
187 
188  Assert(spc != NULL);
189 
190  if (spc_random_page_cost)
191  {
192  if (!spc->opts || spc->opts->random_page_cost < 0)
193  *spc_random_page_cost = random_page_cost;
194  else
195  *spc_random_page_cost = spc->opts->random_page_cost;
196  }
197 
198  if (spc_seq_page_cost)
199  {
200  if (!spc->opts || spc->opts->seq_page_cost < 0)
201  *spc_seq_page_cost = seq_page_cost;
202  else
203  *spc_seq_page_cost = spc->opts->seq_page_cost;
204  }
205 }
206 
207 /*
208  * get_tablespace_io_concurrency
209  *
210  * This value is not locked by the transaction, so this value may
211  * be changed while a SELECT that has used these values for planning
212  * is still executing.
213  */
214 int
216 {
217  TableSpaceCacheEntry *spc = get_tablespace(spcid);
218 
219  if (!spc->opts || spc->opts->effective_io_concurrency < 0)
221  else
222  return spc->opts->effective_io_concurrency;
223 }
224 
225 /*
226  * get_tablespace_maintenance_io_concurrency
227  */
228 int
230 {
231  TableSpaceCacheEntry *spc = get_tablespace(spcid);
232 
233  if (!spc->opts || spc->opts->maintenance_io_concurrency < 0)
235  else
236  return spc->opts->maintenance_io_concurrency;
237 }
int maintenance_io_concurrency
Definition: bufmgr.c:157
int effective_io_concurrency
Definition: bufmgr.c:150
unsigned int uint32
Definition: c.h:506
#define Assert(condition)
Definition: c.h:858
void CreateCacheMemoryContext(void)
Definition: catcache.c:679
double random_page_cost
Definition: costsize.c:120
double seq_page_cost
Definition: costsize.c:119
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1395
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
Oid MyDatabaseTableSpace
Definition: globals.c:93
@ HASH_FIND
Definition: hsearch.h:113
@ HASH_REMOVE
Definition: hsearch.h:115
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1516
void pfree(void *pointer)
Definition: mcxt.c:1520
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1180
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
static AmcheckOptions opts
Definition: pg_amcheck.c:111
void * arg
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
tree ctl
Definition: radixtree.h:1847
bytea * tablespace_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:2086
static TableSpaceCacheEntry * get_tablespace(Oid spcid)
Definition: spccache.c:107
static void InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: spccache.c:55
int get_tablespace_io_concurrency(Oid spcid)
Definition: spccache.c:215
static void InitializeTableSpaceCache(void)
Definition: spccache.c:78
void get_tablespace_page_costs(Oid spcid, double *spc_random_page_cost, double *spc_seq_page_cost)
Definition: spccache.c:182
static HTAB * TableSpaceCacheHash
Definition: spccache.c:36
int get_tablespace_maintenance_io_concurrency(Oid spcid)
Definition: spccache.c:229
Definition: dynahash.c:220
TableSpaceOpts * opts
Definition: spccache.c:41
int maintenance_io_concurrency
Definition: tablespace.h:45
float8 random_page_cost
Definition: tablespace.h:42
int effective_io_concurrency
Definition: tablespace.h:44
float8 seq_page_cost
Definition: tablespace.h:43
Definition: c.h:687
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479
#define VARSIZE(PTR)
Definition: varatt.h:279