/*-------------------------------------------------------------------------
*
* spccache . c
* Tablespace cache management .
*
* We cache the parsed version of spcoptions for each tablespace to avoid
* needing to reparse on every lookup . Right now , there doesn ' t appear to
* be a measurable performance gain from doing this , but that might change
* in the future as we add more options .
*
* Portions Copyright ( c ) 1996 - 2025 , PostgreSQL Global Development Group
* Portions Copyright ( c ) 1994 , Regents of the University of California
*
* IDENTIFICATION
* src / backend / utils / cache / spccache . c
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
#include "postgres.h"
#include "access/reloptions.h"
#include "catalog/pg_tablespace.h"
#include "commands/tablespace.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
#include "storage/bufmgr.h"
#include "utils/catcache.h"
#include "utils/hsearch.h"
#include "utils/inval.h"
#include "utils/spccache.h"
#include "utils/syscache.h"
#include "varatt.h"
/* Hash table for information about each tablespace */
static HTAB *TableSpaceCacheHash = NULL;
typedef struct
{
Oid oid; /* lookup key - must be first */
TableSpaceOpts *opts; /* options, or NULL if none */
} TableSpaceCacheEntry;
/*
* InvalidateTableSpaceCacheCallback
* Flush all cache entries when pg_tablespace is updated .
*
* When pg_tablespace is updated , we must flush the cache entry at least
* for that tablespace . Currently , we just flush them all . This is quick
* and easy and doesn ' t cost much , since there shouldn ' t be terribly many
* tablespaces , nor do we expect them to be frequently modified .
*/
static void
InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
{
HASH_SEQ_STATUS status;
TableSpaceCacheEntry *spc;
hash_seq_init(&status, TableSpaceCacheHash);
while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
{
if (spc->opts)
pfree(spc->opts);
if (hash_search(TableSpaceCacheHash,
&spc->oid,
HASH_REMOVE,
NULL) == NULL)
elog(ERROR, "hash table corrupted" );
}
}
/*
* InitializeTableSpaceCache
* Initialize the tablespace cache .
*/
static void
InitializeTableSpaceCache(void )
{
HASHCTL ctl;
/* Initialize the hash table. */
ctl.keysize = sizeof (Oid);
ctl.entrysize = sizeof (TableSpaceCacheEntry);
TableSpaceCacheHash =
hash_create("TableSpace cache" , 16 , &ctl,
HASH_ELEM | HASH_BLOBS);
/* Make sure we've initialized CacheMemoryContext. */
if (!CacheMemoryContext)
CreateCacheMemoryContext();
/* Watch for invalidation events. */
CacheRegisterSyscacheCallback(TABLESPACEOID,
InvalidateTableSpaceCacheCallback,
(Datum) 0 );
}
/*
* get_tablespace
* Fetch TableSpaceCacheEntry structure for a specified table OID .
*
* Pointers returned by this function should not be stored , since a cache
* flush will invalidate them .
*/
static TableSpaceCacheEntry *
get_tablespace(Oid spcid)
{
TableSpaceCacheEntry *spc;
HeapTuple tp;
TableSpaceOpts *opts;
/*
* Since spcid is always from a pg_class tuple , InvalidOid implies the
* default .
*/
if (spcid == InvalidOid)
spcid = MyDatabaseTableSpace;
/* Find existing cache entry, if any. */
if (!TableSpaceCacheHash)
InitializeTableSpaceCache();
spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
&spcid,
HASH_FIND,
NULL);
if (spc)
return spc;
/*
* Not found in TableSpace cache . Check catcache . If we don ' t find a
* valid HeapTuple , it must mean someone has managed to request tablespace
* details for a non - existent tablespace . We ' ll just treat that case as
* if no options were specified .
*/
tp = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spcid));
if (!HeapTupleIsValid(tp))
opts = NULL;
else
{
Datum datum;
bool isNull;
datum = SysCacheGetAttr(TABLESPACEOID,
tp,
Anum_pg_tablespace_spcoptions,
&isNull);
if (isNull)
opts = NULL;
else
{
bytea *bytea_opts = tablespace_reloptions(datum, false );
opts = MemoryContextAlloc(CacheMemoryContext, VARSIZE(bytea_opts));
memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
}
ReleaseSysCache(tp);
}
/*
* Now create the cache entry . It ' s important to do this only after
* reading the pg_tablespace entry , since doing so could cause a cache
* flush .
*/
spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
&spcid,
HASH_ENTER,
NULL);
spc->opts = opts;
return spc;
}
/*
* get_tablespace_page_costs
* Return random and / or sequential page costs for a given tablespace .
*
* This value is not locked by the transaction , so this value may
* be changed while a SELECT that has used these values for planning
* is still executing .
*/
void
get_tablespace_page_costs(Oid spcid,
double *spc_random_page_cost,
double *spc_seq_page_cost)
{
TableSpaceCacheEntry *spc = get_tablespace(spcid);
Assert(spc != NULL);
if (spc_random_page_cost)
{
if (!spc->opts || spc->opts->random_page_cost < 0 )
*spc_random_page_cost = random_page_cost;
else
*spc_random_page_cost = spc->opts->random_page_cost;
}
if (spc_seq_page_cost)
{
if (!spc->opts || spc->opts->seq_page_cost < 0 )
*spc_seq_page_cost = seq_page_cost;
else
*spc_seq_page_cost = spc->opts->seq_page_cost;
}
}
/*
* get_tablespace_io_concurrency
*
* This value is not locked by the transaction , so this value may
* be changed while a SELECT that has used these values for planning
* is still executing .
*/
int
get_tablespace_io_concurrency(Oid spcid)
{
TableSpaceCacheEntry *spc = get_tablespace(spcid);
if (!spc->opts || spc->opts->effective_io_concurrency < 0 )
return effective_io_concurrency;
else
return spc->opts->effective_io_concurrency;
}
/*
* get_tablespace_maintenance_io_concurrency
*/
int
get_tablespace_maintenance_io_concurrency(Oid spcid)
{
TableSpaceCacheEntry *spc = get_tablespace(spcid);
if (!spc->opts || spc->opts->maintenance_io_concurrency < 0 )
return maintenance_io_concurrency;
else
return spc->opts->maintenance_io_concurrency;
}
Messung V0.5 in Prozent C=94 H=94 G=93
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland