postgres.git / summary / log / commit / refs

commit    8a6a1fe07e062911f6bbcb395b673931cada1ccd
Author:   Michael Paquier <michael@paquier.xyz>
Date:     Mon Oct 04 05:06:03 2021 +0000
First released in: 15.0, 9.6.24, 10.19, 11.14, 12.9, 13.5, 14.1

    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


src/backend/access/transam/xlog.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 3e462816c1a..26b3d381788 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -7915,13 +7915,6 @@ StartupXLOG(void) /* Reload shared-memory state for prepared transactions */ RecoverPreparedTransactions(); - /* - * Shutdown the recovery environment. This must occur after - * RecoverPreparedTransactions(), see notes for lock_twophase_recover() - */ - if (standbyState != STANDBY_DISABLED) - ShutdownRecoveryTransactionEnvironment(); - /* Shut down xlogreader */ if (readFile >= 0) { @@ -7970,6 +7963,18 @@ StartupXLOG(void) UpdateControlFile(); LWLockRelease(ControlFileLock); + /* + * Shutdown the recovery environment. This must occur after + * RecoverPreparedTransactions() (see notes in lock_twophase_recover()) + * and after switching SharedRecoveryState to RECOVERY_STATE_DONE so as + * any session building a snapshot will not rely on KnownAssignedXids as + * RecoveryInProgress() would return false at this stage. This is + * particularly critical for prepared 2PC transactions, that would still + * need to be included in snapshots once recovery has ended. + */ + if (standbyState != STANDBY_DISABLED) + ShutdownRecoveryTransactionEnvironment(); + /* * If there were cascading standby servers connected to us, nudge any wal * sender processes to notice that we've been promoted. [parent: e323630cdd3c]