Consider this sequence of commands: create type rowtype as (c int, d int); create temp table t of rowtype; \c - drop type rowtype cascade;
Since the switch to MVCC catalog scans, it exhibits the following error about 10% of the time on my system: CREATE TYPE CREATE TABLE You are now connected to database "test" as user "nm". ERROR: XX000: cache lookup failed for relation 17009 LOCATION: getRelationDescription, objectaddress.c:2186 With "\c", in general, you may end up executing commands under the new session before the old backend has finished exiting. For this test case specifically, the two backends' attempts to drop table "t" regularly overlap. The old backend would drop it within RemoveTempRelationsCallback(), and the new backend would cascade from "rowtype" to drop it. findDependentObjects() deals with concurrent deletion attempts by acquiring a lock on each object it will delete, then calling systable_recheck_tuple() to determine whether another deleter was successful while the current backend was waiting for the lock. systable_recheck_tuple() uses the scan snapshot, which really only works if that snapshot is SnapshotNow or some other that changes its decision in response to concurrent transaction commits. The switch to MVCC snapshots left this mutual exclusion protocol ineffective. Let's fix this by having systable_recheck_tuple() acquire a fresh catalog MVCC snapshot and recheck against that. I believe it would also be fully safe to use SnapshotNow here; however, I'm assuming we would otherwise manage to remove SnapshotNow entirely. Thanks, nm -- Noah Misch EnterpriseDB http://www.enterprisedb.com
diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c index 2bfe78a..2fecc88 100644 --- a/src/backend/access/index/genam.c +++ b/src/backend/access/index/genam.c @@ -362,7 +362,8 @@ systable_getnext(SysScanDesc sysscan) * systable_recheck_tuple --- recheck visibility of most-recently-fetched tuple * * This is useful to test whether an object was deleted while we waited to - * acquire lock on it. + * acquire lock on it. We recheck visibility in the style of SnapshotNow by + * checking against a fresh catalog snapshot. * * Note: we don't actually *need* the tuple to be passed in, but it's a * good crosscheck that the caller is interested in the right tuple. @@ -370,30 +371,37 @@ systable_getnext(SysScanDesc sysscan) bool systable_recheck_tuple(SysScanDesc sysscan, HeapTuple tup) { + Snapshot freshsnap; bool result; + /* + * For a scan using a non-MVCC snapshot like SnapshotSelf, we would simply + * reuse the old snapshot. So far, the only caller uses MVCC snapshots. + */ + freshsnap = GetCatalogSnapshot(RelationGetRelid(sysscan->heap_rel)); + if (sysscan->irel) { IndexScanDesc scan = sysscan->iscan; + Assert(IsMVCCSnapshot(scan->xs_snapshot)); Assert(tup == &scan->xs_ctup); Assert(BufferIsValid(scan->xs_cbuf)); /* must hold a buffer lock to call HeapTupleSatisfiesVisibility */ LockBuffer(scan->xs_cbuf, BUFFER_LOCK_SHARE); - result = HeapTupleSatisfiesVisibility(tup, scan->xs_snapshot, - scan->xs_cbuf); + result = HeapTupleSatisfiesVisibility(tup, freshsnap, scan->xs_cbuf); LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK); } else { HeapScanDesc scan = sysscan->scan; + Assert(IsMVCCSnapshot(scan->rs_snapshot)); Assert(tup == &scan->rs_ctup); Assert(BufferIsValid(scan->rs_cbuf)); /* must hold a buffer lock to call HeapTupleSatisfiesVisibility */ LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); - result = HeapTupleSatisfiesVisibility(tup, scan->rs_snapshot, - scan->rs_cbuf); + result = HeapTupleSatisfiesVisibility(tup, freshsnap, scan->rs_cbuf); LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK); } return result;
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers