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 void
179  double *spc_random_page_cost,
180  double *spc_seq_page_cost)
181 {
182  TableSpaceCacheEntry *spc = get_tablespace(spcid);
183 
184  Assert(spc != NULL);
185 
186  if (spc_random_page_cost)
187  {
188  if (!spc->opts || spc->opts->random_page_cost < 0)
189  *spc_random_page_cost = random_page_cost;
190  else
191  *spc_random_page_cost = spc->opts->random_page_cost;
192  }
193 
194  if (spc_seq_page_cost)
195  {
196  if (!spc->opts || spc->opts->seq_page_cost < 0)
197  *spc_seq_page_cost = seq_page_cost;
198  else
199  *spc_seq_page_cost = spc->opts->seq_page_cost;
200  }
201 }
202 
203 int
205 {
206  TableSpaceCacheEntry *spc = get_tablespace(spcid);
207 
208  if (!spc->opts || spc->opts->effective_io_concurrency < 0)
210  else
211  return spc->opts->effective_io_concurrency;
212 }
#define HASH_ELEM
Definition: hsearch.h:87
#define VARSIZE(PTR)
Definition: postgres.h:306
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:1450
int get_tablespace_io_concurrency(Oid spcid)
Definition: spccache.c:204
#define MemSet(start, val, len)
Definition: c.h:853
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:149
Oid MyDatabaseTableSpace
Definition: globals.c:78
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:992
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
static HTAB * TableSpaceCacheHash
Definition: spccache.c:35
unsigned int uint32
Definition: c.h:265
void get_tablespace_page_costs(Oid spcid, double *spc_random_page_cost, double *spc_seq_page_cost)
Definition: spccache.c:178
#define HASH_BLOBS
Definition: hsearch.h:88
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1381
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:301
uintptr_t Datum
Definition: postgres.h:374
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1083
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1245
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:226
#define Assert(condition)
Definition: c.h:671
void CreateCacheMemoryContext(void)
Definition: catcache.c:525
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1353
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1343
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:749
static void InitializeTableSpaceCache(void)
Definition: spccache.c:77
#define Anum_pg_tablespace_spcoptions
Definition: pg_tablespace.h:58
void * arg
Definition: c.h:435
#define elog
Definition: elog.h:219
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:222
double seq_page_cost
Definition: costsize.c:104
int effective_io_concurrency
Definition: tablespace.h:42
MemoryContext CacheMemoryContext
Definition: mcxt.c:46