diff --git i/src/include/access/transam.h w/src/include/access/transam.h index e37ecb52fa1..2b46d2b76a0 100644 --- i/src/include/access/transam.h +++ w/src/include/access/transam.h @@ -183,6 +183,8 @@ typedef struct VariableCacheData TransactionId latestCompletedXid; /* newest XID that has committed or * aborted */ + uint64 csn; + /* * These fields are protected by CLogTruncationLock */ diff --git i/src/include/utils/snapshot.h w/src/include/utils/snapshot.h index 2bc415376ac..389f18cf8a5 100644 --- i/src/include/utils/snapshot.h +++ w/src/include/utils/snapshot.h @@ -207,6 +207,8 @@ typedef struct SnapshotData TimestampTz whenTaken; /* timestamp when snapshot was taken */ XLogRecPtr lsn; /* position in the WAL stream when taken */ + + uint64 csn; } SnapshotData; #endif /* SNAPSHOT_H */ diff --git i/src/backend/storage/ipc/procarray.c w/src/backend/storage/ipc/procarray.c index 617853f56fc..520a79c9f73 100644 --- i/src/backend/storage/ipc/procarray.c +++ w/src/backend/storage/ipc/procarray.c @@ -65,6 +65,7 @@ #include "utils/snapmgr.h" #define UINT32_ACCESS_ONCE(var) ((uint32)(*((volatile uint32 *)&(var)))) +#define UINT64_ACCESS_ONCE(var) ((uint64)(*((volatile uint64 *)&(var)))) /* Our shared memory area */ typedef struct ProcArrayStruct @@ -266,6 +267,7 @@ CreateSharedProcArray(void) procArray->lastOverflowedXid = InvalidTransactionId; procArray->replication_slot_xmin = InvalidTransactionId; procArray->replication_slot_catalog_xmin = InvalidTransactionId; + ShmemVariableCache->csn = 1; } allProcs = ProcGlobal->allProcs; @@ -404,6 +406,8 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid) if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid, latestXid)) ShmemVariableCache->latestCompletedXid = latestXid; + /* Same with CSN */ + ShmemVariableCache->csn++; ProcGlobal->xids[proc->pgxactoff] = 0; ProcGlobal->nsubxids[proc->pgxactoff] = 0; @@ -531,6 +535,7 @@ ProcArrayEndTransactionInternal(PGPROC *proc, TransactionId latestXid) { size_t pgxactoff = proc->pgxactoff; + Assert(LWLockHeldByMe(ProcArrayLock)); Assert(TransactionIdIsValid(ProcGlobal->xids[pgxactoff])); Assert(ProcGlobal->xids[pgxactoff] == proc->xidCopy); @@ -561,6 +566,9 @@ ProcArrayEndTransactionInternal(PGPROC *proc, TransactionId latestXid) if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid, latestXid)) ShmemVariableCache->latestCompletedXid = latestXid; + + /* Same with CSN */ + ShmemVariableCache->csn++; } /* @@ -1637,7 +1645,7 @@ GetSnapshotData(Snapshot snapshot) TransactionId oldestxid; int mypgxactoff; TransactionId myxid; - + uint64 csn; TransactionId replication_slot_xmin = InvalidTransactionId; TransactionId replication_slot_catalog_xmin = InvalidTransactionId; @@ -1675,6 +1683,26 @@ GetSnapshotData(Snapshot snapshot) errmsg("out of memory"))); } +#if 1 + if (snapshot->csn != 0 && MyProc->xidCopy == InvalidTransactionId && + UINT64_ACCESS_ONCE(ShmemVariableCache->csn) == snapshot->csn) + { + if (!TransactionIdIsValid(MyProc->xmin)) + MyProc->xmin = TransactionXmin = snapshot->xmin; + RecentXmin = snapshot->xmin; + Assert(TransactionIdPrecedesOrEquals(TransactionXmin, RecentXmin)); + + snapshot->curcid = GetCurrentCommandId(false); + snapshot->active_count = 0; + snapshot->regd_count = 0; + snapshot->copied = false; + snapshot->lsn = InvalidXLogRecPtr; + snapshot->whenTaken = 0; + + return snapshot; + } +#endif + /* * It is sufficient to get shared lock on ProcArrayLock, even if we are * going to set MyProc->xmin. @@ -1687,6 +1715,7 @@ GetSnapshotData(Snapshot snapshot) nextfxid = ShmemVariableCache->nextFullXid; oldestxid = ShmemVariableCache->oldestXid; + csn = ShmemVariableCache->csn; /* xmax is always latestCompletedXid + 1 */ xmax = ShmemVariableCache->latestCompletedXid; @@ -1941,6 +1970,8 @@ GetSnapshotData(Snapshot snapshot) snapshot->regd_count = 0; snapshot->copied = false; + snapshot->csn = csn; + if (old_snapshot_threshold < 0) { /* diff --git i/src/backend/utils/time/snapmgr.c w/src/backend/utils/time/snapmgr.c index 41914f1a6c7..9d8ebe51307 100644 --- i/src/backend/utils/time/snapmgr.c +++ w/src/backend/utils/time/snapmgr.c @@ -604,6 +604,8 @@ SetTransactionSnapshot(Snapshot sourcesnap, VirtualTransactionId *sourcevxid, CurrentSnapshot->takenDuringRecovery = sourcesnap->takenDuringRecovery; /* NB: curcid should NOT be copied, it's a local matter */ + CurrentSnapshot->csn = 0; + /* * Now we have to fix what GetSnapshotData did with MyPgXact->xmin and * TransactionXmin. There is a race condition: to make sure we are not @@ -679,6 +681,7 @@ CopySnapshot(Snapshot snapshot) newsnap->regd_count = 0; newsnap->active_count = 0; newsnap->copied = true; + newsnap->csn = 0; /* setup XID array */ if (snapshot->xcnt > 0) @@ -2180,6 +2183,7 @@ RestoreSnapshot(char *start_address) snapshot->curcid = serialized_snapshot.curcid; snapshot->whenTaken = serialized_snapshot.whenTaken; snapshot->lsn = serialized_snapshot.lsn; + snapshot->csn = 0; /* Copy XIDs, if present. */ if (serialized_snapshot.xcnt > 0)