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
* $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"
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);
/* #define CACHEDEBUG */ /* turns DEBUG elogs on */
/* voodoo constants */
#define NCCBUCKETS 257 /* Hash buckets per CatCache (prime!) */
#define MAXCCTUPLES 5000 /* Maximum # of tuples in all caches */
/*
* variables, macros and other stuff
*
*/
#ifdef CACHEDEBUG
@ -58,8 +56,8 @@ static Datum cc_hashname(PG_FUNCTION_ARGS);
#define CACHE6_elog(a,b,c,d,e,f,g)
#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
@ -68,7 +66,6 @@ static CatCache *Caches = NULL; /* head of list of caches */
*
* XXX this should be replaced by catalog lookups,
* but that seems to pose considerable risk of circularity...
*
*/
static const Oid eqproc[] = {
F_BOOLEQ, InvalidOid, F_CHAREQ, F_NAMEEQ, InvalidOid,
@ -78,9 +75,18 @@ static const Oid eqproc[] = {
#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
*
*/
static PGFunction
@ -88,8 +94,8 @@ GetCCHashFunc(Oid keytype)
{
switch (keytype)
{
case BOOLOID:
case CHAROID:
case BOOLOID:
case CHAROID:
return hashchar;
case NAMEOID:
return cc_hashname;
@ -116,7 +122,6 @@ GetCCHashFunc(Oid keytype)
static Datum
cc_hashname(PG_FUNCTION_ARGS)
{
/*
* We need our own variant of hashname because we want to accept
* null-terminated C strings as search values for name fields. So, we
@ -141,7 +146,6 @@ cc_hashname(PG_FUNCTION_ARGS)
void
CreateCacheMemoryContext(void)
{
/*
* Purely for paranoia, check that context doesn't exist; caller
* probably did so already.
@ -161,7 +165,6 @@ CreateCacheMemoryContext(void)
* This function does final initialization of a catcache: obtain the tuple
* descriptor and set up the hash and equality function links. We assume
* that the relcache entry can be opened at this point!
*
*/
#ifdef CACHEDEBUG
#define CatalogCacheInitializeCache_DEBUG1 \
@ -191,7 +194,7 @@ CatalogCacheInitializeCache(CatCache *cache)
Relation relation;
MemoryContext oldcxt;
TupleDesc tupdesc;
short i;
int i;
CatalogCacheInitializeCache_DEBUG1;
@ -206,8 +209,7 @@ CatalogCacheInitializeCache(CatCache *cache)
* switch to the cache context so our allocations do not vanish at the
* end of a transaction
*/
if (!CacheMemoryContext)
CreateCacheMemoryContext();
Assert(CacheMemoryContext != NULL);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
@ -286,7 +288,6 @@ CatalogCacheInitializeCache(CatCache *cache)
/*
* CatalogCacheComputeHashIndex
*
*/
static Index
CatalogCacheComputeHashIndex(CatCache *cache, ScanKey cur_skey)
@ -330,7 +331,6 @@ CatalogCacheComputeHashIndex(CatCache *cache, ScanKey cur_skey)
/*
* CatalogCacheComputeTupleHashIndex
*
*/
static Index
CatalogCacheComputeTupleHashIndex(CatCache *cache,
@ -396,12 +396,12 @@ CatalogCacheComputeTupleHashIndex(CatCache *cache,
/*
* CatCacheRemoveCTup
*
*/
static void
CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)
{
Assert(ct->refcount == 0);
Assert(ct->my_cache == cache);
/* delink from linked lists */
DLRemove(&ct->lrulist_elem);
@ -413,6 +413,7 @@ CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)
pfree(ct);
--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,
* if the cache has yet to open its relation, there will be no tuples so
* no problem.
*
*/
void
CatalogCacheIdInvalidate(int cacheId,
@ -433,17 +433,14 @@ CatalogCacheIdInvalidate(int cacheId,
/*
* sanity checks
*
*/
Assert(hashIndex < NCCBUCK);
Assert(ItemPointerIsValid(pointer));
CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: called");
/*
* 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,
*nextelt;
@ -451,11 +448,12 @@ CatalogCacheIdInvalidate(int cacheId,
if (cacheId != ccp->id)
continue;
Assert(hashIndex < ccp->cc_size);
/*
* 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);
@ -479,7 +477,7 @@ CatalogCacheIdInvalidate(int cacheId,
* public functions
*
* AtEOXact_CatCache
* ResetSystemCache
* ResetCatalogCaches
* InitCatCache
* SearchCatCache
* ReleaseCatCache
@ -497,68 +495,55 @@ CatalogCacheIdInvalidate(int cacheId,
* necessary in the abort case, since elog() may have interrupted routines.
* In the commit case, any nonzero counts indicate failure to call
* ReleaseSysCache, so we put out a notice for debugging purposes.
*
*/
void
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,
*nextelt;
CatCTup *ct = (CatCTup *) DLE_VAL(elt);
for (elt = DLGetHead(&cache->cc_lrulist); elt; elt = nextelt)
nextelt = DLGetSucc(elt);
if (ct->refcount != 0)
{
CatCTup *ct = (CatCTup *) DLE_VAL(elt);
nextelt = DLGetSucc(elt);
if (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);
if (isCommit)
elog(NOTICE, "Cache reference leak: cache %s (%d), tuple %u has count %d",
ct->my_cache->cc_relname, ct->my_cache->id,
ct->tuple.t_data->t_oid,
ct->refcount);
ct->refcount = 0;
}
/* 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
ResetSystemCache(void)
static void
ResetCatalogCache(CatCache *cache)
{
CatCache *cache;
int i;
CACHE1_elog(DEBUG, "ResetSystemCache called");
/* ----------------
* 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)
/* Remove each tuple in this cache, or at least mark it dead */
for (i = 0; i < cache->cc_size; i++)
{
Dlelem *elt,
*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);
@ -570,12 +555,28 @@ ResetSystemCache(void)
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
* 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
* tables --- although those'll never be dropped, they can get flushed from
* the relcache (VACUUM causes this, for example). In that case we need
* to flush all cache entries from that table. The brute-force method
* currently used takes care of that quite handily. (At one point we
* to flush all cache entries that came from that table. (At one point we
* 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
* 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,
* 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...)
*
*/
void
SystemCacheRelationFlushed(Oid relId)
CatalogCacheFlushRelation(Oid relId)
{
CatCache *cache;
/*
* XXX Ideally we'd search the caches and just zap entries that
* actually refer to or come from the indicated relation. For now, we
* take the brute-force approach: just flush the caches entirely.
*/
ResetSystemCache();
CACHE2_elog(DEBUG, "CatalogCacheFlushRelation called for %u", relId);
for (cache = CacheHdr->ch_caches; cache; cache = cache->cc_next)
{
int i;
/* 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
* relation. The relation will be opened and the rest of the cache
* structure initialized on the first access.
*
*/
#ifdef CACHEDEBUG
#define InitCatCache_DEBUG1 \
@ -628,10 +682,11 @@ do { \
#define InitCatCache_DEBUG1
#endif
CatCache *
CatCache *
InitCatCache(int id,
char *relname,
char *indname,
int reloidattr,
int nkeys,
int *key)
{
@ -642,63 +697,67 @@ InitCatCache(int id,
/*
* first switch to the cache context so our allocations do not vanish
* at the end of a transaction
*
*/
if (!CacheMemoryContext)
CreateCacheMemoryContext();
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
*
*/
cp = (CatCache *) palloc(sizeof(CatCache));
MemSet((char *) cp, 0, sizeof(CatCache));
cp = (CatCache *) palloc(sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist));
MemSet((char *) cp, 0, sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist));
/*
* initialize the cache buckets (each bucket is a list header) and the
* LRU tuple list
*
* initialize the cache buckets (each bucket is a list header)
*/
DLInitList(&cp->cc_lrulist);
for (i = 0; i < NCCBUCK; ++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;
for (i = 0; i < NCCBUCKETS; ++i)
DLInitList(&cp->cc_bucket[i]);
/*
* initialize the cache's relation information for the relation
* corresponding to this cache, and initialize some of the new cache's
* other internal fields. But don't open the relation yet.
*
*/
cp->id = id;
cp->cc_relname = relname;
cp->cc_indname = indname;
cp->cc_reloidattr = reloidattr;
cp->cc_tupdesc = (TupleDesc) NULL;
cp->id = id;
cp->cc_maxtup = MAXTUP;
cp->cc_size = NCCBUCK;
cp->cc_ntup = 0;
cp->cc_size = NCCBUCKETS;
cp->cc_nkeys = nkeys;
for (i = 0; i < nkeys; ++i)
cp->cc_key[i] = key[i];
/*
* all done. new cache is initialized. print some debugging
* information, if appropriate.
*
* new cache is initialized as far as we can go for now.
* print some debugging information, if appropriate.
*/
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...
*
*/
MemoryContextSwitchTo(oldcxt);
@ -766,7 +825,6 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey)
*
* This call searches a system cache for a tuple, opening the relation
* if necessary (the first access to a particular cache).
*
*/
HeapTuple
SearchCatCache(CatCache *cache,
@ -785,14 +843,12 @@ SearchCatCache(CatCache *cache,
/*
* one-time startup overhead
*
*/
if (cache->cc_tupdesc == NULL)
CatalogCacheInitializeCache(cache);
/*
* initialize the search key information
*
*/
memcpy(cur_skey, cache->cc_skey, sizeof(cur_skey));
cur_skey[0].sk_argument = v1;
@ -802,15 +858,13 @@ SearchCatCache(CatCache *cache,
/*
* find the hash bucket in which to look for the tuple
*
*/
hash = CatalogCacheComputeHashIndex(cache, cur_skey);
/*
* 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 = DLGetSucc(elt))
{
@ -824,7 +878,6 @@ SearchCatCache(CatCache *cache,
/*
* see if the cached tuple matches our key. (should we be worried
* about time ranges? -cim 10/2/90)
*
*/
HeapKeyTest(&ct->tuple,
cache->cc_tupdesc,
@ -841,7 +894,6 @@ SearchCatCache(CatCache *cache,
* subsequent searches. (The most frequently accessed elements in
* any hashbucket will tend to be near the front of the
* hashbucket's list.)
*
*/
ct->refcount++;
@ -869,19 +921,16 @@ SearchCatCache(CatCache *cache,
* will never be referenced again, and will eventually age out of the
* cache, so there's no functional problem. This case is rare enough
* that it's not worth expending extra cycles to detect.
*
*/
/*
* open the relation associated with the cache
*
*/
relation = heap_openr(cache->cc_relname, AccessShareLock);
/*
* 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.
*
*/
ct = NULL;
@ -958,13 +1007,11 @@ SearchCatCache(CatCache *cache,
/*
* close the relation
*
*/
heap_close(relation, AccessShareLock);
/*
* scan is complete. if tup was found, we can add it to the cache.
*
*/
if (ct == NULL)
return NULL;
@ -972,27 +1019,27 @@ SearchCatCache(CatCache *cache,
/*
* Finish initializing the CatCTup header, and add it to the linked
* lists.
*
*/
CACHE1_elog(DEBUG, "SearchCatCache: found tuple");
ct->ct_magic = CT_MAGIC;
ct->my_cache = cache;
DLInitElem(&ct->lrulist_elem, (void *) ct);
DLInitElem(&ct->cache_elem, (void *) ct);
ct->refcount = 1; /* count this first reference */
ct->dead = false;
DLAddHead(&cache->cc_lrulist, &ct->lrulist_elem);
DLAddHead(&cache->cc_cache[hash], &ct->cache_elem);
DLAddHead(&CacheHdr->ch_lrulist, &ct->lrulist_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.
*
*/
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 = DLGetPred(elt))
{
@ -1002,14 +1049,14 @@ SearchCatCache(CatCache *cache,
{
CACHE2_elog(DEBUG, "SearchCatCache(%s): Overflow, LRU removal",
cache->cc_relname);
CatCacheRemoveCTup(cache, oldct);
CatCacheRemoveCTup(oldct->my_cache, oldct);
break;
}
}
}
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",
cache->cc_relname, hash);
@ -1026,7 +1073,6 @@ SearchCatCache(CatCache *cache,
* 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
* to catch references to already-released catcache entries.
*
*/
void
ReleaseCatCache(HeapTuple tuple)
@ -1046,12 +1092,7 @@ ReleaseCatCache(HeapTuple tuple)
#endif
)
{
/* We can find the associated cache using the dllist pointers */
Dllist *lru = DLGetListHdr(&ct->lrulist_elem);
CatCache *cache = (CatCache *) (((char *) lru) -
offsetof(CatCache, cc_lrulist));
CatCacheRemoveCTup(cache, ct);
CatCacheRemoveCTup(ct->my_cache, ct);
}
}
@ -1061,7 +1102,7 @@ ReleaseCatCache(HeapTuple tuple)
* 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
* 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
* 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
* catcaches --- it will call this routine for any tuple that's in a
* system relation.
*
*/
void
PrepareToInvalidateCacheTuple(Relation relation,
@ -1090,14 +1130,15 @@ PrepareToInvalidateCacheTuple(Relation relation,
{
CatCache *ccp;
CACHE1_elog(DEBUG, "PrepareToInvalidateCacheTuple: called");
/*
* sanity checks
*
*/
Assert(RelationIsValid(relation));
Assert(HeapTupleIsValid(tuple));
Assert(PointerIsValid(function));
CACHE1_elog(DEBUG, "PrepareToInvalidateCacheTuple: called");
Assert(CacheHdr != NULL);
/* ----------------
* 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)
continue;

View File

@ -34,7 +34,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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
* 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
* all the cached relation descriptors (and closes their files too).
* 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
ResetSystemCaches(void)
InvalidateSystemCaches(void)
{
ResetSystemCache();
ResetCatalogCaches();
RelationCacheInvalidate();
}
@ -643,7 +647,7 @@ DiscardInvalid(void)
elog(DEBUG, "DiscardInvalid called");
#endif /* defined(INVALIDDEBUG) */
InvalidateSharedInvalid(CacheIdInvalidate, ResetSystemCaches);
InvalidateSharedInvalid(CacheIdInvalidate, InvalidateSystemCaches);
}
/*

View File

@ -8,7 +8,7 @@
*
*
* 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);
/* 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

View File

@ -8,7 +8,7 @@
*
*
* 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
* 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
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
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
{
char *name; /* name of the relation being cached */
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 key[4]; /* attribute numbers of key attrs */
};
@ -89,6 +94,7 @@ struct cachedesc
static struct cachedesc cacheinfo[] = {
{AggregateRelationName, /* AGGNAME */
AggregateNameTypeIndex,
0,
2,
{
Anum_pg_aggregate_aggname,
@ -98,6 +104,7 @@ static struct cachedesc cacheinfo[] = {
}},
{AccessMethodRelationName, /* AMNAME */
AmNameIndex,
0,
1,
{
Anum_pg_am_amname,
@ -107,6 +114,7 @@ static struct cachedesc cacheinfo[] = {
}},
{AccessMethodOperatorRelationName, /* AMOPOPID */
AccessMethodOpidIndex,
0,
3,
{
Anum_pg_amop_amopclaid,
@ -116,6 +124,7 @@ static struct cachedesc cacheinfo[] = {
}},
{AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
AccessMethodStrategyIndex,
0,
3,
{
Anum_pg_amop_amopid,
@ -125,6 +134,7 @@ static struct cachedesc cacheinfo[] = {
}},
{AttributeRelationName, /* ATTNAME */
AttributeRelidNameIndex,
Anum_pg_attribute_attrelid,
2,
{
Anum_pg_attribute_attrelid,
@ -134,6 +144,7 @@ static struct cachedesc cacheinfo[] = {
}},
{AttributeRelationName, /* ATTNUM */
AttributeRelidNumIndex,
Anum_pg_attribute_attrelid,
2,
{
Anum_pg_attribute_attrelid,
@ -143,6 +154,7 @@ static struct cachedesc cacheinfo[] = {
}},
{OperatorClassRelationName, /* CLADEFTYPE */
OpclassDeftypeIndex,
0,
1,
{
Anum_pg_opclass_opcdeftype,
@ -152,6 +164,7 @@ static struct cachedesc cacheinfo[] = {
}},
{OperatorClassRelationName, /* CLANAME */
OpclassNameIndex,
0,
1,
{
Anum_pg_opclass_opcname,
@ -161,6 +174,7 @@ static struct cachedesc cacheinfo[] = {
}},
{GroupRelationName, /* GRONAME */
GroupNameIndex,
0,
1,
{
Anum_pg_group_groname,
@ -170,6 +184,7 @@ static struct cachedesc cacheinfo[] = {
}},
{GroupRelationName, /* GROSYSID */
GroupSysidIndex,
0,
1,
{
Anum_pg_group_grosysid,
@ -179,6 +194,7 @@ static struct cachedesc cacheinfo[] = {
}},
{IndexRelationName, /* INDEXRELID */
IndexRelidIndex,
Anum_pg_index_indrelid,
1,
{
Anum_pg_index_indexrelid,
@ -188,6 +204,7 @@ static struct cachedesc cacheinfo[] = {
}},
{InheritsRelationName, /* INHRELID */
InheritsRelidSeqnoIndex,
Anum_pg_inherits_inhrelid,
2,
{
Anum_pg_inherits_inhrelid,
@ -197,6 +214,7 @@ static struct cachedesc cacheinfo[] = {
}},
{LanguageRelationName, /* LANGNAME */
LanguageNameIndex,
0,
1,
{
Anum_pg_language_lanname,
@ -206,6 +224,7 @@ static struct cachedesc cacheinfo[] = {
}},
{LanguageRelationName, /* LANGOID */
LanguageOidIndex,
0,
1,
{
ObjectIdAttributeNumber,
@ -215,6 +234,7 @@ static struct cachedesc cacheinfo[] = {
}},
{OperatorRelationName, /* OPERNAME */
OperatorNameIndex,
0,
4,
{
Anum_pg_operator_oprname,
@ -224,6 +244,7 @@ static struct cachedesc cacheinfo[] = {
}},
{OperatorRelationName, /* OPEROID */
OperatorOidIndex,
0,
1,
{
ObjectIdAttributeNumber,
@ -233,6 +254,7 @@ static struct cachedesc cacheinfo[] = {
}},
{ProcedureRelationName, /* PROCNAME */
ProcedureNameIndex,
0,
3,
{
Anum_pg_proc_proname,
@ -242,6 +264,7 @@ static struct cachedesc cacheinfo[] = {
}},
{ProcedureRelationName, /* PROCOID */
ProcedureOidIndex,
0,
1,
{
ObjectIdAttributeNumber,
@ -251,6 +274,7 @@ static struct cachedesc cacheinfo[] = {
}},
{RelationRelationName, /* RELNAME */
ClassNameIndex,
ObjectIdAttributeNumber,
1,
{
Anum_pg_class_relname,
@ -260,6 +284,7 @@ static struct cachedesc cacheinfo[] = {
}},
{RelationRelationName, /* RELOID */
ClassOidIndex,
ObjectIdAttributeNumber,
1,
{
ObjectIdAttributeNumber,
@ -269,6 +294,7 @@ static struct cachedesc cacheinfo[] = {
}},
{RewriteRelationName, /* RULENAME */
RewriteRulenameIndex,
Anum_pg_rewrite_ev_class,
1,
{
Anum_pg_rewrite_rulename,
@ -278,6 +304,7 @@ static struct cachedesc cacheinfo[] = {
}},
{ShadowRelationName, /* SHADOWNAME */
ShadowNameIndex,
0,
1,
{
Anum_pg_shadow_usename,
@ -287,6 +314,7 @@ static struct cachedesc cacheinfo[] = {
}},
{ShadowRelationName, /* SHADOWSYSID */
ShadowSysidIndex,
0,
1,
{
Anum_pg_shadow_usesysid,
@ -296,6 +324,7 @@ static struct cachedesc cacheinfo[] = {
}},
{StatisticRelationName, /* STATRELATT */
StatisticRelidAttnumIndex,
Anum_pg_statistic_starelid,
2,
{
Anum_pg_statistic_starelid,
@ -305,6 +334,7 @@ static struct cachedesc cacheinfo[] = {
}},
{TypeRelationName, /* TYPENAME */
TypeNameIndex,
Anum_pg_type_typrelid,
1,
{
Anum_pg_type_typname,
@ -314,6 +344,7 @@ static struct cachedesc cacheinfo[] = {
}},
{TypeRelationName, /* TYPEOID */
TypeOidIndex,
Anum_pg_type_typrelid,
1,
{
ObjectIdAttributeNumber,
@ -323,8 +354,7 @@ static struct cachedesc cacheinfo[] = {
}}
};
static CatCache *SysCache[
lengthof(cacheinfo)];
static CatCache *SysCache[lengthof(cacheinfo)];
static int SysCacheSize = lengthof(cacheinfo);
static bool CacheInitialized = false;
@ -358,6 +388,7 @@ InitCatalogCache(void)
SysCache[cacheId] = InitCatCache(cacheId,
cacheinfo[cacheId].name,
cacheinfo[cacheId].indname,
cacheinfo[cacheId].reloidattr,
cacheinfo[cacheId].nkeys,
cacheinfo[cacheId].key);
if (!PointerIsValid(SysCache[cacheId]))

View File

@ -13,32 +13,49 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* 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
#define CATCACHE_H
/* #define CACHEDEBUG *//* turns DEBUG elogs on */
#include "access/htup.h"
#include "lib/dllist.h"
/*
* struct catctup: individual tuple in the 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
{
int ct_magic; /* for Assert checks */
#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
* elements in that cache in LRU order, and the other lists just the
* elements in one hashbucket, also in LRU order.
* elements in all the caches in LRU order, and the other lists just
* the elements in one hashbucket of one cache, also in LRU order.
*
* A tuple marked "dead" must not be returned by subsequent searches.
* However, it won't be physically deleted from the cache until its
@ -52,30 +69,14 @@ typedef struct catctup
} CatCTup;
/* voodoo constants */
#define NCCBUCK 500 /* CatCache buckets */
#define MAXTUP 500 /* Maximum # of tuples stored per cache */
typedef struct catcache
typedef struct catcacheheader
{
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 */
TupleDesc cc_tupdesc; /* tuple descriptor (copied from reldesc) */
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;
CatCache *ch_caches; /* head of list of CatCache structs */
int ch_ntup; /* # of tuples in all caches */
int ch_maxtup; /* max # of tuples allowed (LRU) */
Dllist ch_lrulist; /* overall LRU list, most recent first */
} CatCacheHeader;
#define InvalidCatalogCacheId (-1)
/* this extern duplicates utils/memutils.h... */
extern MemoryContext CacheMemoryContext;
@ -84,15 +85,16 @@ extern void CreateCacheMemoryContext(void);
extern void AtEOXact_CatCache(bool isCommit);
extern CatCache *InitCatCache(int id, char *relname, char *indname,
int nkeys, int *key);
int reloidattr,
int nkeys, int *key);
extern HeapTuple SearchCatCache(CatCache *cache,
Datum v1, Datum v2,
Datum v3, Datum v4);
extern void ReleaseCatCache(HeapTuple tuple);
extern void ResetSystemCache(void);
extern void SystemCacheRelationFlushed(Oid relId);
extern void ResetCatalogCaches(void);
extern void CatalogCacheFlushRelation(Oid relId);
extern void CatalogCacheIdInvalidate(int cacheId, Index hashIndex,
ItemPointer pointer);
extern void PrepareToInvalidateCacheTuple(Relation relation,