RE: Conflict detection for update_deleted in logical replication

Zhijie Hou (Fujitsu) <houzj.fnst@fujitsu.com>

From: "Zhijie Hou (Fujitsu)" <houzj.fnst@fujitsu.com>
To: shveta malik <shveta.malik@gmail.com>
Cc: Amit Kapila <amit.kapila16@gmail.com>, Nisha Moond <nisha.moond412@gmail.com>, Masahiko Sawada <sawada.mshk@gmail.com>, "Hayato Kuroda (Fujitsu)" <kuroda.hayato@fujitsu.com>, pgsql-hackers <pgsql-hackers@postgresql.org>, vignesh C <vignesh21@gmail.com>, Dilip Kumar <dilipbalaut@gmail.com>
Date: 2025-09-10T03:39:00Z
Lists: pgsql-hackers
On Tuesday, September 9, 2025 5:17 PM shveta malik <shveta.malik@gmail.com> wrote:
> 
> On Tue, Sep 9, 2025 at 11:47 AM Zhijie Hou (Fujitsu) <houzj.fnst@fujitsu.com>
> wrote:
> >
> >
> > Here is V71 patch set which addressed above comments and [1].
> >
> 
> Thank You for the patches. Please find a few comments on 001:
> 
> 1)
> In compute_min_nonremovable_xid, when 'wait_for_xid' is true, we should
> have Assert(!worker->oldest_nonremovable_xid) to ensure it is always Invalid
> if reached here.

Added.

> 
> Or we can rewrite the current if-else-if code logic based on worker's oldest-xid
> as main criteria as that will be NULL in both the blocks:
> 
> if (!TransactionIdIsValid(nonremovable_xid))
> {
>   /* resume case */
>   if(wait_for_xid)
>     set worker's oldest-xid using slot's xmin
>   else
>   /* stop case */
>     return;
> }

I am personally not in favor this style because it adds more conditions, so I
did not change in this version.

> 
> 2)
> In stop_conflict_info_retention(), there may be a case where due to an ongoing
> transaction, it could not update retentionactive to false. But even in such cases,
> the function still sets oldest_nonremovable_xid to Invalid, which seems wrong.
> 
> 3)
> Similar in resume flow, it still sets wait_for_initial_xid=true even when it could
> not update retentionactive=true.

Right, I missed to return when the update fails. Fixed in this version.

> 
> 4)
> resume_conflict_info_retention():
> + /*
> + * Return if the launcher has not initialized oldest_nonremovable_xid.
> + *
> + */
> + if (!TransactionIdIsValid(nonremovable_xid))
> + return;
> 
> I think we should have
> 'Assert(MyLogicalRepWorker->wait_for_initial_xid)' before 'return'
> here.

Added.

Best Regards,
Hou zj

Commits

  1. Fix intermittent BF failures in 035_conflicts.

  2. Resume conflict-relevant data retention automatically.

  3. Fix intermittent test failure introduced in 6456c6e2c4.

  4. Fix Coverity issue reported in commit a850be2fe.

  5. Add test to prevent premature removal of conflict-relevant data.

  6. Post-commit review fixes for 228c370868.

  7. Add max_retention_duration option to subscriptions.

  8. Detect and report update_deleted conflicts.

  9. Preserve conflict-relevant data during logical replication.

  10. Integrate FullTransactionIds deeper into two-phase code

  11. Improve checks for GUC recovery_target_timeline

  12. Prevent excessive delays before launching new logrep workers.

  13. Keep WAL segments by slot's last saved restart LSN

  14. Rework some code handling pg_subscription data in psql and pg_dump

  15. Use generateClonedIndexStmt to propagate CREATE INDEX to partitions.