diff options
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r-- | src/backend/utils/cache/relcache.c | 36 |
1 files changed, 33 insertions, 3 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 162588ee3d1..b9a969281bf 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -1831,7 +1831,9 @@ RelationClearRelation(Relation relation, bool rebuild) { /* * As per notes above, a rel to be rebuilt MUST have refcnt > 0; while of - * course it would be a bad idea to blow away one with nonzero refcnt. + * course it would be an equally bad idea to blow away one with nonzero + * refcnt, since that would leave someone somewhere with a dangling + * pointer. All callers are expected to have verified that this holds. */ Assert(rebuild ? !RelationHasReferenceCountZero(relation) : @@ -2321,11 +2323,25 @@ AtEOXact_RelationCache(bool isCommit) { if (isCommit) relation->rd_createSubid = InvalidSubTransactionId; - else + else if (RelationHasReferenceCountZero(relation)) { RelationClearRelation(relation, false); continue; } + else + { + /* + * Hmm, somewhere there's a (leaked?) reference to the + * relation. We daren't remove the entry for fear of + * dereferencing a dangling pointer later. Bleat, and mark it + * as not belonging to the current transaction. Hopefully + * it'll get cleaned up eventually. This must be just a + * WARNING to avoid error-during-error-recovery loops. + */ + relation->rd_createSubid = InvalidSubTransactionId; + elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount", + RelationGetRelationName(relation)); + } } /* @@ -2386,11 +2402,25 @@ AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid, { if (isCommit) relation->rd_createSubid = parentSubid; - else + else if (RelationHasReferenceCountZero(relation)) { RelationClearRelation(relation, false); continue; } + else + { + /* + * Hmm, somewhere there's a (leaked?) reference to the + * relation. We daren't remove the entry for fear of + * dereferencing a dangling pointer later. Bleat, and + * transfer it to the parent subtransaction so we can try + * again later. This must be just a WARNING to avoid + * error-during-error-recovery loops. + */ + relation->rd_createSubid = parentSubid; + elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount", + RelationGetRelationName(relation)); + } } /* |