LCOV - code coverage report
Current view: top level - src/backend/utils/cache - spccache.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 91.0 % 78 71
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 6 6
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 70.5 % 44 31

             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                 :          60 : InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
      56                 :             : {
      57                 :          60 :         HASH_SEQ_STATUS status;
      58                 :          60 :         TableSpaceCacheEntry *spc;
      59                 :             : 
      60                 :          60 :         hash_seq_init(&status, TableSpaceCacheHash);
      61         [ +  + ]:         119 :         while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
      62                 :             :         {
      63         [ +  - ]:          59 :                 if (spc->opts)
      64                 :           0 :                         pfree(spc->opts);
      65                 :         118 :                 if (hash_search(TableSpaceCacheHash,
      66                 :          59 :                                                 &spc->oid,
      67                 :             :                                                 HASH_REMOVE,
      68         [ +  - ]:          59 :                                                 NULL) == NULL)
      69   [ #  #  #  # ]:           0 :                         elog(ERROR, "hash table corrupted");
      70                 :             :         }
      71                 :          60 : }
      72                 :             : 
      73                 :             : /*
      74                 :             :  * InitializeTableSpaceCache
      75                 :             :  *              Initialize the tablespace cache.
      76                 :             :  */
      77                 :             : static void
      78                 :         640 : InitializeTableSpaceCache(void)
      79                 :             : {
      80                 :         640 :         HASHCTL         ctl;
      81                 :             : 
      82                 :             :         /* Initialize the hash table. */
      83                 :         640 :         ctl.keysize = sizeof(Oid);
      84                 :         640 :         ctl.entrysize = sizeof(TableSpaceCacheEntry);
      85                 :         640 :         TableSpaceCacheHash =
      86                 :         640 :                 hash_create("TableSpace cache", 16, &ctl,
      87                 :             :                                         HASH_ELEM | HASH_BLOBS);
      88                 :             : 
      89                 :             :         /* Make sure we've initialized CacheMemoryContext. */
      90         [ +  - ]:         640 :         if (!CacheMemoryContext)
      91                 :           0 :                 CreateCacheMemoryContext();
      92                 :             : 
      93                 :             :         /* Watch for invalidation events. */
      94                 :         640 :         CacheRegisterSyscacheCallback(TABLESPACEOID,
      95                 :             :                                                                   InvalidateTableSpaceCacheCallback,
      96                 :             :                                                                   (Datum) 0);
      97                 :         640 : }
      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                 :      572502 : get_tablespace(Oid spcid)
     108                 :             : {
     109                 :      572502 :         TableSpaceCacheEntry *spc;
     110                 :      572502 :         HeapTuple       tp;
     111                 :      572502 :         TableSpaceOpts *opts;
     112                 :             : 
     113                 :             :         /*
     114                 :             :          * Since spcid is always from a pg_class tuple, InvalidOid implies the
     115                 :             :          * default.
     116                 :             :          */
     117         [ +  + ]:      572502 :         if (spcid == InvalidOid)
     118                 :      244315 :                 spcid = MyDatabaseTableSpace;
     119                 :             : 
     120                 :             :         /* Find existing cache entry, if any. */
     121         [ +  + ]:      572502 :         if (!TableSpaceCacheHash)
     122                 :         640 :                 InitializeTableSpaceCache();
     123                 :      572502 :         spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
     124                 :             :                                                                                            &spcid,
     125                 :             :                                                                                            HASH_FIND,
     126                 :             :                                                                                            NULL);
     127         [ +  + ]:      572502 :         if (spc)
     128                 :      571742 :                 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                 :         760 :         tp = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spcid));
     137         [ +  - ]:         760 :         if (!HeapTupleIsValid(tp))
     138                 :           0 :                 opts = NULL;
     139                 :             :         else
     140                 :             :         {
     141                 :         760 :                 Datum           datum;
     142                 :         760 :                 bool            isNull;
     143                 :             : 
     144                 :         760 :                 datum = SysCacheGetAttr(TABLESPACEOID,
     145                 :         760 :                                                                 tp,
     146                 :             :                                                                 Anum_pg_tablespace_spcoptions,
     147                 :             :                                                                 &isNull);
     148         [ +  + ]:         760 :                 if (isNull)
     149                 :         759 :                         opts = NULL;
     150                 :             :                 else
     151                 :             :                 {
     152                 :           1 :                         bytea      *bytea_opts = tablespace_reloptions(datum, false);
     153                 :             : 
     154                 :           1 :                         opts = MemoryContextAlloc(CacheMemoryContext, VARSIZE(bytea_opts));
     155                 :           1 :                         memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
     156                 :           1 :                 }
     157                 :         760 :                 ReleaseSysCache(tp);
     158                 :         760 :         }
     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                 :         760 :         spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
     166                 :             :                                                                                            &spcid,
     167                 :             :                                                                                            HASH_ENTER,
     168                 :             :                                                                                            NULL);
     169                 :         760 :         spc->opts = opts;
     170                 :         760 :         return spc;
     171                 :      572502 : }
     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                 :      249679 : get_tablespace_page_costs(Oid spcid,
     183                 :             :                                                   double *spc_random_page_cost,
     184                 :             :                                                   double *spc_seq_page_cost)
     185                 :             : {
     186                 :      249679 :         TableSpaceCacheEntry *spc = get_tablespace(spcid);
     187                 :             : 
     188         [ +  - ]:      249679 :         Assert(spc != NULL);
     189                 :             : 
     190         [ +  + ]:      249679 :         if (spc_random_page_cost)
     191                 :             :         {
     192   [ +  +  +  - ]:      202282 :                 if (!spc->opts || spc->opts->random_page_cost < 0)
     193                 :      202282 :                         *spc_random_page_cost = random_page_cost;
     194                 :             :                 else
     195                 :           0 :                         *spc_random_page_cost = spc->opts->random_page_cost;
     196                 :      202282 :         }
     197                 :             : 
     198         [ +  + ]:      249679 :         if (spc_seq_page_cost)
     199                 :             :         {
     200   [ +  +  -  + ]:      175668 :                 if (!spc->opts || spc->opts->seq_page_cost < 0)
     201                 :      175625 :                         *spc_seq_page_cost = seq_page_cost;
     202                 :             :                 else
     203                 :          43 :                         *spc_seq_page_cost = spc->opts->seq_page_cost;
     204                 :      175668 :         }
     205                 :      249679 : }
     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                 :      321140 : get_tablespace_io_concurrency(Oid spcid)
     216                 :             : {
     217                 :      321140 :         TableSpaceCacheEntry *spc = get_tablespace(spcid);
     218                 :             : 
     219   [ +  +  +  - ]:      321140 :         if (!spc->opts || spc->opts->effective_io_concurrency < 0)
     220                 :      321140 :                 return effective_io_concurrency;
     221                 :             :         else
     222                 :           0 :                 return spc->opts->effective_io_concurrency;
     223                 :      321140 : }
     224                 :             : 
     225                 :             : /*
     226                 :             :  * get_tablespace_maintenance_io_concurrency
     227                 :             :  */
     228                 :             : int
     229                 :        1683 : get_tablespace_maintenance_io_concurrency(Oid spcid)
     230                 :             : {
     231                 :        1683 :         TableSpaceCacheEntry *spc = get_tablespace(spcid);
     232                 :             : 
     233   [ +  +  +  - ]:        1683 :         if (!spc->opts || spc->opts->maintenance_io_concurrency < 0)
     234                 :        1683 :                 return maintenance_io_concurrency;
     235                 :             :         else
     236                 :           0 :                 return spc->opts->maintenance_io_concurrency;
     237                 :        1683 : }
        

Generated by: LCOV version 2.3.2-1