postgres.git / summary / log / commit / refs

commit    d9ade6f2d4cdf95097bbb927f575611b525a2646
Author:   Michael Paquier <michael@paquier.xyz>
Date:     Sun Dec 29 23:06:43 2024 +0000
First released in: master (reverted before release), REL_13_STABLE (reverted before release), REL_14_STABLE (reverted before release), REL_15_STABLE (reverted before release), REL_16_STABLE (reverted before release), REL_17_STABLE (reverted before release)
Reverted by: 4d6d7bdc0642 (in 13.19), 060f9f5ea537 (in 14.16), 42c900d31e57 (in 15.11), 4d72357c40ee (in 16.7), d1bf86a62211 (in 17.3), a6c70f68cdeb (in 18.0)

    Fix handling of orphaned 2PC files in the future at recovery
    
    Before 728bd991c3c4, that has improved the support for 2PC files during
    recovery, the initial logic scanning files in pg_twophase was done so as
    files in the future of the transaction ID horizon were checked first,
    followed by a check if a transaction ID is aborted or committed which
    could involve a pg_xact lookup.  After this commit, these checks have
    been done in reverse order.
    
    Files detected as in the future do not have a state that can be checked
    in pg_xact, hence this caused recovery to fail abruptly should an
    orphaned 2PC file in the future of the transaction ID horizon exist in
    pg_twophase at the beginning of recovery.
    
    A test is added to check for this scenario, using an empty 2PC with a
    transaction ID large enough to be in the future when running the test.
    This test is added in 16 and older versions for now.  17 and newer
    versions are impacted by a second bug caused by the addition of the
    epoch in the 2PC file names.  An equivalent test will be added in these
    branches in a follow-up commit, once the second set of issues reported
    are fixed.
    
    Author: Vitaly Davydov, Michael Paquier
    Discussion: https://postgr.es/m/11e597-676ab680-8d-374f23c0@145466129
    Backpatch-through: 13


src/backend/access/transam/twophase.c | 16 ++++++++-------- src/test/recovery/t/009_twophase.pl | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index 8c5e5913df5..238f29ce7ed 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -2185,40 +2185,40 @@ ProcessTwoPhaseBuffer(TransactionId xid, if (!fromdisk) Assert(prepare_start_lsn != InvalidXLogRecPtr); - /* Already processed? */ - if (TransactionIdDidCommit(xid) || TransactionIdDidAbort(xid)) + /* Reject XID if too new */ + if (TransactionIdFollowsOrEquals(xid, origNextXid)) { if (fromdisk) { ereport(WARNING, - (errmsg("removing stale two-phase state file for transaction %u", + (errmsg("removing future two-phase state file for transaction %u", xid))); RemoveTwoPhaseFile(xid, true); } else { ereport(WARNING, - (errmsg("removing stale two-phase state from memory for transaction %u", + (errmsg("removing future two-phase state from memory for transaction %u", xid))); PrepareRedoRemove(xid, true); } return NULL; } - /* Reject XID if too new */ - if (TransactionIdFollowsOrEquals(xid, origNextXid)) + /* Already processed? */ + if (TransactionIdDidCommit(xid) || TransactionIdDidAbort(xid)) { if (fromdisk) { ereport(WARNING, - (errmsg("removing future two-phase state file for transaction %u", + (errmsg("removing stale two-phase state file for transaction %u", xid))); RemoveTwoPhaseFile(xid, true); } else { ereport(WARNING, - (errmsg("removing future two-phase state from memory for transaction %u", + (errmsg("removing stale two-phase state from memory for transaction %u", xid))); PrepareRedoRemove(xid, true); } diff --git a/src/test/recovery/t/009_twophase.pl b/src/test/recovery/t/009_twophase.pl index ad9b5371dd0..4417275cb22 100644 --- a/src/test/recovery/t/009_twophase.pl +++ b/src/test/recovery/t/009_twophase.pl @@ -528,4 +528,27 @@ is( $psql_out, qq{27|issued to paris}, "Check expected t_009_tbl2 data on standby"); +############################################################################### +# Check handling of orphaned 2PC files at recovery. +############################################################################### + +$cur_primary->teardown_node; + +# Grab location in logs of primary +my $log_offset = -s $cur_primary->logfile; + +# Create a fake file with a transaction ID large enough to be in the future, +# then check that the primary is able to start and remove this file at +# recovery. + +my $future_2pc_file = $cur_primary->data_dir . '/pg_twophase/00FFFFFF'; +append_to_file $future_2pc_file, ""; + +$cur_primary->start; +$cur_primary->log_check( + "future two-phase file removed at recovery", + $log_offset, + log_like => + [qr/removing future two-phase state file for transaction 16777215/]); + done_testing(); [parent: 3d1ecc92a0d1]