LCOV - code coverage report
Current view: top level - src/backend/utils/cache - spccache.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 53 60 88.3 %
Date: 2024-12-12 16:15:21 Functions: 6 6 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-2024, 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             : #include "varatt.h"
      33             : 
      34             : 
      35             : /* Hash table for information about each tablespace */
      36             : static HTAB *TableSpaceCacheHash = NULL;
      37             : 
      38             : typedef struct
      39             : {
      40             :     Oid         oid;            /* lookup key - must be first */
      41             :     TableSpaceOpts *opts;       /* options, or NULL if none */
      42             : } TableSpaceCacheEntry;
      43             : 
      44             : 
      45             : /*
      46             :  * InvalidateTableSpaceCacheCallback
      47             :  *      Flush all cache entries when pg_tablespace is updated.
      48             :  *
      49             :  * When pg_tablespace is updated, we must flush the cache entry at least
      50             :  * for that tablespace.  Currently, we just flush them all.  This is quick
      51             :  * and easy and doesn't cost much, since there shouldn't be terribly many
      52             :  * tablespaces, nor do we expect them to be frequently modified.
      53             :  */
      54             : static void
      55         828 : InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
      56             : {
      57             :     HASH_SEQ_STATUS status;
      58             :     TableSpaceCacheEntry *spc;
      59             : 
      60         828 :     hash_seq_init(&status, TableSpaceCacheHash);
      61        1190 :     while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
      62             :     {
      63         362 :         if (spc->opts)
      64           0 :             pfree(spc->opts);
      65         362 :         if (hash_search(TableSpaceCacheHash,
      66         362 :                         &spc->oid,
      67             :                         HASH_REMOVE,
      68             :                         NULL) == NULL)
      69           0 :             elog(ERROR, "hash table corrupted");
      70             :     }
      71         828 : }
      72             : 
      73             : /*
      74             :  * InitializeTableSpaceCache
      75             :  *      Initialize the tablespace cache.
      76             :  */
      77             : static void
      78       11664 : InitializeTableSpaceCache(void)
      79             : {
      80             :     HASHCTL     ctl;
      81             : 
      82             :     /* Initialize the hash table. */
      83       11664 :     ctl.keysize = sizeof(Oid);
      84       11664 :     ctl.entrysize = sizeof(TableSpaceCacheEntry);
      85       11664 :     TableSpaceCacheHash =
      86       11664 :         hash_create("TableSpace cache", 16, &ctl,
      87             :                     HASH_ELEM | HASH_BLOBS);
      88             : 
      89             :     /* Make sure we've initialized CacheMemoryContext. */
      90       11664 :     if (!CacheMemoryContext)
      91           0 :         CreateCacheMemoryContext();
      92             : 
      93             :     /* Watch for invalidation events. */
      94       11664 :     CacheRegisterSyscacheCallback(TABLESPACEOID,
      95             :                                   InvalidateTableSpaceCacheCallback,
      96             :                                   (Datum) 0);
      97       11664 : }
      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     2390876 : 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     2390876 :     if (spcid == InvalidOid)
     118     2180240 :         spcid = MyDatabaseTableSpace;
     119             : 
     120             :     /* Find existing cache entry, if any. */
     121     2390876 :     if (!TableSpaceCacheHash)
     122       11664 :         InitializeTableSpaceCache();
     123     2390876 :     spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
     124             :                                                &spcid,
     125             :                                                HASH_FIND,
     126             :                                                NULL);
     127     2390876 :     if (spc)
     128     2377896 :         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       12980 :     tp = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spcid));
     137       12980 :     if (!HeapTupleIsValid(tp))
     138           0 :         opts = NULL;
     139             :     else
     140             :     {
     141             :         Datum       datum;
     142             :         bool        isNull;
     143             : 
     144       12980 :         datum = SysCacheGetAttr(TABLESPACEOID,
     145             :                                 tp,
     146             :                                 Anum_pg_tablespace_spcoptions,
     147             :                                 &isNull);
     148       12980 :         if (isNull)
     149       12974 :             opts = NULL;
     150             :         else
     151             :         {
     152           6 :             bytea      *bytea_opts = tablespace_reloptions(datum, false);
     153             : 
     154           6 :             opts = MemoryContextAlloc(CacheMemoryContext, VARSIZE(bytea_opts));
     155           6 :             memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
     156             :         }
     157       12980 :         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       12980 :     spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
     166             :                                                &spcid,
     167             :                                                HASH_ENTER,
     168             :                                                NULL);
     169       12980 :     spc->opts = opts;
     170       12980 :     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     2219848 : get_tablespace_page_costs(Oid spcid,
     183             :                           double *spc_random_page_cost,
     184             :                           double *spc_seq_page_cost)
     185             : {
     186     2219848 :     TableSpaceCacheEntry *spc = get_tablespace(spcid);
     187             : 
     188             :     Assert(spc != NULL);
     189             : 
     190     2219848 :     if (spc_random_page_cost)
     191             :     {
     192     1833246 :         if (!spc->opts || spc->opts->random_page_cost < 0)
     193     1833246 :             *spc_random_page_cost = random_page_cost;
     194             :         else
     195           0 :             *spc_random_page_cost = spc->opts->random_page_cost;
     196             :     }
     197             : 
     198     2219848 :     if (spc_seq_page_cost)
     199             :     {
     200     1549312 :         if (!spc->opts || spc->opts->seq_page_cost < 0)
     201     1549054 :             *spc_seq_page_cost = seq_page_cost;
     202             :         else
     203         258 :             *spc_seq_page_cost = spc->opts->seq_page_cost;
     204             :     }
     205     2219848 : }
     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      161396 : get_tablespace_io_concurrency(Oid spcid)
     216             : {
     217      161396 :     TableSpaceCacheEntry *spc = get_tablespace(spcid);
     218             : 
     219      161396 :     if (!spc->opts || spc->opts->effective_io_concurrency < 0)
     220      161396 :         return effective_io_concurrency;
     221             :     else
     222           0 :         return spc->opts->effective_io_concurrency;
     223             : }
     224             : 
     225             : /*
     226             :  * get_tablespace_maintenance_io_concurrency
     227             :  */
     228             : int
     229        9632 : get_tablespace_maintenance_io_concurrency(Oid spcid)
     230             : {
     231        9632 :     TableSpaceCacheEntry *spc = get_tablespace(spcid);
     232             : 
     233        9632 :     if (!spc->opts || spc->opts->maintenance_io_concurrency < 0)
     234        9632 :         return maintenance_io_concurrency;
     235             :     else
     236           0 :         return spc->opts->maintenance_io_concurrency;
     237             : }

Generated by: LCOV version 1.14