Header And Logo

PostgreSQL
| The world's most advanced open source database.

attoptcache.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * attoptcache.c
00004  *    Attribute options cache management.
00005  *
00006  * Attribute options are cached separately from the fixed-size portion of
00007  * pg_attribute entries, which are handled by the relcache.
00008  *
00009  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00010  * Portions Copyright (c) 1994, Regents of the University of California
00011  *
00012  * IDENTIFICATION
00013  *    src/backend/utils/cache/attoptcache.c
00014  *
00015  *-------------------------------------------------------------------------
00016  */
00017 #include "postgres.h"
00018 
00019 #include "access/reloptions.h"
00020 #include "utils/attoptcache.h"
00021 #include "utils/catcache.h"
00022 #include "utils/hsearch.h"
00023 #include "utils/inval.h"
00024 #include "utils/syscache.h"
00025 
00026 
00027 /* Hash table for informations about each attribute's options */
00028 static HTAB *AttoptCacheHash = NULL;
00029 
00030 /* attrelid and attnum form the lookup key, and must appear first */
00031 typedef struct
00032 {
00033     Oid         attrelid;
00034     int         attnum;
00035 } AttoptCacheKey;
00036 
00037 typedef struct
00038 {
00039     AttoptCacheKey key;         /* lookup key - must be first */
00040     AttributeOpts *opts;        /* options, or NULL if none */
00041 } AttoptCacheEntry;
00042 
00043 
00044 /*
00045  * InvalidateAttoptCacheCallback
00046  *      Flush all cache entries when pg_attribute is updated.
00047  *
00048  * When pg_attribute is updated, we must flush the cache entry at least
00049  * for that attribute.  Currently, we just flush them all.  Since attribute
00050  * options are not currently used in performance-critical paths (such as
00051  * query execution), this seems OK.
00052  */
00053 static void
00054 InvalidateAttoptCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
00055 {
00056     HASH_SEQ_STATUS status;
00057     AttoptCacheEntry *attopt;
00058 
00059     hash_seq_init(&status, AttoptCacheHash);
00060     while ((attopt = (AttoptCacheEntry *) hash_seq_search(&status)) != NULL)
00061     {
00062         if (attopt->opts)
00063             pfree(attopt->opts);
00064         if (hash_search(AttoptCacheHash,
00065                         (void *) &attopt->key,
00066                         HASH_REMOVE,
00067                         NULL) == NULL)
00068             elog(ERROR, "hash table corrupted");
00069     }
00070 }
00071 
00072 /*
00073  * InitializeAttoptCache
00074  *      Initialize the tablespace cache.
00075  */
00076 static void
00077 InitializeAttoptCache(void)
00078 {
00079     HASHCTL     ctl;
00080 
00081     /* Initialize the hash table. */
00082     MemSet(&ctl, 0, sizeof(ctl));
00083     ctl.keysize = sizeof(AttoptCacheKey);
00084     ctl.entrysize = sizeof(AttoptCacheEntry);
00085     ctl.hash = tag_hash;
00086     AttoptCacheHash =
00087         hash_create("Attopt cache", 256, &ctl,
00088                     HASH_ELEM | HASH_FUNCTION);
00089 
00090     /* Make sure we've initialized CacheMemoryContext. */
00091     if (!CacheMemoryContext)
00092         CreateCacheMemoryContext();
00093 
00094     /* Watch for invalidation events. */
00095     CacheRegisterSyscacheCallback(ATTNUM,
00096                                   InvalidateAttoptCacheCallback,
00097                                   (Datum) 0);
00098 }
00099 
00100 /*
00101  * get_attribute_options
00102  *      Fetch attribute options for a specified table OID.
00103  */
00104 AttributeOpts *
00105 get_attribute_options(Oid attrelid, int attnum)
00106 {
00107     AttoptCacheKey key;
00108     AttoptCacheEntry *attopt;
00109     AttributeOpts *result;
00110     HeapTuple   tp;
00111 
00112     /* Find existing cache entry, if any. */
00113     if (!AttoptCacheHash)
00114         InitializeAttoptCache();
00115     memset(&key, 0, sizeof(key));       /* make sure any padding bits are
00116                                          * unset */
00117     key.attrelid = attrelid;
00118     key.attnum = attnum;
00119     attopt =
00120         (AttoptCacheEntry *) hash_search(AttoptCacheHash,
00121                                          (void *) &key,
00122                                          HASH_FIND,
00123                                          NULL);
00124 
00125     /* Not found in Attopt cache.  Construct new cache entry. */
00126     if (!attopt)
00127     {
00128         AttributeOpts *opts;
00129 
00130         tp = SearchSysCache2(ATTNUM,
00131                              ObjectIdGetDatum(attrelid),
00132                              Int16GetDatum(attnum));
00133 
00134         /*
00135          * If we don't find a valid HeapTuple, it must mean someone has
00136          * managed to request attribute details for a non-existent attribute.
00137          * We treat that case as if no options were specified.
00138          */
00139         if (!HeapTupleIsValid(tp))
00140             opts = NULL;
00141         else
00142         {
00143             Datum       datum;
00144             bool        isNull;
00145 
00146             datum = SysCacheGetAttr(ATTNUM,
00147                                     tp,
00148                                     Anum_pg_attribute_attoptions,
00149                                     &isNull);
00150             if (isNull)
00151                 opts = NULL;
00152             else
00153             {
00154                 bytea      *bytea_opts = attribute_reloptions(datum, false);
00155 
00156                 opts = MemoryContextAlloc(CacheMemoryContext,
00157                                           VARSIZE(bytea_opts));
00158                 memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
00159             }
00160             ReleaseSysCache(tp);
00161         }
00162 
00163         /*
00164          * It's important to create the actual cache entry only after reading
00165          * pg_attribute, since the read could cause a cache flush.
00166          */
00167         attopt = (AttoptCacheEntry *) hash_search(AttoptCacheHash,
00168                                                   (void *) &key,
00169                                                   HASH_ENTER,
00170                                                   NULL);
00171         attopt->opts = opts;
00172     }
00173 
00174     /* Return results in caller's memory context. */
00175     if (attopt->opts == NULL)
00176         return NULL;
00177     result = palloc(VARSIZE(attopt->opts));
00178     memcpy(result, attopt->opts, VARSIZE(attopt->opts));
00179     return result;
00180 }