You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
postgres/src/backend/utils/cache/spccache.c

186 lines
4.8 KiB

/*-------------------------------------------------------------------------
*
* 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-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/spccache.c,v 1.2 2010/01/06 22:27:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#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"
static HTAB *TableSpaceCacheHash = NULL;
typedef struct {
Oid oid;
TableSpaceOpts *opts;
} TableSpace;
/*
* 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, ItemPointer tuplePtr)
{
HASH_SEQ_STATUS status;
TableSpace *spc;
hash_seq_init(&status, TableSpaceCacheHash);
while ((spc = (TableSpace *) 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
* Initiate 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(TableSpace);
ctl.hash = tag_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 TableSpace structure for a specified table OID.
*
* Pointers returned by this function should not be stored, since a cache
* flush will invalidate them.
*/
static TableSpace *
get_tablespace(Oid spcid)
{
HeapTuple tp;
TableSpace *spc;
bool found;
/*
* Since spcid is always from a pg_class tuple, InvalidOid implies the
* default.
*/
if (spcid == InvalidOid)
spcid = MyDatabaseTableSpace;
/* Find existing cache entry, or create a new one. */
if (!TableSpaceCacheHash)
InitializeTableSpaceCache();
spc = (TableSpace *) hash_search(TableSpaceCacheHash, (void *) &spcid,
HASH_ENTER, &found);
if (found)
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 = SearchSysCache(TABLESPACEOID, ObjectIdGetDatum(spcid), 0, 0, 0);
if (!HeapTupleIsValid(tp))
spc->opts = NULL;
else
{
Datum datum;
bool isNull;
MemoryContext octx;
datum = SysCacheGetAttr(TABLESPACEOID,
tp,
Anum_pg_tablespace_spcoptions,
&isNull);
if (isNull)
spc->opts = NULL;
else
{
octx = MemoryContextSwitchTo(CacheMemoryContext);
spc->opts = (TableSpaceOpts *) tablespace_reloptions(datum, false);
MemoryContextSwitchTo(octx);
}
ReleaseSysCache(tp);
}
/* Update new TableSpace cache entry with results of option parsing. */
return spc;
}
/*
* get_tablespace_page_costs
* Return random and sequential page costs for a given tablespace.
*/
void
get_tablespace_page_costs(Oid spcid, double *spc_random_page_cost,
double *spc_seq_page_cost)
{
TableSpace *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;
}
}