LCOV - code coverage report
Current view: top level - src/backend/utils/cache - attoptcache.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 43 46 93.5 %
Date: 2019-06-18 07:06:57 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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-2019, 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             : 
      26             : 
      27             : /* Hash table for information about each attribute's options */
      28             : static HTAB *AttoptCacheHash = NULL;
      29             : 
      30             : /* attrelid and attnum form the lookup key, and must appear first */
      31             : typedef struct
      32             : {
      33             :     Oid         attrelid;
      34             :     int         attnum;
      35             : } AttoptCacheKey;
      36             : 
      37             : typedef struct
      38             : {
      39             :     AttoptCacheKey key;         /* lookup key - must be first */
      40             :     AttributeOpts *opts;        /* options, or NULL if none */
      41             : } AttoptCacheEntry;
      42             : 
      43             : 
      44             : /*
      45             :  * InvalidateAttoptCacheCallback
      46             :  *      Flush all cache entries when pg_attribute is updated.
      47             :  *
      48             :  * When pg_attribute is updated, we must flush the cache entry at least
      49             :  * for that attribute.  Currently, we just flush them all.  Since attribute
      50             :  * options are not currently used in performance-critical paths (such as
      51             :  * query execution), this seems OK.
      52             :  */
      53             : static void
      54      182914 : InvalidateAttoptCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
      55             : {
      56             :     HASH_SEQ_STATUS status;
      57             :     AttoptCacheEntry *attopt;
      58             : 
      59      182914 :     hash_seq_init(&status, AttoptCacheHash);
      60      182914 :     while ((attopt = (AttoptCacheEntry *) hash_seq_search(&status)) != NULL)
      61             :     {
      62        3620 :         if (attopt->opts)
      63           4 :             pfree(attopt->opts);
      64        3620 :         if (hash_search(AttoptCacheHash,
      65        3620 :                         (void *) &attopt->key,
      66             :                         HASH_REMOVE,
      67             :                         NULL) == NULL)
      68           0 :             elog(ERROR, "hash table corrupted");
      69             :     }
      70      182914 : }
      71             : 
      72             : /*
      73             :  * InitializeAttoptCache
      74             :  *      Initialize the attribute options cache.
      75             :  */
      76             : static void
      77         546 : InitializeAttoptCache(void)
      78             : {
      79             :     HASHCTL     ctl;
      80             : 
      81             :     /* Initialize the hash table. */
      82         546 :     MemSet(&ctl, 0, sizeof(ctl));
      83         546 :     ctl.keysize = sizeof(AttoptCacheKey);
      84         546 :     ctl.entrysize = sizeof(AttoptCacheEntry);
      85         546 :     AttoptCacheHash =
      86         546 :         hash_create("Attopt cache", 256, &ctl,
      87             :                     HASH_ELEM | HASH_BLOBS);
      88             : 
      89             :     /* Make sure we've initialized CacheMemoryContext. */
      90         546 :     if (!CacheMemoryContext)
      91           0 :         CreateCacheMemoryContext();
      92             : 
      93             :     /* Watch for invalidation events. */
      94         546 :     CacheRegisterSyscacheCallback(ATTNUM,
      95             :                                   InvalidateAttoptCacheCallback,
      96             :                                   (Datum) 0);
      97         546 : }
      98             : 
      99             : /*
     100             :  * get_attribute_options
     101             :  *      Fetch attribute options for a specified table OID.
     102             :  */
     103             : AttributeOpts *
     104      186632 : get_attribute_options(Oid attrelid, int attnum)
     105             : {
     106             :     AttoptCacheKey key;
     107             :     AttoptCacheEntry *attopt;
     108             :     AttributeOpts *result;
     109             :     HeapTuple   tp;
     110             : 
     111             :     /* Find existing cache entry, if any. */
     112      186632 :     if (!AttoptCacheHash)
     113         546 :         InitializeAttoptCache();
     114      186632 :     memset(&key, 0, sizeof(key));   /* make sure any padding bits are unset */
     115      186632 :     key.attrelid = attrelid;
     116      186632 :     key.attnum = attnum;
     117      186632 :     attopt =
     118      186632 :         (AttoptCacheEntry *) hash_search(AttoptCacheHash,
     119             :                                          (void *) &key,
     120             :                                          HASH_FIND,
     121             :                                          NULL);
     122             : 
     123             :     /* Not found in Attopt cache.  Construct new cache entry. */
     124      186632 :     if (!attopt)
     125             :     {
     126             :         AttributeOpts *opts;
     127             : 
     128      186006 :         tp = SearchSysCache2(ATTNUM,
     129             :                              ObjectIdGetDatum(attrelid),
     130             :                              Int16GetDatum(attnum));
     131             : 
     132             :         /*
     133             :          * If we don't find a valid HeapTuple, it must mean someone has
     134             :          * managed to request attribute details for a non-existent attribute.
     135             :          * We treat that case as if no options were specified.
     136             :          */
     137      186006 :         if (!HeapTupleIsValid(tp))
     138           0 :             opts = NULL;
     139             :         else
     140             :         {
     141             :             Datum       datum;
     142             :             bool        isNull;
     143             : 
     144      186006 :             datum = SysCacheGetAttr(ATTNUM,
     145             :                                     tp,
     146             :                                     Anum_pg_attribute_attoptions,
     147             :                                     &isNull);
     148      186006 :             if (isNull)
     149      186002 :                 opts = NULL;
     150             :             else
     151             :             {
     152           4 :                 bytea      *bytea_opts = attribute_reloptions(datum, false);
     153             : 
     154           4 :                 opts = MemoryContextAlloc(CacheMemoryContext,
     155           4 :                                           VARSIZE(bytea_opts));
     156           4 :                 memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
     157             :             }
     158      186006 :             ReleaseSysCache(tp);
     159             :         }
     160             : 
     161             :         /*
     162             :          * It's important to create the actual cache entry only after reading
     163             :          * pg_attribute, since the read could cause a cache flush.
     164             :          */
     165      186006 :         attopt = (AttoptCacheEntry *) hash_search(AttoptCacheHash,
     166             :                                                   (void *) &key,
     167             :                                                   HASH_ENTER,
     168             :                                                   NULL);
     169      186006 :         attopt->opts = opts;
     170             :     }
     171             : 
     172             :     /* Return results in caller's memory context. */
     173      186632 :     if (attopt->opts == NULL)
     174      186628 :         return NULL;
     175           4 :     result = palloc(VARSIZE(attopt->opts));
     176           4 :     memcpy(result, attopt->opts, VARSIZE(attopt->opts));
     177           4 :     return result;
     178             : }

Generated by: LCOV version 1.13