mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
This includes removing tabs after periods in C comments, which was applied to back branches, so this change should not effect backpatching.
202 lines
5.2 KiB
C
202 lines
5.2 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* 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-2014, 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/cost.h"
|
|
#include "utils/catcache.h"
|
|
#include "utils/hsearch.h"
|
|
#include "utils/inval.h"
|
|
#include "utils/spccache.h"
|
|
#include "utils/syscache.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,
|
|
(void *) &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. */
|
|
MemSet(&ctl, 0, sizeof(ctl));
|
|
ctl.keysize = sizeof(Oid);
|
|
ctl.entrysize = sizeof(TableSpaceCacheEntry);
|
|
ctl.hash = oid_hash;
|
|
TableSpaceCacheHash =
|
|
hash_create("TableSpace cache", 16, &ctl,
|
|
HASH_ELEM | HASH_FUNCTION);
|
|
|
|
/* 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,
|
|
(void *) &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,
|
|
(void *) &spcid,
|
|
HASH_ENTER,
|
|
NULL);
|
|
spc->opts = opts;
|
|
return spc;
|
|
}
|
|
|
|
/*
|
|
* get_tablespace_page_costs
|
|
* Return random and/or sequential page costs for a given tablespace.
|
|
*/
|
|
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;
|
|
}
|
|
}
|