aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2005-08-08 19:17:23 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2005-08-08 19:17:23 +0000
commit4568e0f791f7e838409e1ef93d3513a6314b835e (patch)
treef35fc0900e984a6ec9fe0861753330df613ed41c /src
parentbe27a2012311af1ad3254b2d17df28f7f4ddd5c5 (diff)
downloadpostgresql-4568e0f791f7e838409e1ef93d3513a6314b835e.tar.gz
postgresql-4568e0f791f7e838409e1ef93d3513a6314b835e.zip
Modify AtEOXact_CatCache and AtEOXact_RelationCache to assume that the
ResourceOwner mechanism already released all reference counts for the cache entries; therefore, we do not need to scan the catcache or relcache at transaction end, unless we want to do it as a debugging crosscheck. Do the crosscheck only in Assert mode. This is the same logic we had previously installed in AtEOXact_Buffers to avoid overhead with large numbers of shared buffers. I thought it'd be a good idea to do it here too, in view of Kari Lavikka's recent report showing a real-world case where AtEOXact_CatCache is taking a significant fraction of runtime.
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/xact.c16
-rw-r--r--src/backend/utils/cache/catcache.c262
-rw-r--r--src/backend/utils/cache/relcache.c105
-rw-r--r--src/backend/utils/resowner/resowner.c86
4 files changed, 233 insertions, 236 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index ee33030292f..5323cefe0e7 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.211 2005/07/25 22:12:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.212 2005/08/08 19:17:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1549,6 +1549,9 @@ CommitTransaction(void)
/* Check we've released all buffer pins */
AtEOXact_Buffers(true);
+ /* Clean up the relation cache */
+ AtEOXact_RelationCache(true);
+
/*
* Make catalog changes visible to all backends. This has to happen
* after relcache references are dropped (see comments for
@@ -1576,6 +1579,9 @@ CommitTransaction(void)
RESOURCE_RELEASE_AFTER_LOCKS,
true, true);
+ /* Check we've released all catcache entries */
+ AtEOXact_CatCache(true);
+
AtEOXact_GUC(true, false);
AtEOXact_SPI(true);
AtEOXact_on_commit_actions(true);
@@ -1768,6 +1774,9 @@ PrepareTransaction(void)
/* Check we've released all buffer pins */
AtEOXact_Buffers(true);
+ /* Clean up the relation cache */
+ AtEOXact_RelationCache(true);
+
/* notify and flatfiles don't need a postprepare call */
PostPrepare_Inval();
@@ -1785,6 +1794,9 @@ PrepareTransaction(void)
RESOURCE_RELEASE_AFTER_LOCKS,
true, true);
+ /* Check we've released all catcache entries */
+ AtEOXact_CatCache(true);
+
/* PREPARE acts the same as COMMIT as far as GUC is concerned */
AtEOXact_GUC(true, false);
AtEOXact_SPI(true);
@@ -1922,6 +1934,7 @@ AbortTransaction(void)
RESOURCE_RELEASE_BEFORE_LOCKS,
false, true);
AtEOXact_Buffers(false);
+ AtEOXact_RelationCache(false);
AtEOXact_Inval(false);
smgrDoPendingDeletes(false);
AtEOXact_MultiXact();
@@ -1931,6 +1944,7 @@ AbortTransaction(void)
ResourceOwnerRelease(TopTransactionResourceOwner,
RESOURCE_RELEASE_AFTER_LOCKS,
false, true);
+ AtEOXact_CatCache(false);
AtEOXact_GUC(false, false);
AtEOXact_SPI(false);
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index abe0aa060c0..24b8836f07b 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.121 2005/05/06 17:24:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.122 2005/08/08 19:17:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -530,62 +530,43 @@ CreateCacheMemoryContext(void)
*
* 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.
- * In the commit case, any nonzero counts indicate failure to call
- * ReleaseSysCache, so we put out a notice for debugging purposes.
+ * As of PostgreSQL 8.1, catcache pins should get released by the
+ * ResourceOwner mechanism. This routine is just a debugging
+ * cross-check that no pins remain.
*/
void
AtEOXact_CatCache(bool isCommit)
{
- CatCache *ccp;
- Dlelem *elt,
- *nextelt;
-
- /*
- * First clean up CatCLists
- */
- for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next)
+#ifdef USE_ASSERT_CHECKING
+ if (assert_enabled)
{
- for (elt = DLGetHead(&ccp->cc_lists); elt; elt = nextelt)
- {
- CatCList *cl = (CatCList *) DLE_VAL(elt);
-
- nextelt = DLGetSucc(elt);
+ CatCache *ccp;
+ Dlelem *elt;
- if (cl->refcount != 0)
+ /* Check CatCLists */
+ for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next)
+ {
+ for (elt = DLGetHead(&ccp->cc_lists); elt; elt = DLGetSucc(elt))
{
- if (isCommit)
- PrintCatCacheListLeakWarning(cl);
- cl->refcount = 0;
- }
+ CatCList *cl = (CatCList *) DLE_VAL(elt);
- /* Clean up any now-deletable dead entries */
- if (cl->dead)
- CatCacheRemoveCList(ccp, cl);
+ Assert(cl->cl_magic == CL_MAGIC);
+ Assert(cl->refcount == 0);
+ Assert(!cl->dead);
+ }
}
- }
-
- /*
- * Now clean up tuples; we can scan them all using the global LRU list
- */
- for (elt = DLGetHead(&CacheHdr->ch_lrulist); elt; elt = nextelt)
- {
- CatCTup *ct = (CatCTup *) DLE_VAL(elt);
-
- nextelt = DLGetSucc(elt);
- if (ct->refcount != 0)
+ /* Check individual tuples */
+ for (elt = DLGetHead(&CacheHdr->ch_lrulist); elt; elt = DLGetSucc(elt))
{
- if (isCommit)
- PrintCatCacheLeakWarning(&ct->tuple);
- ct->refcount = 0;
- }
+ CatCTup *ct = (CatCTup *) DLE_VAL(elt);
- /* Clean up any now-deletable dead entries */
- if (ct->dead)
- CatCacheRemoveCTup(ct->my_cache, ct);
+ Assert(ct->ct_magic == CT_MAGIC);
+ Assert(ct->refcount == 0);
+ Assert(!ct->dead);
+ }
}
+#endif
}
/*
@@ -1329,11 +1310,9 @@ SearchCatCacheList(CatCache *cache,
Dlelem *elt;
CatCList *cl;
CatCTup *ct;
- List *ctlist;
+ List * volatile ctlist;
ListCell *ctlist_item;
int nmembers;
- Relation relation;
- SysScanDesc scandesc;
bool ordered;
HeapTuple ntp;
MemoryContext oldcxt;
@@ -1433,98 +1412,131 @@ SearchCatCacheList(CatCache *cache,
* List was not found in cache, so we have to build it by reading the
* relation. For each matching tuple found in the relation, use an
* existing cache entry if possible, else build a new one.
+ *
+ * We have to bump the member refcounts immediately to ensure they
+ * won't get dropped from the cache while loading other members.
+ * We use a PG_TRY block to ensure we can undo those refcounts if
+ * we get an error before we finish constructing the CatCList.
*/
- relation = heap_open(cache->cc_reloid, AccessShareLock);
-
- scandesc = systable_beginscan(relation,
- cache->cc_indexoid,
- true,
- SnapshotNow,
- nkeys,
- cur_skey);
-
- /* The list will be ordered iff we are doing an index scan */
- ordered = (scandesc->irel != NULL);
+ ResourceOwnerEnlargeCatCacheListRefs(CurrentResourceOwner);
ctlist = NIL;
- nmembers = 0;
- while (HeapTupleIsValid(ntp = systable_getnext(scandesc)))
+ PG_TRY();
{
- uint32 hashValue;
- Index hashIndex;
+ Relation relation;
+ SysScanDesc scandesc;
- /*
- * See if there's an entry for this tuple already.
- */
- ct = NULL;
- hashValue = CatalogCacheComputeTupleHashValue(cache, ntp);
- hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);
+ relation = heap_open(cache->cc_reloid, AccessShareLock);
- for (elt = DLGetHead(&cache->cc_bucket[hashIndex]);
- elt;
- elt = DLGetSucc(elt))
- {
- ct = (CatCTup *) DLE_VAL(elt);
+ scandesc = systable_beginscan(relation,
+ cache->cc_indexoid,
+ true,
+ SnapshotNow,
+ nkeys,
+ cur_skey);
- if (ct->dead || ct->negative)
- continue; /* ignore dead and negative entries */
+ /* The list will be ordered iff we are doing an index scan */
+ ordered = (scandesc->irel != NULL);
- if (ct->hash_value != hashValue)
- continue; /* quickly skip entry if wrong hash val */
-
- if (!ItemPointerEquals(&(ct->tuple.t_self), &(ntp->t_self)))
- continue; /* not same tuple */
+ while (HeapTupleIsValid(ntp = systable_getnext(scandesc)))
+ {
+ uint32 hashValue;
+ Index hashIndex;
/*
- * Found a match, but can't use it if it belongs to another
- * list already
+ * See if there's an entry for this tuple already.
*/
- if (ct->c_list)
- continue;
+ ct = NULL;
+ hashValue = CatalogCacheComputeTupleHashValue(cache, ntp);
+ hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);
- /* Found a match, so move it to front */
- DLMoveToFront(&ct->lrulist_elem);
+ for (elt = DLGetHead(&cache->cc_bucket[hashIndex]);
+ elt;
+ elt = DLGetSucc(elt))
+ {
+ ct = (CatCTup *) DLE_VAL(elt);
- break;
- }
+ if (ct->dead || ct->negative)
+ continue; /* ignore dead and negative entries */
- if (elt == NULL)
- {
- /* We didn't find a usable entry, so make a new one */
- ct = CatalogCacheCreateEntry(cache, ntp,
- hashValue, hashIndex,
- false);
+ if (ct->hash_value != hashValue)
+ continue; /* quickly skip entry if wrong hash val */
+
+ if (!ItemPointerEquals(&(ct->tuple.t_self), &(ntp->t_self)))
+ continue; /* not same tuple */
+
+ /*
+ * Found a match, but can't use it if it belongs to another
+ * list already
+ */
+ if (ct->c_list)
+ continue;
+
+ /* Found a match, so move it to front */
+ DLMoveToFront(&ct->lrulist_elem);
+
+ break;
+ }
+
+ if (elt == NULL)
+ {
+ /* We didn't find a usable entry, so make a new one */
+ ct = CatalogCacheCreateEntry(cache, ntp,
+ hashValue, hashIndex,
+ false);
+ }
+
+ /* Careful here: add entry to ctlist, then bump its refcount */
+ ctlist = lappend(ctlist, ct);
+ ct->refcount++;
}
+ systable_endscan(scandesc);
+
+ heap_close(relation, AccessShareLock);
+
/*
- * 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.
+ * Now we can build the CatCList entry. First we need a dummy tuple
+ * containing the key values...
*/
- ct->refcount++;
- ctlist = lappend(ctlist, ct);
- nmembers++;
- }
+ ntp = build_dummy_tuple(cache, nkeys, cur_skey);
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+ nmembers = list_length(ctlist);
+ cl = (CatCList *)
+ palloc(sizeof(CatCList) + nmembers * sizeof(CatCTup *));
+ heap_copytuple_with_tuple(ntp, &cl->tuple);
+ MemoryContextSwitchTo(oldcxt);
+ heap_freetuple(ntp);
- systable_endscan(scandesc);
+ /*
+ * We are now past the last thing that could trigger an elog before
+ * we have finished building the CatCList and remembering it in the
+ * resource owner. So it's OK to fall out of the PG_TRY, and indeed
+ * we'd better do so before we start marking the members as belonging
+ * to the list.
+ */
- heap_close(relation, AccessShareLock);
+ }
+ PG_CATCH();
+ {
+ foreach(ctlist_item, ctlist)
+ {
+ ct = (CatCTup *) lfirst(ctlist_item);
+ Assert(ct->c_list == NULL);
+ Assert(ct->refcount > 0);
+ ct->refcount--;
+ if (ct->refcount == 0
+#ifndef CATCACHE_FORCE_RELEASE
+ && ct->dead
+#endif
+ )
+ CatCacheRemoveCTup(cache, ct);
+ }
- /*
- * Now we can build the CatCList entry. First we need a dummy tuple
- * containing the key values...
- */
- ntp = build_dummy_tuple(cache, nkeys, cur_skey);
- oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
- cl = (CatCList *) palloc(sizeof(CatCList) + nmembers * sizeof(CatCTup *));
- heap_copytuple_with_tuple(ntp, &cl->tuple);
- MemoryContextSwitchTo(oldcxt);
- heap_freetuple(ntp);
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
cl->cl_magic = CL_MAGIC;
cl->my_cache = cache;
@@ -1536,29 +1548,27 @@ SearchCatCacheList(CatCache *cache,
cl->hash_value = lHashValue;
cl->n_members = nmembers;
- Assert(nmembers == list_length(ctlist));
- ctlist_item = list_head(ctlist);
- for (i = 0; i < nmembers; i++)
+ i = 0;
+ foreach(ctlist_item, ctlist)
{
- cl->members[i] = ct = (CatCTup *) lfirst(ctlist_item);
+ cl->members[i++] = ct = (CatCTup *) lfirst(ctlist_item);
Assert(ct->c_list == NULL);
ct->c_list = cl;
/* mark list dead if any members already dead */
if (ct->dead)
cl->dead = true;
- ctlist_item = lnext(ctlist_item);
}
+ Assert(i == nmembers);
DLAddHead(&cache->cc_lists, &cl->cache_elem);
- 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);
+ CACHE3_elog(DEBUG2, "SearchCatCacheList(%s): made list of %d members",
+ cache->cc_relname, nmembers);
+
return cl;
}
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 7b140228c8c..09f54f7bc91 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.225 2005/05/29 04:23:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.226 2005/08/08 19:17:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -122,9 +122,9 @@ static long relcacheInvalsReceived = 0L;
static List *initFileRelationIds = NIL;
/*
- * This flag lets us optimize away work in AtEOSubXact_RelationCache().
+ * This flag lets us optimize away work in AtEO(Sub)Xact_RelationCache().
*/
-static bool need_eosubxact_work = false;
+static bool need_eoxact_work = false;
/*
@@ -1816,6 +1816,12 @@ RelationCacheInvalidate(void)
* In the case of abort, we don't want to try to rebuild any invalidated
* cache entries (since we can't safely do database accesses). Therefore
* we must reset refcnts before handling pending invalidations.
+ *
+ * As of PostgreSQL 8.1, relcache refcnts should get released by the
+ * ResourceOwner mechanism. This routine just does a debugging
+ * cross-check that no pins remain. However, we also need to do special
+ * cleanup when the current transaction created any relations or made use
+ * of forced index lists.
*/
void
AtEOXact_RelationCache(bool isCommit)
@@ -1823,12 +1829,47 @@ AtEOXact_RelationCache(bool isCommit)
HASH_SEQ_STATUS status;
RelIdCacheEnt *idhentry;
+ /*
+ * To speed up transaction exit, we want to avoid scanning the relcache
+ * unless there is actually something for this routine to do. Other
+ * than the debug-only Assert checks, most transactions don't create
+ * any work for us to do here, so we keep a static flag that gets set
+ * if there is anything to do. (Currently, this means either a relation
+ * is created in the current xact, or an index list is forced.) For
+ * simplicity, the flag remains set till end of top-level transaction,
+ * even though we could clear it at subtransaction end in some cases.
+ */
+ if (!need_eoxact_work
+#ifdef USE_ASSERT_CHECKING
+ && !assert_enabled
+#endif
+ )
+ return;
+
hash_seq_init(&status, RelationIdCache);
while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
{
Relation relation = idhentry->reldesc;
- int expected_refcnt;
+
+ /*
+ * The relcache entry's ref count should be back to its normal
+ * not-in-a-transaction state: 0 unless it's nailed in cache.
+ *
+ * In bootstrap mode, this is NOT true, so don't check it ---
+ * the bootstrap code expects relations to stay open across
+ * start/commit transaction calls. (That seems bogus, but it's
+ * not worth fixing.)
+ */
+#ifdef USE_ASSERT_CHECKING
+ if (!IsBootstrapProcessingMode())
+ {
+ int expected_refcnt;
+
+ expected_refcnt = relation->rd_isnailed ? 1 : 0;
+ Assert(relation->rd_refcnt == expected_refcnt);
+ }
+#endif
/*
* Is it a relation created in the current transaction?
@@ -1852,40 +1893,6 @@ AtEOXact_RelationCache(bool isCommit)
}
/*
- * During transaction abort, we must also reset relcache entry ref
- * counts to their normal not-in-a-transaction state. A ref count
- * may be too high because some routine was exited by ereport()
- * between incrementing and decrementing the count.
- *
- * During commit, we should not have to do this, but it's still
- * useful to check that the counts are correct to catch missed
- * relcache closes.
- *
- * In bootstrap mode, do NOT reset the refcnt nor complain that it's
- * nonzero --- the bootstrap code expects relations to stay open
- * across start/commit transaction calls. (That seems bogus, but
- * it's not worth fixing.)
- */
- expected_refcnt = relation->rd_isnailed ? 1 : 0;
-
- if (isCommit)
- {
- if (relation->rd_refcnt != expected_refcnt &&
- !IsBootstrapProcessingMode())
- {
- elog(WARNING, "relcache reference leak: relation \"%s\" has refcnt %d instead of %d",
- RelationGetRelationName(relation),
- relation->rd_refcnt, expected_refcnt);
- relation->rd_refcnt = expected_refcnt;
- }
- }
- else
- {
- /* abort case, just reset it quietly */
- relation->rd_refcnt = expected_refcnt;
- }
-
- /*
* Flush any temporary index list.
*/
if (relation->rd_indexvalid == 2)
@@ -1896,8 +1903,8 @@ AtEOXact_RelationCache(bool isCommit)
}
}
- /* Once done with the transaction, we can reset need_eosubxact_work */
- need_eosubxact_work = false;
+ /* Once done with the transaction, we can reset need_eoxact_work */
+ need_eoxact_work = false;
}
/*
@@ -1915,18 +1922,10 @@ AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid,
RelIdCacheEnt *idhentry;
/*
- * In the majority of subtransactions there is not anything for this
- * routine to do, and since there are usually many entries in the
- * relcache, uselessly scanning the cache represents a surprisingly
- * large fraction of the subtransaction entry/exit overhead. To avoid
- * this, we keep a static flag that must be set whenever a condition
- * is created that requires subtransaction-end work. (Currently, this
- * means either a relation is created in the current xact, or an index
- * list is forced.) For simplicity, the flag remains set till end of
- * top-level transaction, even though we could clear it earlier in some
- * cases.
+ * Skip the relcache scan if nothing to do --- see notes for
+ * AtEOXact_RelationCache.
*/
- if (!need_eosubxact_work)
+ if (!need_eoxact_work)
return;
hash_seq_init(&status, RelationIdCache);
@@ -2032,7 +2031,7 @@ RelationBuildLocalRelation(const char *relname,
rel->rd_createSubid = GetCurrentSubTransactionId();
/* must flag that we have rels created in this transaction */
- need_eosubxact_work = true;
+ need_eoxact_work = true;
/* is it a temporary relation? */
rel->rd_istemp = isTempNamespace(relnamespace);
@@ -2626,7 +2625,7 @@ RelationSetIndexList(Relation relation, List *indexIds)
relation->rd_indexlist = indexIds;
relation->rd_indexvalid = 2; /* mark list as forced */
/* must flag that we have a forced index list */
- need_eosubxact_work = true;
+ need_eoxact_work = true;
}
/*
diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c
index ad9186d215b..786652a757b 100644
--- a/src/backend/utils/resowner/resowner.c
+++ b/src/backend/utils/resowner/resowner.c
@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.12 2005/04/06 04:34:22 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.13 2005/08/08 19:17:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -213,32 +213,19 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
ReleaseBuffer(owner->buffers[owner->nbuffers - 1]);
}
- /* Release relcache references */
- if (isTopLevel)
- {
- /*
- * For a top-level xact we are going to release all
- * references, so just do a single relcache call at the top of
- * the recursion.
- */
- if (owner == TopTransactionResourceOwner)
- AtEOXact_RelationCache(isCommit);
- /* Mark object as owning no relrefs, just for sanity */
- owner->nrelrefs = 0;
- }
- else
+ /*
+ * Release relcache references. Note that RelationClose will
+ * remove the relref entry from my list, so I just have to
+ * iterate till there are none.
+ *
+ * As with buffer pins, warn if any are left at commit time,
+ * and release back-to-front for speed.
+ */
+ while (owner->nrelrefs > 0)
{
- /*
- * Release relcache refs retail. Note that RelationClose will
- * remove the relref entry from my list, so I just have to
- * iterate till there are none.
- */
- while (owner->nrelrefs > 0)
- {
- if (isCommit)
- PrintRelCacheLeakWarning(owner->relrefs[owner->nrelrefs - 1]);
- RelationClose(owner->relrefs[owner->nrelrefs - 1]);
- }
+ if (isCommit)
+ PrintRelCacheLeakWarning(owner->relrefs[owner->nrelrefs - 1]);
+ RelationClose(owner->relrefs[owner->nrelrefs - 1]);
}
}
else if (phase == RESOURCE_RELEASE_LOCKS)
@@ -269,40 +256,27 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
}
else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)
{
- /* Release catcache references */
- if (isTopLevel)
+ /*
+ * Release catcache references. Note that ReleaseCatCache
+ * will remove the catref entry from my list, so I just have
+ * to iterate till there are none. Ditto for catcache lists.
+ *
+ * As with buffer pins, warn if any are left at commit time,
+ * and release back-to-front for speed.
+ */
+ while (owner->ncatrefs > 0)
{
- /*
- * For a top-level xact we are going to release all
- * references, so just do a single catcache call at the top of
- * the recursion.
- */
- if (owner == TopTransactionResourceOwner)
- AtEOXact_CatCache(isCommit);
- /* Mark object as owning no catrefs, just for sanity */
- owner->ncatrefs = 0;
- owner->ncatlistrefs = 0;
+ if (isCommit)
+ PrintCatCacheLeakWarning(owner->catrefs[owner->ncatrefs - 1]);
+ ReleaseCatCache(owner->catrefs[owner->ncatrefs - 1]);
}
- else
+ while (owner->ncatlistrefs > 0)
{
- /*
- * Release catcache refs retail. Note that ReleaseCatCache
- * will remove the catref entry from my list, so I just have
- * to iterate till there are none. Ditto for catcache lists.
- */
- while (owner->ncatrefs > 0)
- {
- if (isCommit)
- PrintCatCacheLeakWarning(owner->catrefs[owner->ncatrefs - 1]);
- ReleaseCatCache(owner->catrefs[owner->ncatrefs - 1]);
- }
- while (owner->ncatlistrefs > 0)
- {
- if (isCommit)
- PrintCatCacheListLeakWarning(owner->catlistrefs[owner->ncatlistrefs - 1]);
- ReleaseCatCacheList(owner->catlistrefs[owner->ncatlistrefs - 1]);
- }
+ if (isCommit)
+ PrintCatCacheListLeakWarning(owner->catlistrefs[owner->ncatlistrefs - 1]);
+ ReleaseCatCacheList(owner->catlistrefs[owner->ncatlistrefs - 1]);
}
+
/* Clean up index scans too */
ReleaseResources_gist();
ReleaseResources_hash();