PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2017, 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/cost.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 
33 
34 /* Hash table for information about each tablespace */
36 
37 typedef struct
38 {
39  Oid oid; /* lookup key - must be first */
40  TableSpaceOpts *opts; /* options, or NULL if none */
42 
43 
44 /*
45  * InvalidateTableSpaceCacheCallback
46  * Flush all cache entries when pg_tablespace is updated.
47  *
48  * When pg_tablespace is updated, we must flush the cache entry at least
49  * for that tablespace. Currently, we just flush them all. This is quick
50  * and easy and doesn't cost much, since there shouldn't be terribly many
51  * tablespaces, nor do we expect them to be frequently modified.
52  */
53 static void
55 {
58 
59  hash_seq_init(&status, TableSpaceCacheHash);
60  while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
61  {
62  if (spc->opts)
63  pfree(spc->opts);
64  if (hash_search(TableSpaceCacheHash,
65  (void *) &spc->oid,
67  NULL) == NULL)
68  elog(ERROR, "hash table corrupted");
69  }
70 }
71 
72 /*
73  * InitializeTableSpaceCache
74  * Initialize the tablespace cache.
75  */
76 static void
78 {
79  HASHCTL ctl;
80 
81  /* Initialize the hash table. */
82  MemSet(&ctl, 0, sizeof(ctl));
83  ctl.keysize = sizeof(Oid);
84  ctl.entrysize = sizeof(TableSpaceCacheEntry);
85  TableSpaceCacheHash =
86  hash_create("TableSpace cache", 16, &ctl,
88 
89  /* Make sure we've initialized CacheMemoryContext. */
90  if (!CacheMemoryContext)
92 
93  /* Watch for invalidation events. */
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;
111  TableSpaceOpts *opts;
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)
123  spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
124  (void *) &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  */
137  if (!HeapTupleIsValid(tp))
138  opts = NULL;
139  else
140  {
141  Datum datum;
142  bool isNull;
143 
145  tp,
147  &isNull);
148  if (isNull)
149  opts = NULL;
150  else
151  {
152  bytea *bytea_opts = tablespace_reloptions(datum, false);
153 
154  opts = MemoryContextAlloc(CacheMemoryContext, VARSIZE(bytea_opts));
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  */
165  spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
166  (void *) &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 }
#define HASH_ELEM
Definition: hsearch.h:87
#define VARSIZE(PTR)
Definition: postgres.h:304
static TableSpaceCacheEntry * get_tablespace(Oid spcid)
Definition: spccache.c:107
float8 random_page_cost
Definition: tablespace.h:40
Size entrysize
Definition: hsearch.h:73
bytea * tablespace_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:1493
int get_tablespace_io_concurrency(Oid spcid)
Definition: spccache.c:215
#define MemSet(start, val, len)
Definition: c.h:857
TableSpaceOpts * opts
Definition: spccache.c:40
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
unsigned int Oid
Definition: postgres_ext.h:31
int effective_io_concurrency
Definition: bufmgr.c:112
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
Oid MyDatabaseTableSpace
Definition: globals.c:79
float8 seq_page_cost
Definition: tablespace.h:41
Definition: dynahash.c:193
double random_page_cost
Definition: costsize.c:105
void pfree(void *pointer)
Definition: mcxt.c:950
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
static HTAB * TableSpaceCacheHash
Definition: spccache.c:35
unsigned int uint32
Definition: c.h:268
void get_tablespace_page_costs(Oid spcid, double *spc_random_page_cost, double *spc_seq_page_cost)
Definition: spccache.c:182
#define HASH_BLOBS
Definition: hsearch.h:88
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1389
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:301
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1279
Size keysize
Definition: hsearch.h:72
static void InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: spccache.c:54
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
void CreateCacheMemoryContext(void)
Definition: catcache.c:511
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1351
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1341
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:707
static void InitializeTableSpaceCache(void)
Definition: spccache.c:77
#define Anum_pg_tablespace_spcoptions
Definition: pg_tablespace.h:58
void * arg
Definition: c.h:439
#define elog
Definition: elog.h:219
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
double seq_page_cost
Definition: costsize.c:104
int effective_io_concurrency
Definition: tablespace.h:42
MemoryContext CacheMemoryContext
Definition: mcxt.c:46