v3-0001-Fix-assertion-failure-when-decoding-synced-two-ph.patch
application/octet-stream
Filename: v3-0001-Fix-assertion-failure-when-decoding-synced-two-ph.patch
Type: application/octet-stream
Part: 1
Patch
Format: format-patch
Series: patch v3-0001
Subject: Fix assertion failure when decoding synced two-phase enabled slots.
| File | + | − |
|---|---|---|
| src/backend/replication/logical/slotsync.c | 24 | 12 |
From 777078845255f6c663ace970d7642bbee7e357c8 Mon Sep 17 00:00:00 2001
From: Zhijie Hou <houzj.fnst@cn.fujitsu.com>
Date: Mon, 28 Apr 2025 14:52:00 +0800
Subject: [PATCH v3] Fix assertion failure when decoding synced two-phase
enabled slots.
Current, during slot synchronization, it skips updating the confirmed_lsn if it
detects that the catalog_xmin or restart_lsn of the synced slot has already
surpassed those of the remote slot on the primary. This behavior poses a
problem when two-phase commit is enabled on the remote slot. The lack of
synchronization between the latest confirmed_lsn and two_phase_at may result in
transactions prepared between the old confirmed_lsn and two_phase_at being
unexpectedly decoded and sent to subscribers following a promotion.
To fix this, when catalog_xmin or restart_lsn of the synced slot are ahead,
we postpone syncing the slot configurations including two_phase_at
until the remote slot's restart_lsn and catalog_xmin are ahead.
---
src/backend/replication/logical/slotsync.c | 36 ++++++++++++++--------
1 file changed, 24 insertions(+), 12 deletions(-)
diff --git a/src/backend/replication/logical/slotsync.c b/src/backend/replication/logical/slotsync.c
index e22d41891e6..dd1c725a670 100644
--- a/src/backend/replication/logical/slotsync.c
+++ b/src/backend/replication/logical/slotsync.c
@@ -196,14 +196,14 @@ update_local_synced_slot(RemoteSlot *remote_slot, Oid remote_dbid,
* restart_lsn or the initial xmin_horizon computed for the local slot
* is ahead of the remote slot.
*
- * If the slot is persistent, restart_lsn of the synced slot could
- * still be ahead of the remote slot. Since we use slot advance
- * functionality to keep snapbuild/slot updated, it is possible that
- * the restart_lsn is advanced to a later position than it has on the
- * primary. This can happen when slot advancing machinery finds
- * running xacts record after reaching the consistent state at a later
- * point than the primary where it serializes the snapshot and updates
- * the restart_lsn.
+ * If the slot is persistent, both restart_lsn and catalog_xmin of the
+ * synced slot could still be ahead of the remote slot. Since we use
+ * slot advance functionality to keep snapbuild/slot updated, it is
+ * possible that the restart_lsn and catalog_xmin are advanced to a
+ * later position than it has on the primary. This can happen when
+ * slot advancing machinery finds running xacts record after reaching
+ * the consistent state at a later point than the primary where it
+ * serializes the snapshot and updates the restart_lsn.
*
* We LOG the message if the slot is temporary as it can help the user
* to understand why the slot is not sync-ready. In the case of a
@@ -221,16 +221,28 @@ update_local_synced_slot(RemoteSlot *remote_slot, Oid remote_dbid,
if (remote_slot_precedes)
*remote_slot_precedes = true;
+
+ /*
+ * Return immediately without updating the configuration. This is
+ * crucial when two-phase commit is enabled on the remote slot. In
+ * this scenario, syncing only two_phase_at, without the latest
+ * confirmed_lsn, could cause transactions between the old
+ * confirmed_lsn and two_phase_at to be unexpectedly decoded and sent
+ * to the subscriber following a promotion. Therefore, we delay
+ * syncing both the latest confirmed_lsn and two_phase_at until the
+ * remote slot's restart_lsn and catalog_xmin are ahead.
+ */
+ return false;
}
/*
* Attempt to sync LSNs and xmins only if remote slot is ahead of local
* slot.
*/
- else if (remote_slot->confirmed_lsn > slot->data.confirmed_flush ||
- remote_slot->restart_lsn > slot->data.restart_lsn ||
- TransactionIdFollows(remote_slot->catalog_xmin,
- slot->data.catalog_xmin))
+ if (remote_slot->confirmed_lsn > slot->data.confirmed_flush ||
+ remote_slot->restart_lsn > slot->data.restart_lsn ||
+ TransactionIdFollows(remote_slot->catalog_xmin,
+ slot->data.catalog_xmin))
{
/*
* We can't directly copy the remote slot's LSN or xmin unless there
--
2.31.1