Do some restructuring to improve performance of the catcaches. Teach

CatalogCacheFlushRelation (formerly called SystemCacheRelationFlushed)
how to distinguish tuples it should flush from those it needn't; this
means a relcache flush event now only removes the catcache entries
it ought to, rather than zapping the caches completely as it used to.
Testing with the regression tests indicates that this considerably
improves the lifespan of catcache entries.  Also, rearrange catcache
data structures so that the limit on number of cached tuples applies
globally across all the catcaches, rather than being per-catcache.
It was a little silly to have the same size limit on both, say,
pg_attribute caches and pg_am caches (there being only four possible
rows in the latter...).  Doing LRU removal across all the caches
instead of locally in each one should reduce cache reload traffic
in the more heavily used caches and improve the efficiency of
cache memory use.
This commit is contained in:
Tom Lane 2001-06-18 03:35:07 +00:00
parent 41c377f5c6
commit 2c5aa2acb4
5 changed files with 268 additions and 190 deletions

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.78 2001/06/01 02:41:36 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.79 2001/06/18 03:35:07 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -29,17 +29,15 @@
#include "utils/syscache.h" #include "utils/syscache.h"
static void CatCacheRemoveCTup(CatCache *cache, CatCTup *ct); /* #define CACHEDEBUG */ /* turns DEBUG elogs on */
static Index CatalogCacheComputeHashIndex(CatCache *cache,
ScanKey cur_skey); /* voodoo constants */
static Index CatalogCacheComputeTupleHashIndex(CatCache *cache, #define NCCBUCKETS 257 /* Hash buckets per CatCache (prime!) */
HeapTuple tuple); #define MAXCCTUPLES 5000 /* Maximum # of tuples in all caches */
static void CatalogCacheInitializeCache(CatCache *cache);
static Datum cc_hashname(PG_FUNCTION_ARGS);
/* /*
* variables, macros and other stuff * variables, macros and other stuff
*
*/ */
#ifdef CACHEDEBUG #ifdef CACHEDEBUG
@ -58,8 +56,8 @@ static Datum cc_hashname(PG_FUNCTION_ARGS);
#define CACHE6_elog(a,b,c,d,e,f,g) #define CACHE6_elog(a,b,c,d,e,f,g)
#endif #endif
static CatCache *Caches = NULL; /* head of list of caches */ /* Cache management header --- pointer is NULL until created */
static CatCacheHeader *CacheHdr = NULL;
/* /*
* EQPROC is used in CatalogCacheInitializeCache to find the equality * EQPROC is used in CatalogCacheInitializeCache to find the equality
@ -68,7 +66,6 @@ static CatCache *Caches = NULL; /* head of list of caches */
* *
* XXX this should be replaced by catalog lookups, * XXX this should be replaced by catalog lookups,
* but that seems to pose considerable risk of circularity... * but that seems to pose considerable risk of circularity...
*
*/ */
static const Oid eqproc[] = { static const Oid eqproc[] = {
F_BOOLEQ, InvalidOid, F_CHAREQ, F_NAMEEQ, InvalidOid, F_BOOLEQ, InvalidOid, F_CHAREQ, F_NAMEEQ, InvalidOid,
@ -78,9 +75,18 @@ static const Oid eqproc[] = {
#define EQPROC(SYSTEMTYPEOID) eqproc[(SYSTEMTYPEOID)-BOOLOID] #define EQPROC(SYSTEMTYPEOID) eqproc[(SYSTEMTYPEOID)-BOOLOID]
static void CatCacheRemoveCTup(CatCache *cache, CatCTup *ct);
static Index CatalogCacheComputeHashIndex(CatCache *cache,
ScanKey cur_skey);
static Index CatalogCacheComputeTupleHashIndex(CatCache *cache,
HeapTuple tuple);
static void CatalogCacheInitializeCache(CatCache *cache);
static Datum cc_hashname(PG_FUNCTION_ARGS);
/* /*
* internal support functions * internal support functions
*
*/ */
static PGFunction static PGFunction
@ -88,8 +94,8 @@ GetCCHashFunc(Oid keytype)
{ {
switch (keytype) switch (keytype)
{ {
case BOOLOID: case BOOLOID:
case CHAROID: case CHAROID:
return hashchar; return hashchar;
case NAMEOID: case NAMEOID:
return cc_hashname; return cc_hashname;
@ -116,7 +122,6 @@ GetCCHashFunc(Oid keytype)
static Datum static Datum
cc_hashname(PG_FUNCTION_ARGS) cc_hashname(PG_FUNCTION_ARGS)
{ {
/* /*
* We need our own variant of hashname because we want to accept * We need our own variant of hashname because we want to accept
* null-terminated C strings as search values for name fields. So, we * null-terminated C strings as search values for name fields. So, we
@ -141,7 +146,6 @@ cc_hashname(PG_FUNCTION_ARGS)
void void
CreateCacheMemoryContext(void) CreateCacheMemoryContext(void)
{ {
/* /*
* Purely for paranoia, check that context doesn't exist; caller * Purely for paranoia, check that context doesn't exist; caller
* probably did so already. * probably did so already.
@ -161,7 +165,6 @@ CreateCacheMemoryContext(void)
* This function does final initialization of a catcache: obtain the tuple * This function does final initialization of a catcache: obtain the tuple
* descriptor and set up the hash and equality function links. We assume * descriptor and set up the hash and equality function links. We assume
* that the relcache entry can be opened at this point! * that the relcache entry can be opened at this point!
*
*/ */
#ifdef CACHEDEBUG #ifdef CACHEDEBUG
#define CatalogCacheInitializeCache_DEBUG1 \ #define CatalogCacheInitializeCache_DEBUG1 \
@ -191,7 +194,7 @@ CatalogCacheInitializeCache(CatCache *cache)
Relation relation; Relation relation;
MemoryContext oldcxt; MemoryContext oldcxt;
TupleDesc tupdesc; TupleDesc tupdesc;
short i; int i;
CatalogCacheInitializeCache_DEBUG1; CatalogCacheInitializeCache_DEBUG1;
@ -206,8 +209,7 @@ CatalogCacheInitializeCache(CatCache *cache)
* switch to the cache context so our allocations do not vanish at the * switch to the cache context so our allocations do not vanish at the
* end of a transaction * end of a transaction
*/ */
if (!CacheMemoryContext) Assert(CacheMemoryContext != NULL);
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo(CacheMemoryContext); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
@ -286,7 +288,6 @@ CatalogCacheInitializeCache(CatCache *cache)
/* /*
* CatalogCacheComputeHashIndex * CatalogCacheComputeHashIndex
*
*/ */
static Index static Index
CatalogCacheComputeHashIndex(CatCache *cache, ScanKey cur_skey) CatalogCacheComputeHashIndex(CatCache *cache, ScanKey cur_skey)
@ -330,7 +331,6 @@ CatalogCacheComputeHashIndex(CatCache *cache, ScanKey cur_skey)
/* /*
* CatalogCacheComputeTupleHashIndex * CatalogCacheComputeTupleHashIndex
*
*/ */
static Index static Index
CatalogCacheComputeTupleHashIndex(CatCache *cache, CatalogCacheComputeTupleHashIndex(CatCache *cache,
@ -396,12 +396,12 @@ CatalogCacheComputeTupleHashIndex(CatCache *cache,
/* /*
* CatCacheRemoveCTup * CatCacheRemoveCTup
*
*/ */
static void static void
CatCacheRemoveCTup(CatCache *cache, CatCTup *ct) CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)
{ {
Assert(ct->refcount == 0); Assert(ct->refcount == 0);
Assert(ct->my_cache == cache);
/* delink from linked lists */ /* delink from linked lists */
DLRemove(&ct->lrulist_elem); DLRemove(&ct->lrulist_elem);
@ -413,6 +413,7 @@ CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)
pfree(ct); pfree(ct);
--cache->cc_ntup; --cache->cc_ntup;
--CacheHdr->ch_ntup;
} }
/* /*
@ -422,7 +423,6 @@ CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)
* be found (whether the cache has opened its relation or not). Of course, * be found (whether the cache has opened its relation or not). Of course,
* if the cache has yet to open its relation, there will be no tuples so * if the cache has yet to open its relation, there will be no tuples so
* no problem. * no problem.
*
*/ */
void void
CatalogCacheIdInvalidate(int cacheId, CatalogCacheIdInvalidate(int cacheId,
@ -433,17 +433,14 @@ CatalogCacheIdInvalidate(int cacheId,
/* /*
* sanity checks * sanity checks
*
*/ */
Assert(hashIndex < NCCBUCK);
Assert(ItemPointerIsValid(pointer)); Assert(ItemPointerIsValid(pointer));
CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: called"); CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: called");
/* /*
* inspect caches to find the proper cache * inspect caches to find the proper cache
*
*/ */
for (ccp = Caches; ccp; ccp = ccp->cc_next) for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next)
{ {
Dlelem *elt, Dlelem *elt,
*nextelt; *nextelt;
@ -451,11 +448,12 @@ CatalogCacheIdInvalidate(int cacheId,
if (cacheId != ccp->id) if (cacheId != ccp->id)
continue; continue;
Assert(hashIndex < ccp->cc_size);
/* /*
* inspect the hash bucket until we find a match or exhaust * inspect the hash bucket until we find a match or exhaust
*
*/ */
for (elt = DLGetHead(&ccp->cc_cache[hashIndex]); elt; elt = nextelt) for (elt = DLGetHead(&ccp->cc_bucket[hashIndex]); elt; elt = nextelt)
{ {
CatCTup *ct = (CatCTup *) DLE_VAL(elt); CatCTup *ct = (CatCTup *) DLE_VAL(elt);
@ -479,7 +477,7 @@ CatalogCacheIdInvalidate(int cacheId,
* public functions * public functions
* *
* AtEOXact_CatCache * AtEOXact_CatCache
* ResetSystemCache * ResetCatalogCaches
* InitCatCache * InitCatCache
* SearchCatCache * SearchCatCache
* ReleaseCatCache * ReleaseCatCache
@ -497,68 +495,55 @@ CatalogCacheIdInvalidate(int cacheId,
* necessary in the abort case, since elog() may have interrupted routines. * necessary in the abort case, since elog() may have interrupted routines.
* In the commit case, any nonzero counts indicate failure to call * In the commit case, any nonzero counts indicate failure to call
* ReleaseSysCache, so we put out a notice for debugging purposes. * ReleaseSysCache, so we put out a notice for debugging purposes.
*
*/ */
void void
AtEOXact_CatCache(bool isCommit) AtEOXact_CatCache(bool isCommit)
{ {
CatCache *cache; Dlelem *elt,
*nextelt;
for (cache = Caches; cache; cache = cache->cc_next) for (elt = DLGetHead(&CacheHdr->ch_lrulist); elt; elt = nextelt)
{ {
Dlelem *elt, CatCTup *ct = (CatCTup *) DLE_VAL(elt);
*nextelt;
for (elt = DLGetHead(&cache->cc_lrulist); elt; elt = nextelt) nextelt = DLGetSucc(elt);
if (ct->refcount != 0)
{ {
CatCTup *ct = (CatCTup *) DLE_VAL(elt); if (isCommit)
elog(NOTICE, "Cache reference leak: cache %s (%d), tuple %u has count %d",
nextelt = DLGetSucc(elt); ct->my_cache->cc_relname, ct->my_cache->id,
ct->tuple.t_data->t_oid,
if (ct->refcount != 0) ct->refcount);
{ ct->refcount = 0;
if (isCommit)
elog(NOTICE, "Cache reference leak: cache %s (%d), tuple %u has count %d",
cache->cc_relname, cache->id,
ct->tuple.t_data->t_oid,
ct->refcount);
ct->refcount = 0;
}
/* Clean up any now-deletable dead entries */
if (ct->dead)
CatCacheRemoveCTup(cache, ct);
} }
/* Clean up any now-deletable dead entries */
if (ct->dead)
CatCacheRemoveCTup(ct->my_cache, ct);
} }
} }
/* /*
* ResetSystemCache * ResetCatalogCache
* *
* Reset caches when a shared cache inval event forces it * Reset one catalog cache to empty.
* *
* This is not very efficient if the target cache is nearly empty.
* However, it shouldn't need to be efficient; we don't invoke it often.
*/ */
void static void
ResetSystemCache(void) ResetCatalogCache(CatCache *cache)
{ {
CatCache *cache; int i;
CACHE1_elog(DEBUG, "ResetSystemCache called"); /* Remove each tuple in this cache, or at least mark it dead */
for (i = 0; i < cache->cc_size; i++)
/* ----------------
* here we purge the contents of all the caches
*
* for each system cache
* for each tuple
* remove the tuple, or at least mark it dead
* ----------------
*/
for (cache = Caches; cache; cache = cache->cc_next)
{ {
Dlelem *elt, Dlelem *elt,
*nextelt; *nextelt;
for (elt = DLGetHead(&cache->cc_lrulist); elt; elt = nextelt) for (elt = DLGetHead(&cache->cc_bucket[i]); elt; elt = nextelt)
{ {
CatCTup *ct = (CatCTup *) DLE_VAL(elt); CatCTup *ct = (CatCTup *) DLE_VAL(elt);
@ -570,12 +555,28 @@ ResetSystemCache(void)
CatCacheRemoveCTup(cache, ct); CatCacheRemoveCTup(cache, ct);
} }
} }
CACHE1_elog(DEBUG, "end of ResetSystemCache call");
} }
/* /*
* SystemCacheRelationFlushed * ResetCatalogCaches
*
* Reset all caches when a shared cache inval event forces it
*/
void
ResetCatalogCaches(void)
{
CatCache *cache;
CACHE1_elog(DEBUG, "ResetCatalogCaches called");
for (cache = CacheHdr->ch_caches; cache; cache = cache->cc_next)
ResetCatalogCache(cache);
CACHE1_elog(DEBUG, "end of ResetCatalogCaches call");
}
/*
* CatalogCacheFlushRelation
* *
* This is called by RelationFlushRelation() to clear out cached information * This is called by RelationFlushRelation() to clear out cached information
* about a relation being dropped. (This could be a DROP TABLE command, * about a relation being dropped. (This could be a DROP TABLE command,
@ -586,26 +587,80 @@ ResetSystemCache(void)
* A special case occurs when relId is itself one of the cacheable system * A special case occurs when relId is itself one of the cacheable system
* tables --- although those'll never be dropped, they can get flushed from * tables --- although those'll never be dropped, they can get flushed from
* the relcache (VACUUM causes this, for example). In that case we need * the relcache (VACUUM causes this, for example). In that case we need
* to flush all cache entries from that table. The brute-force method * to flush all cache entries that came from that table. (At one point we
* currently used takes care of that quite handily. (At one point we
* also tried to force re-execution of CatalogCacheInitializeCache for * also tried to force re-execution of CatalogCacheInitializeCache for
* the cache(s) on that table. This is a bad idea since it leads to all * the cache(s) on that table. This is a bad idea since it leads to all
* kinds of trouble if a cache flush occurs while loading cache entries. * kinds of trouble if a cache flush occurs while loading cache entries.
* We now avoid the need to do it by copying cc_tupdesc out of the relcache, * We now avoid the need to do it by copying cc_tupdesc out of the relcache,
* rather than relying on the relcache to keep a tupdesc for us. Of course * rather than relying on the relcache to keep a tupdesc for us. Of course
* this assumes the tupdesc of a cachable system table will not change...) * this assumes the tupdesc of a cachable system table will not change...)
*
*/ */
void void
SystemCacheRelationFlushed(Oid relId) CatalogCacheFlushRelation(Oid relId)
{ {
CatCache *cache;
/* CACHE2_elog(DEBUG, "CatalogCacheFlushRelation called for %u", relId);
* XXX Ideally we'd search the caches and just zap entries that
* actually refer to or come from the indicated relation. For now, we for (cache = CacheHdr->ch_caches; cache; cache = cache->cc_next)
* take the brute-force approach: just flush the caches entirely. {
*/ int i;
ResetSystemCache();
/* We can ignore uninitialized caches, since they must be empty */
if (cache->cc_tupdesc == NULL)
continue;
/* Does this cache store tuples of the target relation itself? */
if (cache->cc_tupdesc->attrs[0]->attrelid == relId)
{
/* Yes, so flush all its contents */
ResetCatalogCache(cache);
continue;
}
/* Does this cache store tuples associated with relations at all? */
if (cache->cc_reloidattr == 0)
continue; /* nope, leave it alone */
/* Yes, scan the tuples and remove those related to relId */
for (i = 0; i < cache->cc_size; i++)
{
Dlelem *elt,
*nextelt;
for (elt = DLGetHead(&cache->cc_bucket[i]); elt; elt = nextelt)
{
CatCTup *ct = (CatCTup *) DLE_VAL(elt);
Oid tupRelid;
nextelt = DLGetSucc(elt);
if (cache->cc_reloidattr == ObjectIdAttributeNumber)
tupRelid = ct->tuple.t_data->t_oid;
else
{
bool isNull;
tupRelid = DatumGetObjectId(
fastgetattr(&ct->tuple,
cache->cc_reloidattr,
cache->cc_tupdesc,
&isNull));
Assert(!isNull);
}
if (tupRelid == relId)
{
if (ct->refcount > 0)
ct->dead = true;
else
CatCacheRemoveCTup(cache, ct);
}
}
}
}
CACHE1_elog(DEBUG, "end of CatalogCacheFlushRelation call");
} }
/* /*
@ -615,7 +670,6 @@ SystemCacheRelationFlushed(Oid relId)
* Actually, the cache is only partially initialized to avoid opening the * Actually, the cache is only partially initialized to avoid opening the
* relation. The relation will be opened and the rest of the cache * relation. The relation will be opened and the rest of the cache
* structure initialized on the first access. * structure initialized on the first access.
*
*/ */
#ifdef CACHEDEBUG #ifdef CACHEDEBUG
#define InitCatCache_DEBUG1 \ #define InitCatCache_DEBUG1 \
@ -628,10 +682,11 @@ do { \
#define InitCatCache_DEBUG1 #define InitCatCache_DEBUG1
#endif #endif
CatCache * CatCache *
InitCatCache(int id, InitCatCache(int id,
char *relname, char *relname,
char *indname, char *indname,
int reloidattr,
int nkeys, int nkeys,
int *key) int *key)
{ {
@ -642,63 +697,67 @@ InitCatCache(int id,
/* /*
* first switch to the cache context so our allocations do not vanish * first switch to the cache context so our allocations do not vanish
* at the end of a transaction * at the end of a transaction
*
*/ */
if (!CacheMemoryContext) if (!CacheMemoryContext)
CreateCacheMemoryContext(); CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo(CacheMemoryContext); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/*
* if first time through, initialize the cache group header,
* including global LRU list header
*/
if (CacheHdr == NULL)
{
CacheHdr = (CatCacheHeader *) palloc(sizeof(CatCacheHeader));
CacheHdr->ch_caches = NULL;
CacheHdr->ch_ntup = 0;
CacheHdr->ch_maxtup = MAXCCTUPLES;
DLInitList(&CacheHdr->ch_lrulist);
}
/* /*
* allocate a new cache structure * allocate a new cache structure
*
*/ */
cp = (CatCache *) palloc(sizeof(CatCache)); cp = (CatCache *) palloc(sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist));
MemSet((char *) cp, 0, sizeof(CatCache)); MemSet((char *) cp, 0, sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist));
/* /*
* initialize the cache buckets (each bucket is a list header) and the * initialize the cache buckets (each bucket is a list header)
* LRU tuple list
*
*/ */
DLInitList(&cp->cc_lrulist); for (i = 0; i < NCCBUCKETS; ++i)
for (i = 0; i < NCCBUCK; ++i) DLInitList(&cp->cc_bucket[i]);
DLInitList(&cp->cc_cache[i]);
/*
* Caches is the pointer to the head of the list of all the system
* caches. here we add the new cache to the top of the list.
*
*/
cp->cc_next = Caches; /* list of caches (single link) */
Caches = cp;
/* /*
* initialize the cache's relation information for the relation * initialize the cache's relation information for the relation
* corresponding to this cache, and initialize some of the new cache's * corresponding to this cache, and initialize some of the new cache's
* other internal fields. But don't open the relation yet. * other internal fields. But don't open the relation yet.
*
*/ */
cp->id = id;
cp->cc_relname = relname; cp->cc_relname = relname;
cp->cc_indname = indname; cp->cc_indname = indname;
cp->cc_reloidattr = reloidattr;
cp->cc_tupdesc = (TupleDesc) NULL; cp->cc_tupdesc = (TupleDesc) NULL;
cp->id = id; cp->cc_ntup = 0;
cp->cc_maxtup = MAXTUP; cp->cc_size = NCCBUCKETS;
cp->cc_size = NCCBUCK;
cp->cc_nkeys = nkeys; cp->cc_nkeys = nkeys;
for (i = 0; i < nkeys; ++i) for (i = 0; i < nkeys; ++i)
cp->cc_key[i] = key[i]; cp->cc_key[i] = key[i];
/* /*
* all done. new cache is initialized. print some debugging * new cache is initialized as far as we can go for now.
* information, if appropriate. * print some debugging information, if appropriate.
*
*/ */
InitCatCache_DEBUG1; InitCatCache_DEBUG1;
/*
* add completed cache to top of group header's list
*/
cp->cc_next = CacheHdr->ch_caches;
CacheHdr->ch_caches = cp;
/* /*
* back to the old context before we return... * back to the old context before we return...
*
*/ */
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
@ -766,7 +825,6 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey)
* *
* This call searches a system cache for a tuple, opening the relation * This call searches a system cache for a tuple, opening the relation
* if necessary (the first access to a particular cache). * if necessary (the first access to a particular cache).
*
*/ */
HeapTuple HeapTuple
SearchCatCache(CatCache *cache, SearchCatCache(CatCache *cache,
@ -785,14 +843,12 @@ SearchCatCache(CatCache *cache,
/* /*
* one-time startup overhead * one-time startup overhead
*
*/ */
if (cache->cc_tupdesc == NULL) if (cache->cc_tupdesc == NULL)
CatalogCacheInitializeCache(cache); CatalogCacheInitializeCache(cache);
/* /*
* initialize the search key information * initialize the search key information
*
*/ */
memcpy(cur_skey, cache->cc_skey, sizeof(cur_skey)); memcpy(cur_skey, cache->cc_skey, sizeof(cur_skey));
cur_skey[0].sk_argument = v1; cur_skey[0].sk_argument = v1;
@ -802,15 +858,13 @@ SearchCatCache(CatCache *cache,
/* /*
* find the hash bucket in which to look for the tuple * find the hash bucket in which to look for the tuple
*
*/ */
hash = CatalogCacheComputeHashIndex(cache, cur_skey); hash = CatalogCacheComputeHashIndex(cache, cur_skey);
/* /*
* scan the hash bucket until we find a match or exhaust our tuples * scan the hash bucket until we find a match or exhaust our tuples
*
*/ */
for (elt = DLGetHead(&cache->cc_cache[hash]); for (elt = DLGetHead(&cache->cc_bucket[hash]);
elt; elt;
elt = DLGetSucc(elt)) elt = DLGetSucc(elt))
{ {
@ -824,7 +878,6 @@ SearchCatCache(CatCache *cache,
/* /*
* see if the cached tuple matches our key. (should we be worried * see if the cached tuple matches our key. (should we be worried
* about time ranges? -cim 10/2/90) * about time ranges? -cim 10/2/90)
*
*/ */
HeapKeyTest(&ct->tuple, HeapKeyTest(&ct->tuple,
cache->cc_tupdesc, cache->cc_tupdesc,
@ -841,7 +894,6 @@ SearchCatCache(CatCache *cache,
* subsequent searches. (The most frequently accessed elements in * subsequent searches. (The most frequently accessed elements in
* any hashbucket will tend to be near the front of the * any hashbucket will tend to be near the front of the
* hashbucket's list.) * hashbucket's list.)
*
*/ */
ct->refcount++; ct->refcount++;
@ -869,19 +921,16 @@ SearchCatCache(CatCache *cache,
* will never be referenced again, and will eventually age out of the * will never be referenced again, and will eventually age out of the
* cache, so there's no functional problem. This case is rare enough * cache, so there's no functional problem. This case is rare enough
* that it's not worth expending extra cycles to detect. * that it's not worth expending extra cycles to detect.
*
*/ */
/* /*
* open the relation associated with the cache * open the relation associated with the cache
*
*/ */
relation = heap_openr(cache->cc_relname, AccessShareLock); relation = heap_openr(cache->cc_relname, AccessShareLock);
/* /*
* Scan the relation to find the tuple. If there's an index, and if * Scan the relation to find the tuple. If there's an index, and if
* it's safe to do so, use the index. Else do a heap scan. * it's safe to do so, use the index. Else do a heap scan.
*
*/ */
ct = NULL; ct = NULL;
@ -958,13 +1007,11 @@ SearchCatCache(CatCache *cache,
/* /*
* close the relation * close the relation
*
*/ */
heap_close(relation, AccessShareLock); heap_close(relation, AccessShareLock);
/* /*
* scan is complete. if tup was found, we can add it to the cache. * scan is complete. if tup was found, we can add it to the cache.
*
*/ */
if (ct == NULL) if (ct == NULL)
return NULL; return NULL;
@ -972,27 +1019,27 @@ SearchCatCache(CatCache *cache,
/* /*
* Finish initializing the CatCTup header, and add it to the linked * Finish initializing the CatCTup header, and add it to the linked
* lists. * lists.
*
*/ */
CACHE1_elog(DEBUG, "SearchCatCache: found tuple"); CACHE1_elog(DEBUG, "SearchCatCache: found tuple");
ct->ct_magic = CT_MAGIC; ct->ct_magic = CT_MAGIC;
ct->my_cache = cache;
DLInitElem(&ct->lrulist_elem, (void *) ct); DLInitElem(&ct->lrulist_elem, (void *) ct);
DLInitElem(&ct->cache_elem, (void *) ct); DLInitElem(&ct->cache_elem, (void *) ct);
ct->refcount = 1; /* count this first reference */ ct->refcount = 1; /* count this first reference */
ct->dead = false; ct->dead = false;
DLAddHead(&cache->cc_lrulist, &ct->lrulist_elem); DLAddHead(&CacheHdr->ch_lrulist, &ct->lrulist_elem);
DLAddHead(&cache->cc_cache[hash], &ct->cache_elem); DLAddHead(&cache->cc_bucket[hash], &ct->cache_elem);
/* /*
* If we've exceeded the desired size of this cache, try to throw away * If we've exceeded the desired size of the caches, try to throw away
* the least recently used entry. * the least recently used entry.
*
*/ */
if (++cache->cc_ntup > cache->cc_maxtup) ++cache->cc_ntup;
if (++CacheHdr->ch_ntup > CacheHdr->ch_maxtup)
{ {
for (elt = DLGetTail(&cache->cc_lrulist); for (elt = DLGetTail(&CacheHdr->ch_lrulist);
elt; elt;
elt = DLGetPred(elt)) elt = DLGetPred(elt))
{ {
@ -1002,14 +1049,14 @@ SearchCatCache(CatCache *cache,
{ {
CACHE2_elog(DEBUG, "SearchCatCache(%s): Overflow, LRU removal", CACHE2_elog(DEBUG, "SearchCatCache(%s): Overflow, LRU removal",
cache->cc_relname); cache->cc_relname);
CatCacheRemoveCTup(cache, oldct); CatCacheRemoveCTup(oldct->my_cache, oldct);
break; break;
} }
} }
} }
CACHE4_elog(DEBUG, "SearchCatCache(%s): Contains %d/%d tuples", CACHE4_elog(DEBUG, "SearchCatCache(%s): Contains %d/%d tuples",
cache->cc_relname, cache->cc_ntup, cache->cc_maxtup); cache->cc_relname, cache->cc_ntup, CacheHdr->ch_ntup);
CACHE3_elog(DEBUG, "SearchCatCache(%s): put in bucket %d", CACHE3_elog(DEBUG, "SearchCatCache(%s): put in bucket %d",
cache->cc_relname, hash); cache->cc_relname, hash);
@ -1026,7 +1073,6 @@ SearchCatCache(CatCache *cache,
* will be freed as soon as their refcount goes to zero. In combination * will be freed as soon as their refcount goes to zero. In combination
* with aset.c's CLOBBER_FREED_MEMORY option, this provides a good test * with aset.c's CLOBBER_FREED_MEMORY option, this provides a good test
* to catch references to already-released catcache entries. * to catch references to already-released catcache entries.
*
*/ */
void void
ReleaseCatCache(HeapTuple tuple) ReleaseCatCache(HeapTuple tuple)
@ -1046,12 +1092,7 @@ ReleaseCatCache(HeapTuple tuple)
#endif #endif
) )
{ {
/* We can find the associated cache using the dllist pointers */ CatCacheRemoveCTup(ct->my_cache, ct);
Dllist *lru = DLGetListHdr(&ct->lrulist_elem);
CatCache *cache = (CatCache *) (((char *) lru) -
offsetof(CatCache, cc_lrulist));
CatCacheRemoveCTup(cache, ct);
} }
} }
@ -1061,7 +1102,7 @@ ReleaseCatCache(HeapTuple tuple)
* This is part of a rather subtle chain of events, so pay attention: * This is part of a rather subtle chain of events, so pay attention:
* *
* When a tuple is updated or deleted, it cannot be flushed from the * When a tuple is updated or deleted, it cannot be flushed from the
* catcaches immediately, for reasons explained at the top of inval.c. * catcaches immediately, for reasons explained at the top of cache/inval.c.
* Instead we have to add entry(s) for the tuple to a list of pending tuple * Instead we have to add entry(s) for the tuple to a list of pending tuple
* invalidations that will be done at the end of the command or transaction. * invalidations that will be done at the end of the command or transaction.
* *
@ -1081,7 +1122,6 @@ ReleaseCatCache(HeapTuple tuple)
* specified relation. inval.c doesn't know exactly which rels have * specified relation. inval.c doesn't know exactly which rels have
* catcaches --- it will call this routine for any tuple that's in a * catcaches --- it will call this routine for any tuple that's in a
* system relation. * system relation.
*
*/ */
void void
PrepareToInvalidateCacheTuple(Relation relation, PrepareToInvalidateCacheTuple(Relation relation,
@ -1090,14 +1130,15 @@ PrepareToInvalidateCacheTuple(Relation relation,
{ {
CatCache *ccp; CatCache *ccp;
CACHE1_elog(DEBUG, "PrepareToInvalidateCacheTuple: called");
/* /*
* sanity checks * sanity checks
*
*/ */
Assert(RelationIsValid(relation)); Assert(RelationIsValid(relation));
Assert(HeapTupleIsValid(tuple)); Assert(HeapTupleIsValid(tuple));
Assert(PointerIsValid(function)); Assert(PointerIsValid(function));
CACHE1_elog(DEBUG, "PrepareToInvalidateCacheTuple: called"); Assert(CacheHdr != NULL);
/* ---------------- /* ----------------
* for each cache * for each cache
@ -1107,7 +1148,7 @@ PrepareToInvalidateCacheTuple(Relation relation,
* ---------------- * ----------------
*/ */
for (ccp = Caches; ccp; ccp = ccp->cc_next) for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next)
{ {
if (strcmp(ccp->cc_relname, RelationGetRelationName(relation)) != 0) if (strcmp(ccp->cc_relname, RelationGetRelationName(relation)) != 0)
continue; continue;

View File

@ -34,7 +34,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.43 2001/06/01 20:23:06 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.44 2001/06/18 03:35:07 tgl Exp $
* *
* Note - this code is real crufty... badly needs a rewrite to improve * Note - this code is real crufty... badly needs a rewrite to improve
* readability and portability. (Shouldn't assume Oid == Index, for example) * readability and portability. (Shouldn't assume Oid == Index, for example)
@ -478,16 +478,20 @@ CacheIdInvalidate(Index cacheId,
} }
/* /*
* ResetSystemCaches * InvalidateSystemCaches
* *
* This blows away all tuples in the system catalog caches and * This blows away all tuples in the system catalog caches and
* all the cached relation descriptors (and closes their files too). * all the cached relation descriptors (and closes their files too).
* Relation descriptors that have positive refcounts are then rebuilt. * Relation descriptors that have positive refcounts are then rebuilt.
*
* We call this when we see a shared-inval-queue overflow signal,
* since that tells us we've lost some shared-inval messages and hence
* don't know what needs to be invalidated.
*/ */
static void static void
ResetSystemCaches(void) InvalidateSystemCaches(void)
{ {
ResetSystemCache(); ResetCatalogCaches();
RelationCacheInvalidate(); RelationCacheInvalidate();
} }
@ -643,7 +647,7 @@ DiscardInvalid(void)
elog(DEBUG, "DiscardInvalid called"); elog(DEBUG, "DiscardInvalid called");
#endif /* defined(INVALIDDEBUG) */ #endif /* defined(INVALIDDEBUG) */
InvalidateSharedInvalid(CacheIdInvalidate, ResetSystemCaches); InvalidateSharedInvalid(CacheIdInvalidate, InvalidateSystemCaches);
} }
/* /*

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.137 2001/06/12 05:55:49 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.138 2001/06/18 03:35:07 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1657,7 +1657,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
/* Clear out catcache's entries for this relation */ /* Clear out catcache's entries for this relation */
SystemCacheRelationFlushed(RelationGetRelid(relation)); CatalogCacheFlushRelation(RelationGetRelid(relation));
/* /*
* Free all the subsidiary data structures of the relcache entry. We * Free all the subsidiary data structures of the relcache entry. We

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.62 2001/06/12 05:55:49 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.63 2001/06/18 03:35:07 tgl Exp $
* *
* NOTES * NOTES
* These routines allow the parser/planner/executor to perform * These routines allow the parser/planner/executor to perform
@ -54,7 +54,12 @@
Add your entry to the cacheinfo[] array below. All cache lists are Add your entry to the cacheinfo[] array below. All cache lists are
alphabetical, so add it in the proper place. Specify the relation alphabetical, so add it in the proper place. Specify the relation
name, index name, number of keys, and key attribute numbers. name, index name, number of keys, and key attribute numbers. If the
relation contains tuples that are associated with a particular relation
(for example, its attributes, rules, triggers, etc) then specify the
attribute number that contains the OID of the associated relation.
This is used by CatalogCacheFlushRelation() to remove the correct
tuples during a table drop or relcache invalidation event.
In include/catalog/indexing.h, add a define for the number of indexes In include/catalog/indexing.h, add a define for the number of indexes
on the relation, add define(s) for the index name(s), add an extern on the relation, add define(s) for the index name(s), add an extern
@ -76,12 +81,12 @@
/* /*
* struct cachedesc: information defining a single syscache * struct cachedesc: information defining a single syscache
*
*/ */
struct cachedesc struct cachedesc
{ {
char *name; /* name of the relation being cached */ char *name; /* name of the relation being cached */
char *indname; /* name of index relation for this cache */ char *indname; /* name of index relation for this cache */
int reloidattr; /* attr number of rel OID reference, or 0 */
int nkeys; /* # of keys needed for cache lookup */ int nkeys; /* # of keys needed for cache lookup */
int key[4]; /* attribute numbers of key attrs */ int key[4]; /* attribute numbers of key attrs */
}; };
@ -89,6 +94,7 @@ struct cachedesc
static struct cachedesc cacheinfo[] = { static struct cachedesc cacheinfo[] = {
{AggregateRelationName, /* AGGNAME */ {AggregateRelationName, /* AGGNAME */
AggregateNameTypeIndex, AggregateNameTypeIndex,
0,
2, 2,
{ {
Anum_pg_aggregate_aggname, Anum_pg_aggregate_aggname,
@ -98,6 +104,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{AccessMethodRelationName, /* AMNAME */ {AccessMethodRelationName, /* AMNAME */
AmNameIndex, AmNameIndex,
0,
1, 1,
{ {
Anum_pg_am_amname, Anum_pg_am_amname,
@ -107,6 +114,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{AccessMethodOperatorRelationName, /* AMOPOPID */ {AccessMethodOperatorRelationName, /* AMOPOPID */
AccessMethodOpidIndex, AccessMethodOpidIndex,
0,
3, 3,
{ {
Anum_pg_amop_amopclaid, Anum_pg_amop_amopclaid,
@ -116,6 +124,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{AccessMethodOperatorRelationName, /* AMOPSTRATEGY */ {AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
AccessMethodStrategyIndex, AccessMethodStrategyIndex,
0,
3, 3,
{ {
Anum_pg_amop_amopid, Anum_pg_amop_amopid,
@ -125,6 +134,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{AttributeRelationName, /* ATTNAME */ {AttributeRelationName, /* ATTNAME */
AttributeRelidNameIndex, AttributeRelidNameIndex,
Anum_pg_attribute_attrelid,
2, 2,
{ {
Anum_pg_attribute_attrelid, Anum_pg_attribute_attrelid,
@ -134,6 +144,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{AttributeRelationName, /* ATTNUM */ {AttributeRelationName, /* ATTNUM */
AttributeRelidNumIndex, AttributeRelidNumIndex,
Anum_pg_attribute_attrelid,
2, 2,
{ {
Anum_pg_attribute_attrelid, Anum_pg_attribute_attrelid,
@ -143,6 +154,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{OperatorClassRelationName, /* CLADEFTYPE */ {OperatorClassRelationName, /* CLADEFTYPE */
OpclassDeftypeIndex, OpclassDeftypeIndex,
0,
1, 1,
{ {
Anum_pg_opclass_opcdeftype, Anum_pg_opclass_opcdeftype,
@ -152,6 +164,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{OperatorClassRelationName, /* CLANAME */ {OperatorClassRelationName, /* CLANAME */
OpclassNameIndex, OpclassNameIndex,
0,
1, 1,
{ {
Anum_pg_opclass_opcname, Anum_pg_opclass_opcname,
@ -161,6 +174,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{GroupRelationName, /* GRONAME */ {GroupRelationName, /* GRONAME */
GroupNameIndex, GroupNameIndex,
0,
1, 1,
{ {
Anum_pg_group_groname, Anum_pg_group_groname,
@ -170,6 +184,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{GroupRelationName, /* GROSYSID */ {GroupRelationName, /* GROSYSID */
GroupSysidIndex, GroupSysidIndex,
0,
1, 1,
{ {
Anum_pg_group_grosysid, Anum_pg_group_grosysid,
@ -179,6 +194,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{IndexRelationName, /* INDEXRELID */ {IndexRelationName, /* INDEXRELID */
IndexRelidIndex, IndexRelidIndex,
Anum_pg_index_indrelid,
1, 1,
{ {
Anum_pg_index_indexrelid, Anum_pg_index_indexrelid,
@ -188,6 +204,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{InheritsRelationName, /* INHRELID */ {InheritsRelationName, /* INHRELID */
InheritsRelidSeqnoIndex, InheritsRelidSeqnoIndex,
Anum_pg_inherits_inhrelid,
2, 2,
{ {
Anum_pg_inherits_inhrelid, Anum_pg_inherits_inhrelid,
@ -197,6 +214,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{LanguageRelationName, /* LANGNAME */ {LanguageRelationName, /* LANGNAME */
LanguageNameIndex, LanguageNameIndex,
0,
1, 1,
{ {
Anum_pg_language_lanname, Anum_pg_language_lanname,
@ -206,6 +224,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{LanguageRelationName, /* LANGOID */ {LanguageRelationName, /* LANGOID */
LanguageOidIndex, LanguageOidIndex,
0,
1, 1,
{ {
ObjectIdAttributeNumber, ObjectIdAttributeNumber,
@ -215,6 +234,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{OperatorRelationName, /* OPERNAME */ {OperatorRelationName, /* OPERNAME */
OperatorNameIndex, OperatorNameIndex,
0,
4, 4,
{ {
Anum_pg_operator_oprname, Anum_pg_operator_oprname,
@ -224,6 +244,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{OperatorRelationName, /* OPEROID */ {OperatorRelationName, /* OPEROID */
OperatorOidIndex, OperatorOidIndex,
0,
1, 1,
{ {
ObjectIdAttributeNumber, ObjectIdAttributeNumber,
@ -233,6 +254,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{ProcedureRelationName, /* PROCNAME */ {ProcedureRelationName, /* PROCNAME */
ProcedureNameIndex, ProcedureNameIndex,
0,
3, 3,
{ {
Anum_pg_proc_proname, Anum_pg_proc_proname,
@ -242,6 +264,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{ProcedureRelationName, /* PROCOID */ {ProcedureRelationName, /* PROCOID */
ProcedureOidIndex, ProcedureOidIndex,
0,
1, 1,
{ {
ObjectIdAttributeNumber, ObjectIdAttributeNumber,
@ -251,6 +274,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{RelationRelationName, /* RELNAME */ {RelationRelationName, /* RELNAME */
ClassNameIndex, ClassNameIndex,
ObjectIdAttributeNumber,
1, 1,
{ {
Anum_pg_class_relname, Anum_pg_class_relname,
@ -260,6 +284,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{RelationRelationName, /* RELOID */ {RelationRelationName, /* RELOID */
ClassOidIndex, ClassOidIndex,
ObjectIdAttributeNumber,
1, 1,
{ {
ObjectIdAttributeNumber, ObjectIdAttributeNumber,
@ -269,6 +294,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{RewriteRelationName, /* RULENAME */ {RewriteRelationName, /* RULENAME */
RewriteRulenameIndex, RewriteRulenameIndex,
Anum_pg_rewrite_ev_class,
1, 1,
{ {
Anum_pg_rewrite_rulename, Anum_pg_rewrite_rulename,
@ -278,6 +304,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{ShadowRelationName, /* SHADOWNAME */ {ShadowRelationName, /* SHADOWNAME */
ShadowNameIndex, ShadowNameIndex,
0,
1, 1,
{ {
Anum_pg_shadow_usename, Anum_pg_shadow_usename,
@ -287,6 +314,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{ShadowRelationName, /* SHADOWSYSID */ {ShadowRelationName, /* SHADOWSYSID */
ShadowSysidIndex, ShadowSysidIndex,
0,
1, 1,
{ {
Anum_pg_shadow_usesysid, Anum_pg_shadow_usesysid,
@ -296,6 +324,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{StatisticRelationName, /* STATRELATT */ {StatisticRelationName, /* STATRELATT */
StatisticRelidAttnumIndex, StatisticRelidAttnumIndex,
Anum_pg_statistic_starelid,
2, 2,
{ {
Anum_pg_statistic_starelid, Anum_pg_statistic_starelid,
@ -305,6 +334,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{TypeRelationName, /* TYPENAME */ {TypeRelationName, /* TYPENAME */
TypeNameIndex, TypeNameIndex,
Anum_pg_type_typrelid,
1, 1,
{ {
Anum_pg_type_typname, Anum_pg_type_typname,
@ -314,6 +344,7 @@ static struct cachedesc cacheinfo[] = {
}}, }},
{TypeRelationName, /* TYPEOID */ {TypeRelationName, /* TYPEOID */
TypeOidIndex, TypeOidIndex,
Anum_pg_type_typrelid,
1, 1,
{ {
ObjectIdAttributeNumber, ObjectIdAttributeNumber,
@ -323,8 +354,7 @@ static struct cachedesc cacheinfo[] = {
}} }}
}; };
static CatCache *SysCache[ static CatCache *SysCache[lengthof(cacheinfo)];
lengthof(cacheinfo)];
static int SysCacheSize = lengthof(cacheinfo); static int SysCacheSize = lengthof(cacheinfo);
static bool CacheInitialized = false; static bool CacheInitialized = false;
@ -358,6 +388,7 @@ InitCatalogCache(void)
SysCache[cacheId] = InitCatCache(cacheId, SysCache[cacheId] = InitCatCache(cacheId,
cacheinfo[cacheId].name, cacheinfo[cacheId].name,
cacheinfo[cacheId].indname, cacheinfo[cacheId].indname,
cacheinfo[cacheId].reloidattr,
cacheinfo[cacheId].nkeys, cacheinfo[cacheId].nkeys,
cacheinfo[cacheId].key); cacheinfo[cacheId].key);
if (!PointerIsValid(SysCache[cacheId])) if (!PointerIsValid(SysCache[cacheId]))

View File

@ -13,32 +13,49 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: catcache.h,v 1.32 2001/03/22 04:01:11 momjian Exp $ * $Id: catcache.h,v 1.33 2001/06/18 03:35:07 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#ifndef CATCACHE_H #ifndef CATCACHE_H
#define CATCACHE_H #define CATCACHE_H
/* #define CACHEDEBUG *//* turns DEBUG elogs on */
#include "access/htup.h" #include "access/htup.h"
#include "lib/dllist.h" #include "lib/dllist.h"
/* /*
* struct catctup: individual tuple in the cache. * struct catctup: individual tuple in the cache.
* struct catcache: information for managing a cache. * struct catcache: information for managing a cache.
* struct catcacheheader: information for managing all the caches.
*/ */
typedef struct catcache
{
int id; /* cache identifier --- see syscache.h */
struct catcache *cc_next; /* link to next catcache */
char *cc_relname; /* name of relation the tuples come from */
char *cc_indname; /* name of index matching cache keys */
int cc_reloidattr; /* AttrNumber of relation OID, or 0 */
TupleDesc cc_tupdesc; /* tuple descriptor (copied from reldesc) */
int cc_ntup; /* # of tuples currently in this cache */
int cc_size; /* # of hash buckets in this cache */
int cc_nkeys; /* number of keys (1..4) */
int cc_key[4]; /* AttrNumber of each key */
PGFunction cc_hashfunc[4]; /* hash function to use for each key */
ScanKeyData cc_skey[4]; /* precomputed key info for heap scans */
Dllist cc_bucket[1]; /* hash buckets --- VARIABLE LENGTH ARRAY */
} CatCache; /* VARIABLE LENGTH STRUCT */
typedef struct catctup typedef struct catctup
{ {
int ct_magic; /* for Assert checks */ int ct_magic; /* for Assert checks */
#define CT_MAGIC 0x57261502 #define CT_MAGIC 0x57261502
CatCache *my_cache; /* link to owning catcache */
/* /*
* Each tuple in a cache is a member of two lists: one lists all the * Each tuple in a cache is a member of two lists: one lists all the
* elements in that cache in LRU order, and the other lists just the * elements in all the caches in LRU order, and the other lists just
* elements in one hashbucket, also in LRU order. * the elements in one hashbucket of one cache, also in LRU order.
* *
* A tuple marked "dead" must not be returned by subsequent searches. * A tuple marked "dead" must not be returned by subsequent searches.
* However, it won't be physically deleted from the cache until its * However, it won't be physically deleted from the cache until its
@ -52,30 +69,14 @@ typedef struct catctup
} CatCTup; } CatCTup;
/* voodoo constants */ typedef struct catcacheheader
#define NCCBUCK 500 /* CatCache buckets */
#define MAXTUP 500 /* Maximum # of tuples stored per cache */
typedef struct catcache
{ {
int id; /* cache identifier --- see syscache.h */ CatCache *ch_caches; /* head of list of CatCache structs */
struct catcache *cc_next; /* link to next catcache */ int ch_ntup; /* # of tuples in all caches */
char *cc_relname; /* name of relation the tuples come from */ int ch_maxtup; /* max # of tuples allowed (LRU) */
char *cc_indname; /* name of index matching cache keys */ Dllist ch_lrulist; /* overall LRU list, most recent first */
TupleDesc cc_tupdesc; /* tuple descriptor (copied from reldesc) */ } CatCacheHeader;
short cc_ntup; /* # of tuples in this cache */
short cc_maxtup; /* max # of tuples allowed (LRU) */
short cc_size; /* # of hash buckets in this cache */
short cc_nkeys; /* number of keys (1..4) */
short cc_key[4]; /* AttrNumber of each key */
PGFunction cc_hashfunc[4]; /* hash function to use for each key */
ScanKeyData cc_skey[4]; /* precomputed key info for heap scans */
Dllist cc_lrulist; /* overall LRU list, most recent first */
Dllist cc_cache[NCCBUCK]; /* hash buckets */
} CatCache;
#define InvalidCatalogCacheId (-1)
/* this extern duplicates utils/memutils.h... */ /* this extern duplicates utils/memutils.h... */
extern MemoryContext CacheMemoryContext; extern MemoryContext CacheMemoryContext;
@ -84,15 +85,16 @@ extern void CreateCacheMemoryContext(void);
extern void AtEOXact_CatCache(bool isCommit); extern void AtEOXact_CatCache(bool isCommit);
extern CatCache *InitCatCache(int id, char *relname, char *indname, extern CatCache *InitCatCache(int id, char *relname, char *indname,
int nkeys, int *key); int reloidattr,
int nkeys, int *key);
extern HeapTuple SearchCatCache(CatCache *cache, extern HeapTuple SearchCatCache(CatCache *cache,
Datum v1, Datum v2, Datum v1, Datum v2,
Datum v3, Datum v4); Datum v3, Datum v4);
extern void ReleaseCatCache(HeapTuple tuple); extern void ReleaseCatCache(HeapTuple tuple);
extern void ResetSystemCache(void); extern void ResetCatalogCaches(void);
extern void SystemCacheRelationFlushed(Oid relId); extern void CatalogCacheFlushRelation(Oid relId);
extern void CatalogCacheIdInvalidate(int cacheId, Index hashIndex, extern void CatalogCacheIdInvalidate(int cacheId, Index hashIndex,
ItemPointer pointer); ItemPointer pointer);
extern void PrepareToInvalidateCacheTuple(Relation relation, extern void PrepareToInvalidateCacheTuple(Relation relation,