RE: Conflict detection for update_deleted in logical replication
Zhijie Hou (Fujitsu) <houzj.fnst@fujitsu.com>
Attachments
- v47-0004-Support-the-conflict-detection-for-update_delete.patch (application/octet-stream) patch v47-0004
- v47-0001-Preserve-conflict-relevant-data-during-logical-r.patch (application/octet-stream) patch v47-0001
- v47-0005-Allow-altering-retain_conflict_info-for-enabled-.patch (application/octet-stream) patch v47-0005
- v47-0002-Introduce-a-new-GUC-max_conflict_retention_durat.patch (application/octet-stream) patch v47-0002
- v47-0003-Re-create-the-replication-slot-if-the-conflict-r.patch (application/octet-stream) patch v47-0003
On Wed, Jul 2, 2025 at 3:28 PM Hou, Zhijie wrote:
> Kindly use the latest patch set for performance testing.
During testing, we observed a limitation in cascading logical replication
setups, such as (A -> B -> C). When retain_conflict_info is enabled on Node C,
it may not retain information necessary for conflict detection when applying
changes originally replicated from Node A. This happens because Node C only
waits for locally originated changes on Node B to be applied before advancing
the non-removable transaction ID.
For example, Consider a logical replication setup as mentioned above : A -> B -> C.
- All three nodes have a table t1 with two tuples (1,1) (2,2).
- Node B subscribed to all changes of t1 from Node A
- Node-C subscribed to all changes from Node B.
- Subscriptions use the default origin=ANY, as this is not a bidirectional
setup.
Now, consider two concurrent operations:
- @9:00 Node A - UPDATE (1,1) -> (1,11)
- @9:02 Node C - DELETE (1,1)
Assume a slight delay at Node B before it applies the update from Node A.
@9:03 Node C - advances the non-removable XID because it sees no concurrent
transactions from Node B. It is unaware of Node A’s concurrent update.
@9:04 Node B - receives Node A's UPDATE and applies (1,1) -> (1,11)
t1 has tuples : (1,11), (2,2)
@9:05 Node C - receives the UPDATE (1,1) -> (1,11)
- As conflict slot’s xmin is advanced, the deleted tuple may already have
been removed.
- Conflict resolution fails to detect update_deleted and instead raises
update_missing.
Note that, as per decoding logic Node C sees the commit timestamp of the update
as 9:00 (origin commit_ts from Node A), not 9:04 (commit time on Node B). In
this case, since the UPDATE's timestamp is earlier than the DELETE, Node C
should ideally detect an update_deleted conflict. However, it cannot, because
it no longer retains the deleted tuple.
Even if Node C attempts to retrieve the latest WAL position from Node A, Node C
doesn't maintain any LSN which we could use to compare with it.
This scenario is similar to another restriction in the patch where
retain_conflict_info is not supported if the publisher is also a physical
standby, as the required transaction information from the original primary is
unavailable. Moreover, this limitation is relevant only when the subscription
origin option is set to ANY, as only in that case changes from other origins
can be replicated. Since retain_conflict_info is primarily useful for conflict
detection in bidirectional clusters where the origin option is set to NONE,
this limitation appears acceptable.
Given these findings, to help users avoid unintended configurations, we plan to
issue a warning in scenarios where replicated changes may include origins other
than the direct publisher, similar to the existing checks in the
check_publications_origin() function.
Here is the latest patch that implements the warning and documents
this case. Only 0001 is modified for this.
A big thanks to Nisha for invaluable assistance in identifying this
case and preparing the analysis for it.
Best Regards,
Hou zj
Commits
-
Fix intermittent BF failures in 035_conflicts.
- 0f42206531b3 19 (unreleased) landed
-
Resume conflict-relevant data retention automatically.
- 0d48d393d465 19 (unreleased) landed
-
Fix intermittent test failure introduced in 6456c6e2c4.
- 01d793698f59 19 (unreleased) landed
-
Fix Coverity issue reported in commit a850be2fe.
- 5ac3c1ac22cb 19 (unreleased) landed
-
Add test to prevent premature removal of conflict-relevant data.
- 6456c6e2c4ad 19 (unreleased) landed
-
Post-commit review fixes for 228c370868.
- 1f7e9ba3ac4e 19 (unreleased) landed
-
Add max_retention_duration option to subscriptions.
- a850be2fe653 19 (unreleased) landed
-
Detect and report update_deleted conflicts.
- fd5a1a0c3e56 19 (unreleased) landed
-
Preserve conflict-relevant data during logical replication.
- 228c37086855 19 (unreleased) landed
-
Integrate FullTransactionIds deeper into two-phase code
- 62a17a92833d 19 (unreleased) cited
-
Improve checks for GUC recovery_target_timeline
- fd7d7b719137 19 (unreleased) cited
-
Prevent excessive delays before launching new logrep workers.
- fd519419c948 18.0 cited
-
Keep WAL segments by slot's last saved restart LSN
- ca307d5cec90 18.0 cited
-
Rework some code handling pg_subscription data in psql and pg_dump
- 08691ea958c2 18.0 cited
-
Use generateClonedIndexStmt to propagate CREATE INDEX to partitions.
- 68dfecbef210 18.0 cited