77 *
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.42 1999/05/31 23:48:04 tgl Exp $
11- *
12- * Notes:
13- *XXX This needs to use exception.h to handle recovery when
14- *an abort occurs during DisableCache.
10+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.43 1999/06/04 02:19:45 tgl Exp $
1511 *
1612 *-------------------------------------------------------------------------
1713 */
@@ -66,10 +62,11 @@ static long comphash(long l, char *v);
6662#define CACHE6_elog (a ,b ,c ,d ,e ,f ,g )
6763#endif
6864
69- CatCache * Caches = NULL ;
70- GlobalMemory CacheCxt ;
65+ static CatCache * Caches = NULL ;/* head of list of caches */
66+
67+ GlobalMemory CacheCxt ;/* context in which caches are allocated */
68+ /* CacheCxt is global because relcache uses it too. */
7169
72- static int DisableCache ;
7370
7471/* ----------------
7572 *EQPROC is used in CatalogCacheInitializeCache
@@ -559,16 +556,7 @@ ResetSystemCache()
559556MemoryContext oldcxt ;
560557struct catcache * cache ;
561558
562- /* ----------------
563- *sanity checks
564- * ----------------
565- */
566559CACHE1_elog (DEBUG ,"ResetSystemCache called" );
567- if (DisableCache )
568- {
569- elog (ERROR ,"ResetSystemCache: Called while cache disabled" );
570- return ;
571- }
572560
573561/* ----------------
574562 *first switch to the cache context so our allocations
@@ -602,11 +590,13 @@ ResetSystemCache()
602590{
603591nextelt = DLGetSucc (elt );
604592CatCacheRemoveCTup (cache ,elt );
605- if (cache -> cc_ntup == -1 )
606- elog (ERROR ,"ResetSystemCache: cc_ntup<0 (software error)" );
593+ if (cache -> cc_ntup < 0 )
594+ elog (NOTICE ,
595+ "ResetSystemCache: cc_ntup<0 (software error)" );
607596}
608597}
609598cache -> cc_ntup = 0 ;/* in case of WARN error above */
599+ cache -> busy = false;/* to recover from recursive-use error */
610600}
611601
612602CACHE1_elog (DEBUG ,"end of ResetSystemCache call" );
@@ -621,17 +611,37 @@ ResetSystemCache()
621611/* --------------------------------
622612 *SystemCacheRelationFlushed
623613 *
624- *RelationFlushRelation() frees some information referenced in the
625- *cache structures. So we get informed when this is done and arrange
626- *for the next SearchSysCache() call that this information is setup
627- *again.
614+ *This is called by RelationFlushRelation() to clear out cached information
615+ *about a relation being dropped. (This could be a DROP TABLE command,
616+ *or a temp table being dropped at end of transaction, or a table created
617+ *during the current transaction that is being dropped because of abort.)
618+ *Remove all cache entries relevant to the specified relation OID.
619+ *
620+ *A special case occurs when relId is itself one of the cacheable system
621+ *tables --- although those'll never be dropped, they can get flushed from
622+ *the relcache (VACUUM causes this, for example). In that case we need to
623+ *force the next SearchSysCache() call to reinitialize the cache itself,
624+ *because we have info (such as cc_tupdesc) that is pointing at the about-
625+ *to-be-deleted relcache entry.
628626 * --------------------------------
629627 */
630628void
631629SystemCacheRelationFlushed (Oid relId )
632630{
633631struct catcache * cache ;
634632
633+ /*
634+ * XXX Ideally we'd search the caches and just zap entries that actually
635+ * refer to the indicated relation. For now, we take the brute-force
636+ * approach: just flush the caches entirely.
637+ */
638+ ResetSystemCache ();
639+
640+ /*
641+ * If relcache is dropping a system relation's cache entry, mark the
642+ * associated cache structures invalid, so we can rebuild them from
643+ * scratch (not just repopulate them) next time they are used.
644+ */
635645for (cache = Caches ;PointerIsValid (cache );cache = cache -> cc_next )
636646{
637647if (cache -> relationId == relId )
@@ -746,6 +756,7 @@ InitSysCache(char *relname,
746756cp -> cc_indname = indname ;
747757cp -> cc_tupdesc = (TupleDesc )NULL ;
748758cp -> id = id ;
759+ cp -> busy = false;
749760cp -> cc_maxtup = MAXTUP ;
750761cp -> cc_size = NCCBUCK ;
751762cp -> cc_nkeys = nkeys ;
@@ -902,19 +913,23 @@ SearchSysCache(struct catcache * cache,
902913/* ----------------
903914 *Tuple was not found in cache, so we have to try and
904915 *retrieve it directly from the relation. If it's found,
905- *we add it to the cache. We must avoid recursion here,
906- *so we disable cache operations. If operations are
907- *currently disabled and we couldn't find the requested item
908- *in the cache, then this may be a recursive request, and we
909- *abort with an error.
916+ *we add it to the cache.
917+ *
918+ *To guard against possible infinite recursion, we mark this cache
919+ *"busy" while trying to load a new entry for it. It is OK to
920+ *recursively invoke SearchSysCache for a different cache, but
921+ *a recursive call for the same cache will error out. (We could
922+ *store the specific key(s) being looked for, and consider only
923+ *a recursive request for the same key to be an error, but this
924+ *simple scheme is sufficient for now.)
910925 * ----------------
911926 */
912927
913- if (DisableCache )
928+ if (cache -> busy )
914929{
915- elog (ERROR ,"SearchSysCache: Called while cache disabled" );
916- return (HeapTuple )NULL ;
930+ elog (ERROR ,"SearchSysCache: recursive use of cache %d" ,cache -> id );
917931}
932+ cache -> busy = true;
918933
919934/* ----------------
920935 *open the relation associated with the cache
@@ -925,10 +940,9 @@ SearchSysCache(struct catcache * cache,
925940RelationGetRelationName (relation ));
926941
927942/* ----------------
928- *DisableCache and then switch to the cache memory context.
943+ *Switch to the cache memory context.
929944 * ----------------
930945 */
931- DisableCache = 1 ;
932946
933947if (!CacheCxt )
934948CacheCxt = CreateGlobalMemory ("Cache" );
@@ -1011,7 +1025,7 @@ SearchSysCache(struct catcache * cache,
10111025MemoryContextSwitchTo ((MemoryContext )CacheCxt );
10121026}
10131027
1014- DisableCache = 0 ;
1028+ cache -> busy = false ;
10151029
10161030/* ----------------
10171031 *scan is complete. if tup is valid, we copy it and add the copy to
@@ -1046,7 +1060,8 @@ SearchSysCache(struct catcache * cache,
10461060DLAddHead (cache -> cc_cache [hash ],elt );
10471061
10481062/* ----------------
1049- *deal with hash bucket overflow
1063+ *If we've exceeded the desired size of this cache,
1064+ *throw away the least recently used entry.
10501065 * ----------------
10511066 */
10521067if (++ cache -> cc_ntup > cache -> cc_maxtup )
@@ -1056,13 +1071,12 @@ SearchSysCache(struct catcache * cache,
10561071elt = DLGetTail (cache -> cc_lrulist );
10571072ct = (CatCTup * )DLE_VAL (elt );
10581073
1059- if (ct != nct )
1074+ if (ct != nct )/* shouldn't be possible, but be safe... */
10601075{
10611076CACHE2_elog (DEBUG ,"SearchSysCache(%s): Overflow, LRU removal" ,
10621077RelationGetRelationName (relation ));
10631078
10641079CatCacheRemoveCTup (cache ,elt );
1065-
10661080}
10671081}
10681082