Skip to content

Commit 8a42379

Browse files
committed
Fix snapshot builds during promotion of hot standby node with 2PC
Some specific logic is done at the end of recovery when involving 2PC transactions: 1) Call RecoverPreparedTransactions(), to recover the state of 2PC transactions into memory (re-acquire locks, etc.). 2) ShutdownRecoveryTransactionEnvironment(), to move back to normal operations, mainly cleaning up recovery locks and KnownAssignedXids (including any 2PC transaction tracked previously). 3) Switch XLogCtl->SharedRecoveryState to RECOVERY_STATE_DONE, which is the tipping point for any process calling RecoveryInProgress() to check if the cluster is still in recovery or not. Any snapshot taken between steps 2) and 3) would be empty, causing any transaction relying on a snapshot at this point to potentially corrupt data as there could still be some 2PC transactions to track, with RecentXmin moving backwards on successive calls to GetSnapshotData() in the same transaction. As SharedRecoveryState is the point to take into account to know if it is safe to discard KnownAssignedXids, this commit moves step 2) after step 3), so as we can never finish with empty snapshots. This exists since the introduction of hot standby, so backpatch all the way down. The window with incorrect snapshots is extremely small, but I have seen it when running 023_pitr_prepared_xact.pl, as did buildfarm member fairywren. Thomas Munro also found it independently. Special thanks to Andres Freund for taking the time to analyze this issue. Reported-by: Thomas Munro, Michael Paquier Analyzed-by: Andres Freund Discussion: https://postgr.es/m/20210422203603.fdnh3fu2mmfp2iov@alap3.anarazel.de Backpatch-through: 9.6
1 parent a0558cf commit 8a42379

File tree

1 file changed

+12
-7
lines changed
  • src/backend/access/transam

1 file changed

+12
-7
lines changed

src/backend/access/transam/xlog.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8111,13 +8111,6 @@ StartupXLOG(void)
81118111
/* Reload shared-memory state for prepared transactions */
81128112
RecoverPreparedTransactions();
81138113

8114-
/*
8115-
* Shutdown the recovery environment. This must occur after
8116-
* RecoverPreparedTransactions(), see notes for lock_twophase_recover()
8117-
*/
8118-
if (standbyState != STANDBY_DISABLED)
8119-
ShutdownRecoveryTransactionEnvironment();
8120-
81218114
/* Shut down xlogreader */
81228115
if (readFile >= 0)
81238116
{
@@ -8165,6 +8158,18 @@ StartupXLOG(void)
81658158
UpdateControlFile();
81668159
LWLockRelease(ControlFileLock);
81678160

8161+
/*
8162+
* Shutdown the recovery environment. This must occur after
8163+
* RecoverPreparedTransactions() (see notes in lock_twophase_recover())
8164+
* and after switching SharedRecoveryState to RECOVERY_STATE_DONE so as
8165+
* any session building a snapshot will not rely on KnownAssignedXids as
8166+
* RecoveryInProgress() would return false at this stage. This is
8167+
* particularly critical for prepared 2PC transactions, that would still
8168+
* need to be included in snapshots once recovery has ended.
8169+
*/
8170+
if (standbyState != STANDBY_DISABLED)
8171+
ShutdownRecoveryTransactionEnvironment();
8172+
81688173
/*
81698174
* If there were cascading standby servers connected to us, nudge any wal
81708175
* sender processes to notice that we've been promoted.

0 commit comments

Comments
 (0)