LCOV - differential code coverage report
Current view: top level - src/backend/utils/cache - spccache.c (source / functions) Coverage Total Hit LBC UIC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 90.2 % 61 55 2 4 36 1 18 6 32 3
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 6 6 6 6
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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-2023, 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 GIC         166 : InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
      56 ECB             : {
      57                 :     HASH_SEQ_STATUS status;
      58                 :     TableSpaceCacheEntry *spc;
      59                 : 
      60 GIC         166 :     hash_seq_init(&status, TableSpaceCacheHash);
      61 CBC         262 :     while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
      62 ECB             :     {
      63 GIC          96 :         if (spc->opts)
      64 CBC           3 :             pfree(spc->opts);
      65              96 :         if (hash_search(TableSpaceCacheHash,
      66 GNC          96 :                         &spc->oid,
      67 ECB             :                         HASH_REMOVE,
      68                 :                         NULL) == NULL)
      69 UIC           0 :             elog(ERROR, "hash table corrupted");
      70 EUB             :     }
      71 GIC         166 : }
      72 ECB             : 
      73                 : /*
      74                 :  * InitializeTableSpaceCache
      75                 :  *      Initialize the tablespace cache.
      76                 :  */
      77                 : static void
      78 GIC        3590 : InitializeTableSpaceCache(void)
      79 ECB             : {
      80                 :     HASHCTL     ctl;
      81                 : 
      82                 :     /* Initialize the hash table. */
      83 GIC        3590 :     ctl.keysize = sizeof(Oid);
      84 CBC        3590 :     ctl.entrysize = sizeof(TableSpaceCacheEntry);
      85            3590 :     TableSpaceCacheHash =
      86            3590 :         hash_create("TableSpace cache", 16, &ctl,
      87 ECB             :                     HASH_ELEM | HASH_BLOBS);
      88                 : 
      89                 :     /* Make sure we've initialized CacheMemoryContext. */
      90 GIC        3590 :     if (!CacheMemoryContext)
      91 LBC           0 :         CreateCacheMemoryContext();
      92 EUB             : 
      93                 :     /* Watch for invalidation events. */
      94 GIC        3590 :     CacheRegisterSyscacheCallback(TABLESPACEOID,
      95 ECB             :                                   InvalidateTableSpaceCacheCallback,
      96                 :                                   (Datum) 0);
      97 GIC        3590 : }
      98 ECB             : 
      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 GIC      925360 : get_tablespace(Oid spcid)
     108 ECB             : {
     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 GIC      925360 :     if (spcid == InvalidOid)
     118 CBC      893268 :         spcid = MyDatabaseTableSpace;
     119 ECB             : 
     120                 :     /* Find existing cache entry, if any. */
     121 GIC      925360 :     if (!TableSpaceCacheHash)
     122 CBC        3590 :         InitializeTableSpaceCache();
     123          925360 :     spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
     124                 :                                                &spcid,
     125                 :                                                HASH_FIND,
     126                 :                                                NULL);
     127 GIC      925360 :     if (spc)
     128 CBC      921021 :         return spc;
     129 ECB             : 
     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 GIC        4339 :     tp = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spcid));
     137 CBC        4339 :     if (!HeapTupleIsValid(tp))
     138 LBC           0 :         opts = NULL;
     139 EUB             :     else
     140                 :     {
     141                 :         Datum       datum;
     142                 :         bool        isNull;
     143                 : 
     144 GIC        4339 :         datum = SysCacheGetAttr(TABLESPACEOID,
     145 ECB             :                                 tp,
     146                 :                                 Anum_pg_tablespace_spcoptions,
     147                 :                                 &isNull);
     148 GIC        4339 :         if (isNull)
     149 CBC        4336 :             opts = NULL;
     150 ECB             :         else
     151                 :         {
     152 GIC           3 :             bytea      *bytea_opts = tablespace_reloptions(datum, false);
     153 ECB             : 
     154 GIC           3 :             opts = MemoryContextAlloc(CacheMemoryContext, VARSIZE(bytea_opts));
     155 CBC           3 :             memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
     156 ECB             :         }
     157 GIC        4339 :         ReleaseSysCache(tp);
     158 ECB             :     }
     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 GIC        4339 :     spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
     166                 :                                                &spcid,
     167                 :                                                HASH_ENTER,
     168                 :                                                NULL);
     169            4339 :     spc->opts = opts;
     170 CBC        4339 :     return spc;
     171 ECB             : }
     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 GIC      888690 : get_tablespace_page_costs(Oid spcid,
     183 ECB             :                           double *spc_random_page_cost,
     184                 :                           double *spc_seq_page_cost)
     185                 : {
     186 GIC      888690 :     TableSpaceCacheEntry *spc = get_tablespace(spcid);
     187 ECB             : 
     188 GIC      888690 :     Assert(spc != NULL);
     189 ECB             : 
     190 GIC      888690 :     if (spc_random_page_cost)
     191 ECB             :     {
     192 GIC      718659 :         if (!spc->opts || spc->opts->random_page_cost < 0)
     193 CBC      718659 :             *spc_random_page_cost = random_page_cost;
     194 ECB             :         else
     195 UIC           0 :             *spc_random_page_cost = spc->opts->random_page_cost;
     196 EUB             :     }
     197                 : 
     198 GIC      888690 :     if (spc_seq_page_cost)
     199 ECB             :     {
     200 GIC      625731 :         if (!spc->opts || spc->opts->seq_page_cost < 0)
     201 CBC      625602 :             *spc_seq_page_cost = seq_page_cost;
     202 ECB             :         else
     203 GIC         129 :             *spc_seq_page_cost = spc->opts->seq_page_cost;
     204 ECB             :     }
     205 GIC      888690 : }
     206 ECB             : 
     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 GIC       10598 : get_tablespace_io_concurrency(Oid spcid)
     216 ECB             : {
     217 GIC       10598 :     TableSpaceCacheEntry *spc = get_tablespace(spcid);
     218 ECB             : 
     219 GIC       10598 :     if (!spc->opts || spc->opts->effective_io_concurrency < 0)
     220 CBC       10598 :         return effective_io_concurrency;
     221 ECB             :     else
     222 UIC           0 :         return spc->opts->effective_io_concurrency;
     223 EUB             : }
     224                 : 
     225                 : /*
     226                 :  * get_tablespace_maintenance_io_concurrency
     227                 :  */
     228                 : int
     229 GIC       26072 : get_tablespace_maintenance_io_concurrency(Oid spcid)
     230 ECB             : {
     231 GIC       26072 :     TableSpaceCacheEntry *spc = get_tablespace(spcid);
     232 ECB             : 
     233 GIC       26072 :     if (!spc->opts || spc->opts->maintenance_io_concurrency < 0)
     234 CBC       26072 :         return maintenance_io_concurrency;
     235 ECB             :     else
     236 UIC           0 :         return spc->opts->maintenance_io_concurrency;
     237 EUB             : }
        

Generated by: LCOV version v1.16-55-g56c0a2a