summaryrefslogtreecommitdiff
path: root/src/backend/utils/cache/catcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/cache/catcache.c')
-rw-r--r--src/backend/utils/cache/catcache.c232
1 files changed, 39 insertions, 193 deletions
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index 8bfa3610bdb..c382d749746 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.113 2004/07/01 00:51:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.114 2004/07/17 03:29:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -31,6 +31,7 @@
#include "utils/fmgroids.h"
#include "utils/catcache.h"
#include "utils/relcache.h"
+#include "utils/resowner.h"
#include "utils/syscache.h"
@@ -360,8 +361,6 @@ CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)
/* free associated tuple data */
if (ct->tuple.t_data != NULL)
pfree(ct->tuple.t_data);
- if (ct->prev_refcount != NULL)
- pfree(ct->prev_refcount);
pfree(ct);
--cache->cc_ntup;
@@ -396,8 +395,6 @@ CatCacheRemoveCList(CatCache *cache, CatCList *cl)
/* free associated tuple data */
if (cl->tuple.t_data != NULL)
pfree(cl->tuple.t_data);
- if (cl->prev_refcount != NULL)
- pfree(cl->prev_refcount);
pfree(cl);
}
@@ -531,7 +528,7 @@ CreateCacheMemoryContext(void)
/*
* AtEOXact_CatCache
*
- * Clean up catcaches at end of transaction (either commit or abort)
+ * Clean up catcaches at end of main transaction (either commit or abort)
*
* We scan the caches to reset refcounts to zero. This is of course
* necessary in the abort case, since elog() may have interrupted routines.
@@ -564,13 +561,6 @@ AtEOXact_CatCache(bool isCommit)
cl->refcount = 0;
}
- /*
- * Reset the refcount stack. Drop the item count to zero,
- * but don't deallocate the stack itself, so it can be used by
- * future subtransactions.
- */
- cl->numpushes = 0;
-
/* Clean up any now-deletable dead entries */
if (cl->dead)
CatCacheRemoveCList(ccp, cl);
@@ -596,13 +586,6 @@ AtEOXact_CatCache(bool isCommit)
ct->refcount = 0;
}
- /*
- * Reset the refcount stack. Drop the item count to zero,
- * but don't deallocate the stack itself, so it can be used by
- * future subtransactions.
- */
- ct->numpushes = 0;
-
/* Clean up any now-deletable dead entries */
if (ct->dead)
CatCacheRemoveCTup(ct->my_cache, ct);
@@ -610,161 +593,6 @@ AtEOXact_CatCache(bool isCommit)
}
/*
- * AtSubStart_CatCache
- *
- * Saves reference counts of each entry at subtransaction start so they
- * can be restored if the subtransaction later aborts.
- */
-void
-AtSubStart_CatCache(void)
-{
- CatCache *ccp;
- Dlelem *elt,
- *nextelt;
- MemoryContext old_cxt;
-
-
- old_cxt = MemoryContextSwitchTo(CacheMemoryContext);
-
- /*
- * Prepare CLists
- */
- for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next)
- {
- for (elt = DLGetHead(&ccp->cc_lists); elt; elt = nextelt)
- {
- CatCList *cl = (CatCList *) DLE_VAL(elt);
-
- nextelt = DLGetSucc(elt);
-
- if (cl->numpushes == cl->numalloc)
- {
- if (cl->numalloc == 0)
- {
- cl->numalloc = 8;
- cl->prev_refcount = palloc(sizeof(int) * cl->numalloc);
- }
- else
- {
- cl->numalloc *= 2;
- cl->prev_refcount = repalloc(cl->prev_refcount, cl->numalloc * sizeof(int));
- }
- }
-
- cl->prev_refcount[cl->numpushes++] = cl->refcount;
- }
- }
-
- /*
- * Prepare CTuples
- */
- for (elt = DLGetHead(&CacheHdr->ch_lrulist); elt; elt = nextelt)
- {
- CatCTup *ct = (CatCTup *) DLE_VAL(elt);
-
- nextelt = DLGetSucc(elt);
-
- if (ct->numpushes == ct->numalloc)
- {
- if (ct->numalloc == 0)
- {
- ct->numalloc = 8;
- ct->prev_refcount = palloc(sizeof(int) * ct->numalloc);
- }
- else
- {
- ct->numalloc *= 2;
- ct->prev_refcount = repalloc(ct->prev_refcount, sizeof(int) * ct->numalloc);
- }
- }
-
- ct->prev_refcount[ct->numpushes++] = ct->refcount;
- }
-
- MemoryContextSwitchTo(old_cxt);
-}
-
-void
-AtEOSubXact_CatCache(bool isCommit)
-{
- CatCache *ccp;
- Dlelem *elt,
- *nextelt;
-
- /*
- * Restore CLists
- */
- for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next)
- {
- for (elt = DLGetHead(&ccp->cc_lists); elt; elt = nextelt)
- {
- CatCList *cl = (CatCList *) DLE_VAL(elt);
-
- nextelt = DLGetSucc(elt);
-
- /*
- * During commit, check whether the count is what
- * we expect.
- */
- if (isCommit)
- {
- int expected_refcount;
- if (cl->numpushes > 0)
- expected_refcount = cl->prev_refcount[cl->numpushes - 1];
- else
- expected_refcount = 0;
-
- if (cl->refcount != expected_refcount)
- elog(WARNING, "catcache reference leak");
- }
-
- /*
- * During abort we have to restore the original count;
- * during commit, we have to restore in case of a leak,
- * and it won't harm if this is the expected count.
- */
- if (cl->numpushes > 0)
- cl->refcount = cl->prev_refcount[--cl->numpushes];
- else
- cl->refcount = 0;
- }
- }
-
- /*
- * Prepare CTuples
- */
- for (elt = DLGetHead(&CacheHdr->ch_lrulist); elt; elt = nextelt)
- {
- CatCTup *ct = (CatCTup *) DLE_VAL(elt);
-
- nextelt = DLGetSucc(elt);
-
- if (isCommit)
- {
- int expected_refcount;
-
- if (ct->numpushes > 0)
- expected_refcount = ct->prev_refcount[ct->numpushes - 1];
- else
- expected_refcount = 0;
-
- if (ct->refcount != expected_refcount)
- elog(WARNING, "catcache reference leak");
- }
-
- /*
- * During abort we have to restore the original count;
- * during commit, we have to restore in case of a leak,
- * and it won't harm if this is the expected count.
- */
- if (ct->numpushes > 0)
- ct->refcount = ct->prev_refcount[--ct->numpushes];
- else
- ct->refcount = 0;
- }
-}
-
-/*
* ResetCatalogCache
*
* Reset one catalog cache to empty.
@@ -1334,7 +1162,9 @@ SearchCatCache(CatCache *cache,
*/
if (!ct->negative)
{
+ ResourceOwnerEnlargeCatCacheRefs(CurrentResourceOwner);
ct->refcount++;
+ ResourceOwnerRememberCatCacheRef(CurrentResourceOwner, &ct->tuple);
CACHE3_elog(DEBUG2, "SearchCatCache(%s): found in bucket %d",
cache->cc_relname, hashIndex);
@@ -1389,6 +1219,10 @@ SearchCatCache(CatCache *cache,
ct = CatalogCacheCreateEntry(cache, ntp,
hashValue, hashIndex,
false);
+ /* immediately set the refcount to 1 */
+ ResourceOwnerEnlargeCatCacheRefs(CurrentResourceOwner);
+ ct->refcount++;
+ ResourceOwnerRememberCatCacheRef(CurrentResourceOwner, &ct->tuple);
break; /* assume only one match */
}
@@ -1415,10 +1249,9 @@ SearchCatCache(CatCache *cache,
cache->cc_relname, hashIndex);
/*
- * We are not returning the new entry to the caller, so reset its
- * refcount.
+ * We are not returning the negative entry to the caller, so leave
+ * its refcount zero.
*/
- ct->refcount = 0; /* negative entries never have refs */
return NULL;
}
@@ -1457,6 +1290,7 @@ ReleaseCatCache(HeapTuple tuple)
Assert(ct->refcount > 0);
ct->refcount--;
+ ResourceOwnerForgetCatCacheRef(CurrentResourceOwner, &ct->tuple);
if (ct->refcount == 0
#ifndef CATCACHE_FORCE_RELEASE
@@ -1564,7 +1398,10 @@ SearchCatCacheList(CatCache *cache,
* do not move the members to the fronts of their hashbucket
* lists, however, since there's no point in that unless they are
* searched for individually.) Also bump the members' refcounts.
+ * (member refcounts are NOT registered separately with the
+ * resource owner.)
*/
+ ResourceOwnerEnlargeCatCacheListRefs(CurrentResourceOwner);
for (i = 0; i < cl->n_members; i++)
{
cl->members[i]->refcount++;
@@ -1574,6 +1411,7 @@ SearchCatCacheList(CatCache *cache,
/* Bump the list's refcount and return it */
cl->refcount++;
+ ResourceOwnerRememberCatCacheListRef(CurrentResourceOwner, cl);
CACHE2_elog(DEBUG2, "SearchCatCacheList(%s): found list",
cache->cc_relname);
@@ -1639,9 +1477,7 @@ SearchCatCacheList(CatCache *cache,
if (ct->c_list)
continue;
- /* Found a match, so bump its refcount and move to front */
- ct->refcount++;
-
+ /* Found a match, so move it to front */
DLMoveToFront(&ct->lrulist_elem);
break;
@@ -1655,6 +1491,16 @@ SearchCatCacheList(CatCache *cache,
false);
}
+ /*
+ * We have to bump the member refcounts immediately to ensure they
+ * won't get dropped from the cache while loading other members.
+ * If we get an error before we finish constructing the CatCList
+ * then we will leak those reference counts. This is annoying but
+ * it has no real consequence beyond possibly generating some
+ * warning messages at the next transaction commit, so it's not
+ * worth fixing.
+ */
+ ct->refcount++;
ctlist = lcons(ct, ctlist);
nmembers++;
}
@@ -1677,10 +1523,7 @@ SearchCatCacheList(CatCache *cache,
cl->cl_magic = CL_MAGIC;
cl->my_cache = cache;
DLInitElem(&cl->cache_elem, (void *) cl);
- cl->refcount = 1; /* count this first reference */
- cl->prev_refcount = NULL;
- cl->numpushes = 0;
- cl->numalloc = 0;
+ cl->refcount = 0; /* for the moment */
cl->dead = false;
cl->ordered = ordered;
cl->nkeys = nkeys;
@@ -1704,6 +1547,11 @@ SearchCatCacheList(CatCache *cache,
CACHE3_elog(DEBUG2, "SearchCatCacheList(%s): made list of %d members",
cache->cc_relname, nmembers);
+ /* Finally, bump the list's refcount and return it */
+ ResourceOwnerEnlargeCatCacheListRefs(CurrentResourceOwner);
+ cl->refcount++;
+ ResourceOwnerRememberCatCacheListRef(CurrentResourceOwner, cl);
+
return cl;
}
@@ -1735,6 +1583,7 @@ ReleaseCatCacheList(CatCList *list)
}
list->refcount--;
+ ResourceOwnerForgetCatCacheListRef(CurrentResourceOwner, list);
if (list->refcount == 0
#ifndef CATCACHE_FORCE_RELEASE
@@ -1748,7 +1597,7 @@ ReleaseCatCacheList(CatCList *list)
/*
* CatalogCacheCreateEntry
* Create a new CatCTup entry, copying the given HeapTuple and other
- * supplied data into it. The new entry is given refcount 1.
+ * supplied data into it. The new entry initially has refcount 0.
*/
static CatCTup *
CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp,
@@ -1775,13 +1624,10 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp,
DLInitElem(&ct->lrulist_elem, (void *) ct);
DLInitElem(&ct->cache_elem, (void *) ct);
ct->c_list = NULL;
- ct->refcount = 1; /* count this first reference */
+ ct->refcount = 0; /* for the moment */
ct->dead = false;
ct->negative = negative;
ct->hash_value = hashValue;
- ct->prev_refcount = NULL;
- ct->numpushes = 0;
- ct->numalloc = 0;
DLAddHead(&CacheHdr->ch_lrulist, &ct->lrulist_elem);
DLAddHead(&cache->cc_bucket[hashIndex], &ct->cache_elem);
@@ -1791,8 +1637,8 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp,
/*
* If we've exceeded the desired size of the caches, try to throw away
- * the least recently used entry. NB: the newly-built entry cannot
- * get thrown away here, because it has positive refcount.
+ * the least recently used entry. NB: be careful not to throw away
+ * the newly-built entry...
*/
if (CacheHdr->ch_ntup > CacheHdr->ch_maxtup)
{
@@ -1805,7 +1651,7 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp,
prevelt = DLGetPred(elt);
- if (oldct->refcount == 0)
+ if (oldct->refcount == 0 && oldct != ct)
{
CACHE2_elog(DEBUG2, "CatCacheCreateEntry(%s): Overflow, LRU removal",
cache->cc_relname);