I wrote: > After review of all the callers of RelationClearRelation, it seems like > most of them already have sufficient guards to prevent triggering of the > Assert. The ones that lack such tests are AtEOXact_cleanup and > AtEOSubXact_cleanup. So what I'm now thinking is that those should do > something along the lines of
Specifically, this, which can be shown to mitigate the results of the problem cases in an otherwise-unpatched build. regards, tom lane
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 44e9509..420ef3d 100644 *** a/src/backend/utils/cache/relcache.c --- b/src/backend/utils/cache/relcache.c *************** RelationClearRelation(Relation relation, *** 2048,2054 **** { /* * 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. */ Assert(rebuild ? !RelationHasReferenceCountZero(relation) : --- 2048,2056 ---- { /* * As per notes above, a rel to be rebuilt MUST have refcnt > 0; while of ! * 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) : *************** AtEOXact_cleanup(Relation relation, bool *** 2654,2664 **** { if (isCommit) relation->rd_createSubid = InvalidSubTransactionId; ! else { RelationClearRelation(relation, false); return; } } /* --- 2656,2680 ---- { if (isCommit) relation->rd_createSubid = InvalidSubTransactionId; ! else if (RelationHasReferenceCountZero(relation)) { RelationClearRelation(relation, false); return; } + 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)); + } } /* *************** AtEOSubXact_cleanup(Relation relation, b *** 2747,2757 **** { if (isCommit) relation->rd_createSubid = parentSubid; ! else { RelationClearRelation(relation, false); return; } } /* --- 2763,2786 ---- { if (isCommit) relation->rd_createSubid = parentSubid; ! else if (RelationHasReferenceCountZero(relation)) { RelationClearRelation(relation, false); return; } + 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)); + } } /*
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers