Skip to content

Commit 74e7b58

Browse files
committed
Fix for failure to clean SysCache entry when a relation is deleted
in the same transaction that created it.
1 parent 0bddf3d commit 74e7b58

File tree

4 files changed

+61
-57
lines changed

4 files changed

+61
-57
lines changed

src/backend/catalog/heap.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.86 1999/05/26 22:57:39 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.87 1999/06/04 02:19:46 tgl Exp $
1111
*
1212
*
1313
* INTERFACE ROUTINES
@@ -812,13 +812,7 @@ heap_create_with_catalog(char *relname,
812812

813813
if (relid != InvalidOid)
814814
{
815-
816-
/*
817-
* This is heavy-handed, but appears necessary bjm 1999/02/01
818-
* SystemCacheRelationFlushed(relid) is not enough either.
819-
*/
820815
RelationForgetRelation(relid);
821-
ResetSystemCache();
822816
}
823817
}
824818

src/backend/catalog/index.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.76 1999/05/26 22:57:39 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.77 1999/06/04 02:19:47 tgl Exp $
1111
*
1212
*
1313
* INTERFACE ROUTINES
@@ -991,13 +991,7 @@ index_create(char *heapRelationName,
991991

992992
if (relid != InvalidOid)
993993
{
994-
995-
/*
996-
* This is heavy-handed, but appears necessary bjm 1999/02/01
997-
* SystemCacheRelationFlushed(relid) is not enough either.
998-
*/
999994
RelationForgetRelation(relid);
1000-
ResetSystemCache();
1001995
}
1002996
}
1003997

src/backend/utils/cache/catcache.c

Lines changed: 51 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@
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()
559556
MemoryContext oldcxt;
560557
struct catcache *cache;
561558

562-
/* ----------------
563-
* sanity checks
564-
* ----------------
565-
*/
566559
CACHE1_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
{
603591
nextelt = DLGetSucc(elt);
604592
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)");
607596
}
608597
}
609598
cache->cc_ntup = 0; /* in case of WARN error above */
599+
cache->busy = false; /* to recover from recursive-use error */
610600
}
611601

612602
CACHE1_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
*/
630628
void
631629
SystemCacheRelationFlushed(Oid relId)
632630
{
633631
struct 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+
*/
635645
for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next)
636646
{
637647
if (cache->relationId == relId)
@@ -746,6 +756,7 @@ InitSysCache(char *relname,
746756
cp->cc_indname = indname;
747757
cp->cc_tupdesc = (TupleDesc) NULL;
748758
cp->id = id;
759+
cp->busy = false;
749760
cp->cc_maxtup = MAXTUP;
750761
cp->cc_size = NCCBUCK;
751762
cp->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,
925940
RelationGetRelationName(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

933947
if (!CacheCxt)
934948
CacheCxt = CreateGlobalMemory("Cache");
@@ -1011,7 +1025,7 @@ SearchSysCache(struct catcache * cache,
10111025
MemoryContextSwitchTo((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,
10461060
DLAddHead(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
*/
10521067
if (++cache->cc_ntup > cache->cc_maxtup)
@@ -1056,13 +1071,12 @@ SearchSysCache(struct catcache * cache,
10561071
elt = DLGetTail(cache->cc_lrulist);
10571072
ct = (CatCTup *) DLE_VAL(elt);
10581073

1059-
if (ct != nct)
1074+
if (ct != nct) /* shouldn't be possible, but be safe... */
10601075
{
10611076
CACHE2_elog(DEBUG, "SearchSysCache(%s): Overflow, LRU removal",
10621077
RelationGetRelationName(relation));
10631078

10641079
CatCacheRemoveCTup(cache, elt);
1065-
10661080
}
10671081
}
10681082

src/include/utils/catcache.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
* Copyright (c) 1994, Regents of the University of California
88
*
9-
* $Id: catcache.h,v 1.14 1999/02/13 23:22:16 momjian Exp $
9+
* $Id: catcache.h,v 1.15 1999/06/04 02:19:44 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -28,9 +28,11 @@
2828
typedef struct catctup
2929
{
3030
HeapTuple ct_tup; /* A pointer to a tuple */
31-
Dlelem *ct_node; /* points to LRU list is the CatCTup is in
32-
* the cache, else, points to the cache if
33-
* the CatCTup is in LRU list */
31+
/* Each tuple in the cache has two catctup items, one in the LRU list
32+
* and one in the hashbucket list for its hash value. ct_node in each
33+
* one points to the other one.
34+
*/
35+
Dlelem *ct_node; /* the other catctup for this tuple */
3436
} CatCTup;
3537

3638
/* voodoo constants */
@@ -46,6 +48,7 @@ typedef struct catcache
4648
HeapTuple (*cc_iscanfunc) (); /* index scanfunction */
4749
TupleDesc cc_tupdesc; /* tuple descriptor from reldesc */
4850
int id; /* XXX could be improved -hirohama */
51+
bool busy; /* for detecting recursive lookups */
4952
short cc_ntup; /* # of tuples in this cache */
5053
short cc_maxtup; /* max # of tuples allowed (LRU) */
5154
short cc_nkeys;
@@ -55,12 +58,11 @@ typedef struct catcache
5558
ScanKeyData cc_skey[4];
5659
struct catcache *cc_next;
5760
Dllist *cc_lrulist; /* LRU list, most recent first */
58-
Dllist *cc_cache[NCCBUCK + 1];
61+
Dllist *cc_cache[NCCBUCK + 1]; /* hash buckets */
5962
} CatCache;
6063

6164
#define InvalidCatalogCacheId (-1)
6265

63-
extern struct catcache *Caches;
6466
extern GlobalMemory CacheCxt;
6567

6668
extern void CatalogCacheIdInvalidate(int cacheId, Index hashIndex,

0 commit comments

Comments
 (0)