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

          Line data    Source code
       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-2019, 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/optimizer.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 */
      35             : static HTAB *TableSpaceCacheHash = NULL;
      36             : 
      37             : typedef struct
      38             : {
      39             :     Oid         oid;            /* lookup key - must be first */
      40             :     TableSpaceOpts *opts;       /* options, or NULL if none */
      41             : } TableSpaceCacheEntry;
      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
      54         202 : InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
      55             : {
      56             :     HASH_SEQ_STATUS status;
      57             :     TableSpaceCacheEntry *spc;
      58             : 
      59         202 :     hash_seq_init(&status, TableSpaceCacheHash);
      60         202 :     while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
      61             :     {
      62          92 :         if (spc->opts)
      63           4 :             pfree(spc->opts);
      64          92 :         if (hash_search(TableSpaceCacheHash,
      65          92 :                         (void *) &spc->oid,
      66             :                         HASH_REMOVE,
      67             :                         NULL) == NULL)
      68           0 :             elog(ERROR, "hash table corrupted");
      69             :     }
      70         202 : }
      71             : 
      72             : /*
      73             :  * InitializeTableSpaceCache
      74             :  *      Initialize the tablespace cache.
      75             :  */
      76             : static void
      77        3402 : InitializeTableSpaceCache(void)
      78             : {
      79             :     HASHCTL     ctl;
      80             : 
      81             :     /* Initialize the hash table. */
      82        3402 :     MemSet(&ctl, 0, sizeof(ctl));
      83        3402 :     ctl.keysize = sizeof(Oid);
      84        3402 :     ctl.entrysize = sizeof(TableSpaceCacheEntry);
      85        3402 :     TableSpaceCacheHash =
      86        3402 :         hash_create("TableSpace cache", 16, &ctl,
      87             :                     HASH_ELEM | HASH_BLOBS);
      88             : 
      89             :     /* Make sure we've initialized CacheMemoryContext. */
      90        3402 :     if (!CacheMemoryContext)
      91           0 :         CreateCacheMemoryContext();
      92             : 
      93             :     /* Watch for invalidation events. */
      94        3402 :     CacheRegisterSyscacheCallback(TABLESPACEOID,
      95             :                                   InvalidateTableSpaceCacheCallback,
      96             :                                   (Datum) 0);
      97        3402 : }
      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 *
     107     1225842 : get_tablespace(Oid spcid)
     108             : {
     109             :     TableSpaceCacheEntry *spc;
     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     1225842 :     if (spcid == InvalidOid)
     118     1155232 :         spcid = MyDatabaseTableSpace;
     119             : 
     120             :     /* Find existing cache entry, if any. */
     121     1225842 :     if (!TableSpaceCacheHash)
     122        3402 :         InitializeTableSpaceCache();
     123     1225842 :     spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
     124             :                                                (void *) &spcid,
     125             :                                                HASH_FIND,
     126             :                                                NULL);
     127     1225842 :     if (spc)
     128     1221650 :         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             :      */
     136        4192 :     tp = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spcid));
     137        4192 :     if (!HeapTupleIsValid(tp))
     138           0 :         opts = NULL;
     139             :     else
     140             :     {
     141             :         Datum       datum;
     142             :         bool        isNull;
     143             : 
     144        4192 :         datum = SysCacheGetAttr(TABLESPACEOID,
     145             :                                 tp,
     146             :                                 Anum_pg_tablespace_spcoptions,
     147             :                                 &isNull);
     148        4192 :         if (isNull)
     149        4188 :             opts = NULL;
     150             :         else
     151             :         {
     152           4 :             bytea      *bytea_opts = tablespace_reloptions(datum, false);
     153             : 
     154           4 :             opts = MemoryContextAlloc(CacheMemoryContext, VARSIZE(bytea_opts));
     155           4 :             memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
     156             :         }
     157        4192 :         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        4192 :     spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
     166             :                                                (void *) &spcid,
     167             :                                                HASH_ENTER,
     168             :                                                NULL);
     169        4192 :     spc->opts = opts;
     170        4192 :     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
     182     1206218 : get_tablespace_page_costs(Oid spcid,
     183             :                           double *spc_random_page_cost,
     184             :                           double *spc_seq_page_cost)
     185             : {
     186     1206218 :     TableSpaceCacheEntry *spc = get_tablespace(spcid);
     187             : 
     188             :     Assert(spc != NULL);
     189             : 
     190     1206218 :     if (spc_random_page_cost)
     191             :     {
     192      977544 :         if (!spc->opts || spc->opts->random_page_cost < 0)
     193      977544 :             *spc_random_page_cost = random_page_cost;
     194             :         else
     195           0 :             *spc_random_page_cost = spc->opts->random_page_cost;
     196             :     }
     197             : 
     198     1206218 :     if (spc_seq_page_cost)
     199             :     {
     200      843384 :         if (!spc->opts || spc->opts->seq_page_cost < 0)
     201      843248 :             *spc_seq_page_cost = seq_page_cost;
     202             :         else
     203         136 :             *spc_seq_page_cost = spc->opts->seq_page_cost;
     204             :     }
     205     1206218 : }
     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
     215       19624 : get_tablespace_io_concurrency(Oid spcid)
     216             : {
     217       19624 :     TableSpaceCacheEntry *spc = get_tablespace(spcid);
     218             : 
     219       19624 :     if (!spc->opts || spc->opts->effective_io_concurrency < 0)
     220       19624 :         return effective_io_concurrency;
     221             :     else
     222           0 :         return spc->opts->effective_io_concurrency;
     223             : }

Generated by: LCOV version 1.13