PostgreSQL Source Code  git master
attoptcache.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * attoptcache.c
4  * Attribute options cache management.
5  *
6  * Attribute options are cached separately from the fixed-size portion of
7  * pg_attribute entries, which are handled by the relcache.
8  *
9  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
10  * Portions Copyright (c) 1994, Regents of the University of California
11  *
12  * IDENTIFICATION
13  * src/backend/utils/cache/attoptcache.c
14  *
15  *-------------------------------------------------------------------------
16  */
17 #include "postgres.h"
18 
19 #include "access/reloptions.h"
20 #include "utils/attoptcache.h"
21 #include "utils/catcache.h"
22 #include "utils/hsearch.h"
23 #include "utils/inval.h"
24 #include "utils/syscache.h"
25 #include "varatt.h"
26 
27 
28 /* Hash table for information about each attribute's options */
29 static HTAB *AttoptCacheHash = NULL;
30 
31 /* attrelid and attnum form the lookup key, and must appear first */
32 typedef struct
33 {
35  int attnum;
37 
38 typedef struct
39 {
40  AttoptCacheKey key; /* lookup key - must be first */
41  AttributeOpts *opts; /* options, or NULL if none */
43 
44 
45 /*
46  * InvalidateAttoptCacheCallback
47  * Flush cache entry (or entries) when pg_attribute is updated.
48  *
49  * When pg_attribute is updated, we must flush the cache entry at least
50  * for that attribute.
51  */
52 static void
54 {
55  HASH_SEQ_STATUS status;
56  AttoptCacheEntry *attopt;
57 
58  /*
59  * By convention, zero hash value is passed to the callback as a sign that
60  * it's time to invalidate the whole cache. See sinval.c, inval.c and
61  * InvalidateSystemCachesExtended().
62  */
63  if (hashvalue == 0)
65  else
67 
68  while ((attopt = (AttoptCacheEntry *) hash_seq_search(&status)) != NULL)
69  {
70  if (attopt->opts)
71  pfree(attopt->opts);
73  &attopt->key,
75  NULL) == NULL)
76  elog(ERROR, "hash table corrupted");
77  }
78 }
79 
80 /*
81  * Hash function compatible with two-arg system cache hash function.
82  */
83 static uint32
84 relatt_cache_syshash(const void *key, Size keysize)
85 {
86  const AttoptCacheKey *ckey = key;
87 
88  Assert(keysize == sizeof(*ckey));
89  return GetSysCacheHashValue2(ATTNUM, ckey->attrelid, ckey->attnum);
90 }
91 
92 /*
93  * InitializeAttoptCache
94  * Initialize the attribute options cache.
95  */
96 static void
98 {
99  HASHCTL ctl;
100 
101  /* Initialize the hash table. */
102  ctl.keysize = sizeof(AttoptCacheKey);
103  ctl.entrysize = sizeof(AttoptCacheEntry);
104 
105  /*
106  * AttoptCacheEntry takes hash value from the system cache. For
107  * AttoptCacheHash we use the same hash in order to speedup search by hash
108  * value. This is used by hash_seq_init_with_hash_value().
109  */
110  ctl.hash = relatt_cache_syshash;
111 
113  hash_create("Attopt cache", 256, &ctl,
115 
116  /* Make sure we've initialized CacheMemoryContext. */
117  if (!CacheMemoryContext)
119 
120  /* Watch for invalidation events. */
123  (Datum) 0);
124 }
125 
126 /*
127  * get_attribute_options
128  * Fetch attribute options for a specified table OID.
129  */
132 {
134  AttoptCacheEntry *attopt;
135  AttributeOpts *result;
136  HeapTuple tp;
137 
138  /* Find existing cache entry, if any. */
139  if (!AttoptCacheHash)
141  memset(&key, 0, sizeof(key)); /* make sure any padding bits are unset */
142  key.attrelid = attrelid;
143  key.attnum = attnum;
144  attopt =
146  &key,
147  HASH_FIND,
148  NULL);
149 
150  /* Not found in Attopt cache. Construct new cache entry. */
151  if (!attopt)
152  {
154 
155  tp = SearchSysCache2(ATTNUM,
156  ObjectIdGetDatum(attrelid),
158 
159  /*
160  * If we don't find a valid HeapTuple, it must mean someone has
161  * managed to request attribute details for a non-existent attribute.
162  * We treat that case as if no options were specified.
163  */
164  if (!HeapTupleIsValid(tp))
165  opts = NULL;
166  else
167  {
168  Datum datum;
169  bool isNull;
170 
171  datum = SysCacheGetAttr(ATTNUM,
172  tp,
173  Anum_pg_attribute_attoptions,
174  &isNull);
175  if (isNull)
176  opts = NULL;
177  else
178  {
179  bytea *bytea_opts = attribute_reloptions(datum, false);
180 
182  VARSIZE(bytea_opts));
183  memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
184  }
185  ReleaseSysCache(tp);
186  }
187 
188  /*
189  * It's important to create the actual cache entry only after reading
190  * pg_attribute, since the read could cause a cache flush.
191  */
193  &key,
194  HASH_ENTER,
195  NULL);
196  attopt->opts = opts;
197  }
198 
199  /* Return results in caller's memory context. */
200  if (attopt->opts == NULL)
201  return NULL;
202  result = palloc(VARSIZE(attopt->opts));
203  memcpy(result, attopt->opts, VARSIZE(attopt->opts));
204  return result;
205 }
static uint32 relatt_cache_syshash(const void *key, Size keysize)
Definition: attoptcache.c:84
AttributeOpts * get_attribute_options(Oid attrelid, int attnum)
Definition: attoptcache.c:131
static HTAB * AttoptCacheHash
Definition: attoptcache.c:29
static void InvalidateAttoptCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: attoptcache.c:53
static void InitializeAttoptCache(void)
Definition: attoptcache.c:97
unsigned int uint32
Definition: c.h:506
#define Assert(condition)
Definition: c.h:849
size_t Size
Definition: c.h:596
void CreateCacheMemoryContext(void)
Definition: catcache.c:680
void hash_seq_init_with_hash_value(HASH_SEQ_STATUS *status, HTAB *hashp, uint32 hashvalue)
Definition: dynahash.c:1405
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:1420
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:225
@ 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_FUNCTION
Definition: hsearch.h:98
#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:1521
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
void * palloc(Size size)
Definition: mcxt.c:1317
static AmcheckOptions opts
Definition: pg_amcheck.c:111
int16 attnum
Definition: pg_attribute.h:74
void * arg
uintptr_t Datum
Definition: postgres.h:64
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
unsigned int Oid
Definition: postgres_ext.h:31
tree ctl
Definition: radixtree.h:1853
bytea * attribute_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:2069
AttributeOpts * opts
Definition: attoptcache.c:41
AttoptCacheKey key
Definition: attoptcache.c:40
Definition: dynahash.c:220
Definition: c.h:678
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:596
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:232
#define GetSysCacheHashValue2(cacheId, key1, key2)
Definition: syscache.h:120
#define VARSIZE(PTR)
Definition: varatt.h:279