diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index df5e2f99413..9ad3b3c962a 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -6449,6 +6449,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 db917f8aa8d..0f8238a9049 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -435,6 +435,28 @@ ProcArrayClearTransaction(PGPROC *proc) proc->subxids.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 * @@ -523,7 +545,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. */ /* @@ -595,20 +620,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; @@ -667,6 +704,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 efe40c9ca81..923fe4917db 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -28,6 +28,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);