Fix spccache.c to not suppose that a cache entry will live across database

access, per testing with CLOBBER_CACHE_ALWAYS.  Minor other editorialization.
This commit is contained in:
Tom Lane 2010-01-06 23:00:02 +00:00
parent 64b9c850e9
commit 9261b19fb5
1 changed files with 47 additions and 28 deletions

View File

@ -12,12 +12,12 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/spccache.c,v 1.2 2010/01/06 22:27:09 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/cache/spccache.c,v 1.3 2010/01/06 23:00:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/reloptions.h" #include "access/reloptions.h"
#include "catalog/pg_tablespace.h" #include "catalog/pg_tablespace.h"
#include "commands/tablespace.h" #include "commands/tablespace.h"
@ -29,12 +29,16 @@
#include "utils/spccache.h" #include "utils/spccache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
/* Hash table for information about each tablespace */
static HTAB *TableSpaceCacheHash = NULL; static HTAB *TableSpaceCacheHash = NULL;
typedef struct { typedef struct
Oid oid; {
TableSpaceOpts *opts; Oid oid; /* lookup key - must be first */
} TableSpace; TableSpaceOpts *opts; /* options, or NULL if none */
} TableSpaceCacheEntry;
/* /*
* InvalidateTableSpaceCacheCallback * InvalidateTableSpaceCacheCallback
@ -49,10 +53,10 @@ static void
InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr) InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
{ {
HASH_SEQ_STATUS status; HASH_SEQ_STATUS status;
TableSpace *spc; TableSpaceCacheEntry *spc;
hash_seq_init(&status, TableSpaceCacheHash); hash_seq_init(&status, TableSpaceCacheHash);
while ((spc = (TableSpace *) hash_seq_search(&status)) != NULL) while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
{ {
if (spc->opts) if (spc->opts)
pfree(spc->opts); pfree(spc->opts);
@ -66,7 +70,7 @@ InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
/* /*
* InitializeTableSpaceCache * InitializeTableSpaceCache
* Initiate the tablespace cache. * Initialize the tablespace cache.
*/ */
static void static void
InitializeTableSpaceCache(void) InitializeTableSpaceCache(void)
@ -76,8 +80,8 @@ InitializeTableSpaceCache(void)
/* Initialize the hash table. */ /* Initialize the hash table. */
MemSet(&ctl, 0, sizeof(ctl)); MemSet(&ctl, 0, sizeof(ctl));
ctl.keysize = sizeof(Oid); ctl.keysize = sizeof(Oid);
ctl.entrysize = sizeof(TableSpace); ctl.entrysize = sizeof(TableSpaceCacheEntry);
ctl.hash = tag_hash; ctl.hash = oid_hash;
TableSpaceCacheHash = TableSpaceCacheHash =
hash_create("TableSpace cache", 16, &ctl, hash_create("TableSpace cache", 16, &ctl,
HASH_ELEM | HASH_FUNCTION); HASH_ELEM | HASH_FUNCTION);
@ -94,17 +98,17 @@ InitializeTableSpaceCache(void)
/* /*
* get_tablespace * get_tablespace
* Fetch TableSpace structure for a specified table OID. * Fetch TableSpaceCacheEntry structure for a specified table OID.
* *
* Pointers returned by this function should not be stored, since a cache * Pointers returned by this function should not be stored, since a cache
* flush will invalidate them. * flush will invalidate them.
*/ */
static TableSpace * static TableSpaceCacheEntry *
get_tablespace(Oid spcid) get_tablespace(Oid spcid)
{ {
TableSpaceCacheEntry *spc;
HeapTuple tp; HeapTuple tp;
TableSpace *spc; TableSpaceOpts *opts;
bool found;
/* /*
* Since spcid is always from a pg_class tuple, InvalidOid implies the * Since spcid is always from a pg_class tuple, InvalidOid implies the
@ -113,12 +117,14 @@ get_tablespace(Oid spcid)
if (spcid == InvalidOid) if (spcid == InvalidOid)
spcid = MyDatabaseTableSpace; spcid = MyDatabaseTableSpace;
/* Find existing cache entry, or create a new one. */ /* Find existing cache entry, if any. */
if (!TableSpaceCacheHash) if (!TableSpaceCacheHash)
InitializeTableSpaceCache(); InitializeTableSpaceCache();
spc = (TableSpace *) hash_search(TableSpaceCacheHash, (void *) &spcid, spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
HASH_ENTER, &found); (void *) &spcid,
if (found) HASH_FIND,
NULL);
if (spc)
return spc; return spc;
/* /*
@ -127,9 +133,11 @@ get_tablespace(Oid spcid)
* details for a non-existent tablespace. We'll just treat that case as if * details for a non-existent tablespace. We'll just treat that case as if
* no options were specified. * no options were specified.
*/ */
tp = SearchSysCache(TABLESPACEOID, ObjectIdGetDatum(spcid), 0, 0, 0); tp = SearchSysCache(TABLESPACEOID,
ObjectIdGetDatum(spcid),
0, 0, 0);
if (!HeapTupleIsValid(tp)) if (!HeapTupleIsValid(tp))
spc->opts = NULL; opts = NULL;
else else
{ {
Datum datum; Datum datum;
@ -141,29 +149,40 @@ get_tablespace(Oid spcid)
Anum_pg_tablespace_spcoptions, Anum_pg_tablespace_spcoptions,
&isNull); &isNull);
if (isNull) if (isNull)
spc->opts = NULL; opts = NULL;
else else
{ {
/* XXX should NOT do the parsing work in CacheMemoryContext */
octx = MemoryContextSwitchTo(CacheMemoryContext); octx = MemoryContextSwitchTo(CacheMemoryContext);
spc->opts = (TableSpaceOpts *) tablespace_reloptions(datum, false); opts = (TableSpaceOpts *) tablespace_reloptions(datum, false);
MemoryContextSwitchTo(octx); MemoryContextSwitchTo(octx);
} }
ReleaseSysCache(tp); ReleaseSysCache(tp);
} }
/* Update new TableSpace cache entry with results of option parsing. */ /*
* 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; return spc;
} }
/* /*
* get_tablespace_page_costs * get_tablespace_page_costs
* Return random and sequential page costs for a given tablespace. * Return random and/or sequential page costs for a given tablespace.
*/ */
void void
get_tablespace_page_costs(Oid spcid, double *spc_random_page_cost, get_tablespace_page_costs(Oid spcid,
double *spc_seq_page_cost) double *spc_random_page_cost,
double *spc_seq_page_cost)
{ {
TableSpace *spc = get_tablespace(spcid); TableSpaceCacheEntry *spc = get_tablespace(spcid);
Assert(spc != NULL); Assert(spc != NULL);