diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ac8521e0185512a9067cae31b5e6c7d7c8ab877c..47ecdac5fee18d76f25bd4a3c8ef4d1f270faa5d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -6117,6 +6117,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 7805213b31d710a1c0a89d2344225cc046091790..2979691301196485713ae6f111e9a0265b5c7905 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,6 +620,19 @@ 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. * @@ -606,10 +644,8 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running) * 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; @@ -669,6 +705,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 40734935b39fc9587d132031b4a13d0a7b9c0c68..bffe5f4a167d1bfe7e6683890b031919d0ca965d 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);