LCOV - code coverage report
Current view: top level - src/backend/utils/cache - spccache.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 88.3 % 60 53
Test Date: 2026-03-10 05:14:54 Functions: 100.0 % 6 6
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-2026, 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          426 : InvalidateTableSpaceCacheCallback(Datum arg, SysCacheIdentifier cacheid,
      56              :                                   uint32 hashvalue)
      57              : {
      58              :     HASH_SEQ_STATUS status;
      59              :     TableSpaceCacheEntry *spc;
      60              : 
      61          426 :     hash_seq_init(&status, TableSpaceCacheHash);
      62          618 :     while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
      63              :     {
      64          192 :         if (spc->opts)
      65            0 :             pfree(spc->opts);
      66          192 :         if (hash_search(TableSpaceCacheHash,
      67          192 :                         &spc->oid,
      68              :                         HASH_REMOVE,
      69              :                         NULL) == NULL)
      70            0 :             elog(ERROR, "hash table corrupted");
      71              :     }
      72          426 : }
      73              : 
      74              : /*
      75              :  * InitializeTableSpaceCache
      76              :  *      Initialize the tablespace cache.
      77              :  */
      78              : static void
      79         8185 : InitializeTableSpaceCache(void)
      80              : {
      81              :     HASHCTL     ctl;
      82              : 
      83              :     /* Initialize the hash table. */
      84         8185 :     ctl.keysize = sizeof(Oid);
      85         8185 :     ctl.entrysize = sizeof(TableSpaceCacheEntry);
      86         8185 :     TableSpaceCacheHash =
      87         8185 :         hash_create("TableSpace cache", 16, &ctl,
      88              :                     HASH_ELEM | HASH_BLOBS);
      89              : 
      90              :     /* Make sure we've initialized CacheMemoryContext. */
      91         8185 :     if (!CacheMemoryContext)
      92            0 :         CreateCacheMemoryContext();
      93              : 
      94              :     /* Watch for invalidation events. */
      95         8185 :     CacheRegisterSyscacheCallback(TABLESPACEOID,
      96              :                                   InvalidateTableSpaceCacheCallback,
      97              :                                   (Datum) 0);
      98         8185 : }
      99              : 
     100              : /*
     101              :  * get_tablespace
     102              :  *      Fetch TableSpaceCacheEntry structure for a specified table OID.
     103              :  *
     104              :  * Pointers returned by this function should not be stored, since a cache
     105              :  * flush will invalidate them.
     106              :  */
     107              : static TableSpaceCacheEntry *
     108      1637021 : get_tablespace(Oid spcid)
     109              : {
     110              :     TableSpaceCacheEntry *spc;
     111              :     HeapTuple   tp;
     112              :     TableSpaceOpts *opts;
     113              : 
     114              :     /*
     115              :      * Since spcid is always from a pg_class tuple, InvalidOid implies the
     116              :      * default.
     117              :      */
     118      1637021 :     if (spcid == InvalidOid)
     119      1469154 :         spcid = MyDatabaseTableSpace;
     120              : 
     121              :     /* Find existing cache entry, if any. */
     122      1637021 :     if (!TableSpaceCacheHash)
     123         8185 :         InitializeTableSpaceCache();
     124      1637021 :     spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
     125              :                                                &spcid,
     126              :                                                HASH_FIND,
     127              :                                                NULL);
     128      1637021 :     if (spc)
     129      1627919 :         return spc;
     130              : 
     131              :     /*
     132              :      * Not found in TableSpace cache.  Check catcache.  If we don't find a
     133              :      * valid HeapTuple, it must mean someone has managed to request tablespace
     134              :      * details for a non-existent tablespace.  We'll just treat that case as
     135              :      * if no options were specified.
     136              :      */
     137         9102 :     tp = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spcid));
     138         9102 :     if (!HeapTupleIsValid(tp))
     139            0 :         opts = NULL;
     140              :     else
     141              :     {
     142              :         Datum       datum;
     143              :         bool        isNull;
     144              : 
     145         9102 :         datum = SysCacheGetAttr(TABLESPACEOID,
     146              :                                 tp,
     147              :                                 Anum_pg_tablespace_spcoptions,
     148              :                                 &isNull);
     149         9102 :         if (isNull)
     150         9099 :             opts = NULL;
     151              :         else
     152              :         {
     153            3 :             bytea      *bytea_opts = tablespace_reloptions(datum, false);
     154              : 
     155            3 :             opts = MemoryContextAlloc(CacheMemoryContext, VARSIZE(bytea_opts));
     156            3 :             memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
     157              :         }
     158         9102 :         ReleaseSysCache(tp);
     159              :     }
     160              : 
     161              :     /*
     162              :      * Now create the cache entry.  It's important to do this only after
     163              :      * reading the pg_tablespace entry, since doing so could cause a cache
     164              :      * flush.
     165              :      */
     166         9102 :     spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
     167              :                                                &spcid,
     168              :                                                HASH_ENTER,
     169              :                                                NULL);
     170         9102 :     spc->opts = opts;
     171         9102 :     return spc;
     172              : }
     173              : 
     174              : /*
     175              :  * get_tablespace_page_costs
     176              :  *      Return random and/or sequential page costs for a given tablespace.
     177              :  *
     178              :  *      This value is not locked by the transaction, so this value may
     179              :  *      be changed while a SELECT that has used these values for planning
     180              :  *      is still executing.
     181              :  */
     182              : void
     183      1532639 : get_tablespace_page_costs(Oid spcid,
     184              :                           double *spc_random_page_cost,
     185              :                           double *spc_seq_page_cost)
     186              : {
     187      1532639 :     TableSpaceCacheEntry *spc = get_tablespace(spcid);
     188              : 
     189              :     Assert(spc != NULL);
     190              : 
     191      1532639 :     if (spc_random_page_cost)
     192              :     {
     193      1289897 :         if (!spc->opts || spc->opts->random_page_cost < 0)
     194      1289897 :             *spc_random_page_cost = random_page_cost;
     195              :         else
     196            0 :             *spc_random_page_cost = spc->opts->random_page_cost;
     197              :     }
     198              : 
     199      1532639 :     if (spc_seq_page_cost)
     200              :     {
     201      1056776 :         if (!spc->opts || spc->opts->seq_page_cost < 0)
     202      1056647 :             *spc_seq_page_cost = seq_page_cost;
     203              :         else
     204          129 :             *spc_seq_page_cost = spc->opts->seq_page_cost;
     205              :     }
     206      1532639 : }
     207              : 
     208              : /*
     209              :  * get_tablespace_io_concurrency
     210              :  *
     211              :  *      This value is not locked by the transaction, so this value may
     212              :  *      be changed while a SELECT that has used these values for planning
     213              :  *      is still executing.
     214              :  */
     215              : int
     216        86257 : get_tablespace_io_concurrency(Oid spcid)
     217              : {
     218        86257 :     TableSpaceCacheEntry *spc = get_tablespace(spcid);
     219              : 
     220        86257 :     if (!spc->opts || spc->opts->effective_io_concurrency < 0)
     221        86257 :         return effective_io_concurrency;
     222              :     else
     223            0 :         return spc->opts->effective_io_concurrency;
     224              : }
     225              : 
     226              : /*
     227              :  * get_tablespace_maintenance_io_concurrency
     228              :  */
     229              : int
     230        18125 : get_tablespace_maintenance_io_concurrency(Oid spcid)
     231              : {
     232        18125 :     TableSpaceCacheEntry *spc = get_tablespace(spcid);
     233              : 
     234        18125 :     if (!spc->opts || spc->opts->maintenance_io_concurrency < 0)
     235        18125 :         return maintenance_io_concurrency;
     236              :     else
     237            0 :         return spc->opts->maintenance_io_concurrency;
     238              : }
        

Generated by: LCOV version 2.0-1