7
7
*
8
8
*
9
9
* 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 $
15
11
*
16
12
*-------------------------------------------------------------------------
17
13
*/
@@ -66,10 +62,11 @@ static long comphash(long l, char *v);
66
62
#define CACHE6_elog (a ,b ,c ,d ,e ,f ,g )
67
63
#endif
68
64
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. */
71
69
72
- static int DisableCache ;
73
70
74
71
/* ----------------
75
72
* EQPROC is used in CatalogCacheInitializeCache
@@ -559,16 +556,7 @@ ResetSystemCache()
559
556
MemoryContext oldcxt ;
560
557
struct catcache * cache ;
561
558
562
- /* ----------------
563
- * sanity checks
564
- * ----------------
565
- */
566
559
CACHE1_elog (DEBUG , "ResetSystemCache called" );
567
- if (DisableCache )
568
- {
569
- elog (ERROR , "ResetSystemCache: Called while cache disabled" );
570
- return ;
571
- }
572
560
573
561
/* ----------------
574
562
* first switch to the cache context so our allocations
@@ -602,11 +590,13 @@ ResetSystemCache()
602
590
{
603
591
nextelt = DLGetSucc (elt );
604
592
CatCacheRemoveCTup (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)" );
607
596
}
608
597
}
609
598
cache -> cc_ntup = 0 ; /* in case of WARN error above */
599
+ cache -> busy = false; /* to recover from recursive-use error */
610
600
}
611
601
612
602
CACHE1_elog (DEBUG , "end of ResetSystemCache call" );
@@ -621,17 +611,37 @@ ResetSystemCache()
621
611
/* --------------------------------
622
612
* SystemCacheRelationFlushed
623
613
*
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.
628
626
* --------------------------------
629
627
*/
630
628
void
631
629
SystemCacheRelationFlushed (Oid relId )
632
630
{
633
631
struct catcache * cache ;
634
632
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
+ */
635
645
for (cache = Caches ; PointerIsValid (cache ); cache = cache -> cc_next )
636
646
{
637
647
if (cache -> relationId == relId )
@@ -746,6 +756,7 @@ InitSysCache(char *relname,
746
756
cp -> cc_indname = indname ;
747
757
cp -> cc_tupdesc = (TupleDesc ) NULL ;
748
758
cp -> id = id ;
759
+ cp -> busy = false;
749
760
cp -> cc_maxtup = MAXTUP ;
750
761
cp -> cc_size = NCCBUCK ;
751
762
cp -> cc_nkeys = nkeys ;
@@ -902,19 +913,23 @@ SearchSysCache(struct catcache * cache,
902
913
/* ----------------
903
914
* Tuple was not found in cache, so we have to try and
904
915
* 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.)
910
925
* ----------------
911
926
*/
912
927
913
- if (DisableCache )
928
+ if (cache -> busy )
914
929
{
915
- elog (ERROR , "SearchSysCache: Called while cache disabled" );
916
- return (HeapTuple ) NULL ;
930
+ elog (ERROR , "SearchSysCache: recursive use of cache %d" , cache -> id );
917
931
}
932
+ cache -> busy = true;
918
933
919
934
/* ----------------
920
935
* open the relation associated with the cache
@@ -925,10 +940,9 @@ SearchSysCache(struct catcache * cache,
925
940
RelationGetRelationName (relation ));
926
941
927
942
/* ----------------
928
- * DisableCache and then switch to the cache memory context.
943
+ * Switch to the cache memory context.
929
944
* ----------------
930
945
*/
931
- DisableCache = 1 ;
932
946
933
947
if (!CacheCxt )
934
948
CacheCxt = CreateGlobalMemory ("Cache" );
@@ -1011,7 +1025,7 @@ SearchSysCache(struct catcache * cache,
1011
1025
MemoryContextSwitchTo ((MemoryContext ) CacheCxt );
1012
1026
}
1013
1027
1014
- DisableCache = 0 ;
1028
+ cache -> busy = false ;
1015
1029
1016
1030
/* ----------------
1017
1031
* scan is complete. if tup is valid, we copy it and add the copy to
@@ -1046,7 +1060,8 @@ SearchSysCache(struct catcache * cache,
1046
1060
DLAddHead (cache -> cc_cache [hash ], elt );
1047
1061
1048
1062
/* ----------------
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.
1050
1065
* ----------------
1051
1066
*/
1052
1067
if (++ cache -> cc_ntup > cache -> cc_maxtup )
@@ -1056,13 +1071,12 @@ SearchSysCache(struct catcache * cache,
1056
1071
elt = DLGetTail (cache -> cc_lrulist );
1057
1072
ct = (CatCTup * ) DLE_VAL (elt );
1058
1073
1059
- if (ct != nct )
1074
+ if (ct != nct ) /* shouldn't be possible, but be safe... */
1060
1075
{
1061
1076
CACHE2_elog (DEBUG , "SearchSysCache(%s): Overflow, LRU removal" ,
1062
1077
RelationGetRelationName (relation ));
1063
1078
1064
1079
CatCacheRemoveCTup (cache , elt );
1065
-
1066
1080
}
1067
1081
}
1068
1082
0 commit comments