LCOV - code coverage report
Current view: top level - src/backend/utils/cache - spccache.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 88.3 % 60 53
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 6 6
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 75.0 % 40 30

             Branch data     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                 :         512 : InvalidateTableSpaceCacheCallback(Datum arg, SysCacheIdentifier cacheid,
      56                 :             :                                   uint32 hashvalue)
      57                 :             : {
      58                 :             :     HASH_SEQ_STATUS status;
      59                 :             :     TableSpaceCacheEntry *spc;
      60                 :             : 
      61                 :         512 :     hash_seq_init(&status, TableSpaceCacheHash);
      62         [ +  + ]:         780 :     while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
      63                 :             :     {
      64         [ -  + ]:         268 :         if (spc->opts)
      65                 :           0 :             pfree(spc->opts);
      66         [ -  + ]:         268 :         if (hash_search(TableSpaceCacheHash,
      67                 :         268 :                         &spc->oid,
      68                 :             :                         HASH_REMOVE,
      69                 :             :                         NULL) == NULL)
      70         [ #  # ]:           0 :             elog(ERROR, "hash table corrupted");
      71                 :             :     }
      72                 :         512 : }
      73                 :             : 
      74                 :             : /*
      75                 :             :  * InitializeTableSpaceCache
      76                 :             :  *      Initialize the tablespace cache.
      77                 :             :  */
      78                 :             : static void
      79                 :        9042 : InitializeTableSpaceCache(void)
      80                 :             : {
      81                 :             :     HASHCTL     ctl;
      82                 :             : 
      83                 :             :     /* Initialize the hash table. */
      84                 :        9042 :     ctl.keysize = sizeof(Oid);
      85                 :        9042 :     ctl.entrysize = sizeof(TableSpaceCacheEntry);
      86                 :        9042 :     TableSpaceCacheHash =
      87                 :        9042 :         hash_create("TableSpace cache", 16, &ctl,
      88                 :             :                     HASH_ELEM | HASH_BLOBS);
      89                 :             : 
      90                 :             :     /* Make sure we've initialized CacheMemoryContext. */
      91         [ -  + ]:        9042 :     if (!CacheMemoryContext)
      92                 :           0 :         CreateCacheMemoryContext();
      93                 :             : 
      94                 :             :     /* Watch for invalidation events. */
      95                 :        9042 :     CacheRegisterSyscacheCallback(TABLESPACEOID,
      96                 :             :                                   InvalidateTableSpaceCacheCallback,
      97                 :             :                                   (Datum) 0);
      98                 :        9042 : }
      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                 :     2198865 : 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         [ +  + ]:     2198865 :     if (spcid == InvalidOid)
     119                 :     2001420 :         spcid = MyDatabaseTableSpace;
     120                 :             : 
     121                 :             :     /* Find existing cache entry, if any. */
     122         [ +  + ]:     2198865 :     if (!TableSpaceCacheHash)
     123                 :        9042 :         InitializeTableSpaceCache();
     124                 :     2198865 :     spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
     125                 :             :                                                &spcid,
     126                 :             :                                                HASH_FIND,
     127                 :             :                                                NULL);
     128         [ +  + ]:     2198865 :     if (spc)
     129                 :     2188828 :         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                 :       10037 :     tp = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spcid));
     138         [ -  + ]:       10037 :     if (!HeapTupleIsValid(tp))
     139                 :           0 :         opts = NULL;
     140                 :             :     else
     141                 :             :     {
     142                 :             :         Datum       datum;
     143                 :             :         bool        isNull;
     144                 :             : 
     145                 :       10037 :         datum = SysCacheGetAttr(TABLESPACEOID,
     146                 :             :                                 tp,
     147                 :             :                                 Anum_pg_tablespace_spcoptions,
     148                 :             :                                 &isNull);
     149         [ +  + ]:       10037 :         if (isNull)
     150                 :       10033 :             opts = NULL;
     151                 :             :         else
     152                 :             :         {
     153                 :           4 :             bytea      *bytea_opts = tablespace_reloptions(datum, false);
     154                 :             : 
     155                 :           4 :             opts = MemoryContextAlloc(CacheMemoryContext, VARSIZE(bytea_opts));
     156                 :           4 :             memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
     157                 :             :         }
     158                 :       10037 :         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                 :       10037 :     spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
     167                 :             :                                                &spcid,
     168                 :             :                                                HASH_ENTER,
     169                 :             :                                                NULL);
     170                 :       10037 :     spc->opts = opts;
     171                 :       10037 :     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                 :     2064621 : get_tablespace_page_costs(Oid spcid,
     184                 :             :                           double *spc_random_page_cost,
     185                 :             :                           double *spc_seq_page_cost)
     186                 :             : {
     187                 :     2064621 :     TableSpaceCacheEntry *spc = get_tablespace(spcid);
     188                 :             : 
     189                 :             :     Assert(spc != NULL);
     190                 :             : 
     191         [ +  + ]:     2064621 :     if (spc_random_page_cost)
     192                 :             :     {
     193   [ +  +  +  - ]:     1726129 :         if (!spc->opts || spc->opts->random_page_cost < 0)
     194                 :     1726129 :             *spc_random_page_cost = random_page_cost;
     195                 :             :         else
     196                 :           0 :             *spc_random_page_cost = spc->opts->random_page_cost;
     197                 :             :     }
     198                 :             : 
     199         [ +  + ]:     2064621 :     if (spc_seq_page_cost)
     200                 :             :     {
     201   [ +  +  -  + ]:     1428464 :         if (!spc->opts || spc->opts->seq_page_cost < 0)
     202                 :     1428281 :             *spc_seq_page_cost = seq_page_cost;
     203                 :             :         else
     204                 :         183 :             *spc_seq_page_cost = spc->opts->seq_page_cost;
     205                 :             :     }
     206                 :     2064621 : }
     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                 :      113753 : get_tablespace_io_concurrency(Oid spcid)
     217                 :             : {
     218                 :      113753 :     TableSpaceCacheEntry *spc = get_tablespace(spcid);
     219                 :             : 
     220   [ +  +  +  - ]:      113753 :     if (!spc->opts || spc->opts->effective_io_concurrency < 0)
     221                 :      113753 :         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                 :       20491 : get_tablespace_maintenance_io_concurrency(Oid spcid)
     231                 :             : {
     232                 :       20491 :     TableSpaceCacheEntry *spc = get_tablespace(spcid);
     233                 :             : 
     234   [ +  +  +  - ]:       20491 :     if (!spc->opts || spc->opts->maintenance_io_concurrency < 0)
     235                 :       20491 :         return maintenance_io_concurrency;
     236                 :             :     else
     237                 :           0 :         return spc->opts->maintenance_io_concurrency;
     238                 :             : }
        

Generated by: LCOV version 2.0-1