diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index cd54ff766570ef0541caf5b55791a7a9a8ef76d7..4c1d908611182306fe3f601a0c845e2e0dc23ad0 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -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) - { - CatCTup *ct = (CatCTup *) DLE_VAL(elt); + nextelt = DLGetSucc(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 (ct->refcount != 0) + { + 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; - - CACHE1_elog(DEBUG, "ResetSystemCache called"); + int 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) + /* 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"); +/* + * 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"); } /* - * SystemCacheRelationFlushed + * 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,7 +697,6 @@ InitCatCache(int id, /* * first switch to the cache context so our allocations do not vanish * at the end of a transaction - * */ if (!CacheMemoryContext) CreateCacheMemoryContext(); @@ -650,55 +704,60 @@ InitCatCache(int id, oldcxt = MemoryContextSwitchTo(CacheMemoryContext); /* - * allocate a new cache structure - * + * if first time through, initialize the cache group header, + * including global LRU list header */ - cp = (CatCache *) palloc(sizeof(CatCache)); - MemSet((char *) cp, 0, sizeof(CatCache)); + if (CacheHdr == NULL) + { + CacheHdr = (CatCacheHeader *) palloc(sizeof(CatCacheHeader)); + CacheHdr->ch_caches = NULL; + CacheHdr->ch_ntup = 0; + CacheHdr->ch_maxtup = MAXCCTUPLES; + DLInitList(&CacheHdr->ch_lrulist); + } /* - * initialize the cache buckets (each bucket is a list header) and the - * LRU tuple list - * + * allocate a new cache structure */ - DLInitList(&cp->cc_lrulist); - for (i = 0; i < NCCBUCK; ++i) - DLInitList(&cp->cc_cache[i]); + cp = (CatCache *) palloc(sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist)); + MemSet((char *) cp, 0, sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist)); /* - * 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. - * + * initialize the cache buckets (each bucket is a list header) */ - 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; diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c index b15eac025eadde16cafe1489e4fdd0ec13ab1234..91884a4b9c129dcb166fbdb8fd7de9b0d1fde87f 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -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); } /* diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 4c8c3c4398cf218518178c1b3b732d98902829ad..d44c3dc2340e3eb9d5c67fb39f96a576392cf697 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -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 diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 222650fcbea5b45098293202aaa6ff6c91cdd7f4..0e64aacf61ef463795b733b66aae7a97c828c140 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -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])) diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h index a2d99458a9d548f652d021d7b6cf574e94f0e854..a2d3064a8b9b6667a053c7056c8a498746a830c4 100644 --- a/src/include/utils/catcache.h +++ b/src/include/utils/catcache.h @@ -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,