diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 42fa6aa7e9c3c0b7da34f42da27ba5fd1b297cf5..8243ea62d7834d79d07406ae3904eaf724dd6436 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -6692,6 +6692,9 @@ StartupXLOG(void) oldestActiveXID = checkPoint.oldestActiveXid; Assert(TransactionIdIsValid(oldestActiveXID)); + /* Tell procarray about the range of xids it has to deal with */ + ProcArrayInitRecovery(ShmemVariableCache->nextXid); + /* * Startup commit log and subtrans only. Other SLRUs are not * maintained during recovery and need not be started yet. diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 371b1045a13d20c0efcc69a18fc16f6e6d505af7..6cc115090b74375b21dbea703003b4ba1325f6fe 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -468,6 +468,28 @@ ProcArrayClearTransaction(PGPROC *proc) pgxact->overflowed = false; } +/* + * ProcArrayInitRecovery -- initialize recovery xid mgmt environment + * + * Remember up to where the startup process initialized the CLOG and subtrans + * so we can ensure its initialized gaplessly up to the point where necessary + * while in recovery. + */ +void +ProcArrayInitRecovery(TransactionId initializedUptoXID) +{ + Assert(standbyState == STANDBY_INITIALIZED); + Assert(TransactionIdIsNormal(initializedUptoXID)); + + /* + * we set latestObservedXid to the xid SUBTRANS has been initialized upto + * so we can extend it from that point onwards when we reach a consistent + * state in ProcArrayApplyRecoveryInfo(). + */ + latestObservedXid = initializedUptoXID; + TransactionIdRetreat(latestObservedXid); +} + /* * ProcArrayApplyRecoveryInfo -- apply recovery info about xids * @@ -556,7 +578,10 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running) Assert(standbyState == STANDBY_INITIALIZED); /* - * OK, we need to initialise from the RunningTransactionsData record + * OK, we need to initialise from the RunningTransactionsData record. + * + * NB: this can be reached at least twice, so make sure new code can deal + * with that. */ /* @@ -628,20 +653,32 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running) pfree(xids); /* + * latestObservedXid is set to the the point where SUBTRANS was started up + * to, initialize subtrans from thereon, up to nextXid - 1. + */ + Assert(TransactionIdIsNormal(latestObservedXid)); + while (TransactionIdPrecedes(latestObservedXid, running->nextXid)) + { + ExtendCLOG(latestObservedXid); + ExtendSUBTRANS(latestObservedXid); + + TransactionIdAdvance(latestObservedXid); + } + + /* ---------- * Now we've got the running xids we need to set the global values that * are used to track snapshots as they evolve further. * - * - latestCompletedXid which will be the xmax for snapshots - - * lastOverflowedXid which shows whether snapshots overflow - nextXid + * - latestCompletedXid which will be the xmax for snapshots + * - lastOverflowedXid which shows whether snapshots overflow + * - nextXid * * If the snapshot overflowed, then we still initialise with what we know, * but the recovery snapshot isn't fully valid yet because we know there * are some subxids missing. We don't know the specific subxids that are * missing, so conservatively assume the last one is latestObservedXid. + * ---------- */ - latestObservedXid = running->nextXid; - TransactionIdRetreat(latestObservedXid); - if (running->subxid_overflow) { standbyState = STANDBY_SNAPSHOT_PENDING; @@ -711,6 +748,10 @@ ProcArrayApplyXidAssignment(TransactionId topxid, Assert(standbyState >= STANDBY_INITIALIZED); + /* can't do anything useful unless we have more state setup */ + if (standbyState == STANDBY_INITIALIZED) + return; + max_xid = TransactionIdLatest(topxid, nsubxids, subxids); /* diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index 5b4cab926f58dda816b6b9dfa9b93fedb6e33fce..1819be74f8ce95aed81087dce4317fe6a770c76f 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -26,6 +26,7 @@ extern void ProcArrayRemove(PGPROC *proc, TransactionId latestXid); extern void ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid); extern void ProcArrayClearTransaction(PGPROC *proc); +extern void ProcArrayInitRecovery(TransactionId initializedUptoXID); extern void ProcArrayApplyRecoveryInfo(RunningTransactions running); extern void ProcArrayApplyXidAssignment(TransactionId topxid, int nsubxids, TransactionId *subxids);