On Mon, Jan 02, 2012 at 06:41:31PM +0000, Simon Riggs wrote: > On Mon, Jan 2, 2012 at 6:06 PM, Noah Misch <n...@leadboat.com> wrote: > > On Mon, Jan 02, 2012 at 05:09:16PM +0000, Simon Riggs wrote: > >> Attached patch makes SnapshotNow into an MVCC snapshot, initialised at > >> the start of each scan iff SnapshotNow is passed as the scan's > >> snapshot. It's fairly brief but seems to do the trick. > > > > That's a neat trick. ?However, if you start a new SnapshotNow scan while > > one is > > ongoing, the primordial scan's snapshot will change mid-stream. > > Do we ever do that? (and if so, Why?!? or perhaps just Where?)
I hacked up your patch a bit, as attached, to emit a WARNING for any nested use of SnapshotNow. This made 97/127 test files fail. As one example, RelationBuildRuleLock() does TextDatumGetCString() for every tuple of its SnapshotNow scan. That may need a detoast, which itself runs a scan. > We can use more complex code if required, but we'll be adding > complexity and code into the main path that I'd like to avoid. Agreed.
*** a/src/backend/access/heap/heapam.c --- b/src/backend/access/heap/heapam.c *************** *** 1201,1206 **** heap_beginscan_internal(Relation relation, Snapshot snapshot, --- 1201,1208 ---- */ scan->rs_pageatatime = IsMVCCSnapshot(snapshot); + InitSnapshotNowIfNeeded(snapshot); + /* * For a seqscan in a serializable transaction, acquire a predicate lock * on the entire relation. This is required not only to lock all the *************** *** 1270,1275 **** heap_endscan(HeapScanDesc scan) --- 1272,1279 ---- if (BufferIsValid(scan->rs_cbuf)) ReleaseBuffer(scan->rs_cbuf); + FinishSnapshotNow(scan->rs_snapshot); + /* * decrement relation reference count and free scan descriptor storage */ *************** *** 1680,1685 **** heap_get_latest_tid(Relation relation, --- 1684,1691 ---- if (!ItemPointerIsValid(tid)) return; + InitSnapshotNowIfNeeded(snapshot); + /* * Since this can be called with user-supplied TID, don't trust the input * too much. (RelationGetNumberOfBlocks is an expensive check, so we *************** *** 1775,1780 **** heap_get_latest_tid(Relation relation, --- 1781,1788 ---- priorXmax = HeapTupleHeaderGetXmax(tp.t_data); UnlockReleaseBuffer(buffer); } /* end of loop */ + + FinishSnapshotNow(snapshot); } *** a/src/backend/access/index/indexam.c --- b/src/backend/access/index/indexam.c *************** *** 292,297 **** index_beginscan_internal(Relation indexRelation, --- 292,299 ---- */ RelationIncrementReferenceCount(indexRelation); + InitSnapshotNowIfNeeded(snapshot); + /* * Tell the AM to open a scan. */ *************** *** 370,375 **** index_endscan(IndexScanDesc scan) --- 372,379 ---- /* End the AM's scan */ FunctionCall1(procedure, PointerGetDatum(scan)); + FinishSnapshotNow(scan->xs_snapshot); + /* Release index refcount acquired by index_beginscan */ RelationDecrementReferenceCount(scan->indexRelation); *** a/src/backend/utils/time/snapmgr.c --- b/src/backend/utils/time/snapmgr.c *************** *** 205,210 **** GetLatestSnapshot(void) --- 205,235 ---- return SecondarySnapshot; } + static bool SnapshotNowActive; + + /* + * InitSnapshotNowIfNeeded + * If passed snapshot is SnapshotNow then refresh it with latest info. + */ + void + InitSnapshotNowIfNeeded(Snapshot snap) + { + if (!IsSnapshotNow(snap)) + return; + + if (SnapshotNowActive) + elog(WARNING, "SnapshotNow used concurrently"); + + snap = GetSnapshotData(&SnapshotNowData); + SnapshotNowActive = true; + } + + void FinishSnapshotNow(Snapshot snap) + { + if (IsSnapshotNow(snap)) + SnapshotNowActive = false; + } + /* * SnapshotSetCommandId * Propagate CommandCounterIncrement into the static snapshots, if set *** a/src/backend/utils/time/tqual.c --- b/src/backend/utils/time/tqual.c *************** *** 67,73 **** /* Static variables representing various special snapshot semantics */ ! SnapshotData SnapshotNowData = {HeapTupleSatisfiesNow}; SnapshotData SnapshotSelfData = {HeapTupleSatisfiesSelf}; SnapshotData SnapshotAnyData = {HeapTupleSatisfiesAny}; SnapshotData SnapshotToastData = {HeapTupleSatisfiesToast}; --- 67,73 ---- /* Static variables representing various special snapshot semantics */ ! SnapshotData SnapshotNowData = {HeapTupleSatisfiesMVCC}; SnapshotData SnapshotSelfData = {HeapTupleSatisfiesSelf}; SnapshotData SnapshotAnyData = {HeapTupleSatisfiesAny}; SnapshotData SnapshotToastData = {HeapTupleSatisfiesToast}; *************** *** 293,298 **** HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer) --- 293,299 ---- return false; } + #ifdef RECENTLY_DEAD_CODE /* * HeapTupleSatisfiesNow * True iff heap tuple is valid "now". *************** *** 474,479 **** HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer) --- 475,481 ---- HeapTupleHeaderGetXmax(tuple)); return false; } + #endif /* * HeapTupleSatisfiesAny *** a/src/include/utils/snapmgr.h --- b/src/include/utils/snapmgr.h *************** *** 24,29 **** extern TransactionId RecentGlobalXmin; --- 24,31 ---- extern Snapshot GetTransactionSnapshot(void); extern Snapshot GetLatestSnapshot(void); + extern void InitSnapshotNowIfNeeded(Snapshot snap); + extern void FinishSnapshotNow(Snapshot snap); extern void SnapshotSetCommandId(CommandId curcid); extern void PushActiveSnapshot(Snapshot snapshot); *** a/src/include/utils/tqual.h --- b/src/include/utils/tqual.h *************** *** 40,45 **** extern PGDLLIMPORT SnapshotData SnapshotToastData; --- 40,47 ---- /* This macro encodes the knowledge of which snapshots are MVCC-safe */ #define IsMVCCSnapshot(snapshot) \ ((snapshot)->satisfies == HeapTupleSatisfiesMVCC) + #define IsSnapshotNow(snapshot) \ + ((snapshot) == (&SnapshotNowData)) /* * HeapTupleSatisfiesVisibility
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers