]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Don't retreat slot's confirmed_flush LSN.
authorAmit Kapila <akapila@postgresql.org>
Mon, 19 May 2025 06:25:55 +0000 (11:55 +0530)
committerAmit Kapila <akapila@postgresql.org>
Mon, 19 May 2025 06:25:55 +0000 (11:55 +0530)
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

index e941bb491d81dc16c1ba380044fb89c60cc082f0..97b6aa899ee109d5a9ad585b34554a4108a92114 100644 (file)
@@ -1847,7 +1847,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 &&
@@ -1912,7 +1924,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);
        }
 }