postgres.git / summary / log / commit / refs

commit    e323d9df002debb103a58ba2479368c46804a9b6
Author:   Amit Kapila <akapila@postgresql.org>
Date:     Mon May 19 05:34:39 2025 +0000
First released in: 18.0, 13.22, 14.19, 15.14, 16.10, 17.6

    Don't retreat slot's confirmed_flush LSN.
    
    Prevent moving the confirmed_flush backwards, as this could lead to data
    duplication issues caused by replicating already replicated changes.
    
    This can happen when a client acknowledges an LSN it doesn't have to do
    anything for, and thus didn't store persistently. After a restart, the
    client can send the prior LSN that it stored persistently as an
    acknowledgement, but we need to ignore such an LSN to avoid retreating
    confirm_flush LSN.
    
    Diagnosed-by: Zhijie Hou <houzj.fnst@fujitsu.com>
    Author: shveta malik <shveta.malik@gmail.com>
    Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
    Reviewed-by: Dilip Kumar <dilipbalaut@gmail.com>
    Tested-by: Nisha Moond <nisha.moond412@gmail.com>
    Backpatch-through: 13
    Discussion: https://postgr.es/m/CAJpy0uDZ29P=BYB1JDWMCh-6wXaNqMwG1u1mB4=10Ly0x7HhwQ@mail.gmail.com
    Discussion: https://postgr.es/m/OS0PR01MB57164AB5716AF2E477D53F6F9489A@OS0PR01MB5716.jpnprd01.prod.outlook.com


src/backend/replication/logical/logical.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c index 6f1b3702470..08e38c29fa6 100644 --- a/src/backend/replication/logical/logical.c +++ b/src/backend/replication/logical/logical.c @@ -1037,7 +1037,19 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn) SpinLockAcquire(&MyReplicationSlot->mutex); - MyReplicationSlot->data.confirmed_flush = lsn; + /* + * Prevent moving the confirmed_flush backwards, as this could lead to + * data duplication issues caused by replicating already replicated + * changes. + * + * This can happen when a client acknowledges an LSN it doesn't have + * to do anything for, and thus didn't store persistently. After a + * restart, the client can send the prior LSN that it stored + * persistently as an acknowledgement, but we need to ignore such an + * LSN. See similar case handling in CreateDecodingContext. + */ + if (lsn > MyReplicationSlot->data.confirmed_flush) + MyReplicationSlot->data.confirmed_flush = lsn; /* if we're past the location required for bumping xmin, do so */ if (MyReplicationSlot->candidate_xmin_lsn != InvalidXLogRecPtr && @@ -1102,7 +1114,14 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn) else { SpinLockAcquire(&MyReplicationSlot->mutex); - MyReplicationSlot->data.confirmed_flush = lsn; + + /* + * Prevent moving the confirmed_flush backwards. See comments above + * for the details. + */ + if (lsn > MyReplicationSlot->data.confirmed_flush) + MyReplicationSlot->data.confirmed_flush = lsn; + SpinLockRelease(&MyReplicationSlot->mutex); } } [parent: 9bc2d37ccaab]