From dfa89aba06742428fe56a263a9236b862b14e34b Mon Sep 17 00:00:00 2001 From: Satya Narlapuram Date: Mon, 27 Apr 2026 08:17:42 +0000 Subject: [PATCH] Fix apply worker busy loop when subscription max_retention_duration is zero When a subscription has retain_dead_tuples enabled with maxretention set to zero (unlimited retention), adjust_xid_advance_interval() caps xid_advance_interval to Min(interval, maxretention). Since maxretention is zero, this always collapses the interval to zero milliseconds. A zero internal makes TimestampDifferenceExceeds(last_time, now, 0) always true in get_candidate_xid(). This causes the apply worker to call GetOldestActiveTransactionId() on every single WAL message. This results in a huge number of ProcArrayLock acquisitions under moderate write load. Fix by adding a maxretention > 0 guard to the cap. When maxretention is zero, the exponential back-off in adjust_xid_advance_interval() now works correctly, growing the interval from 100 ms toward the 180 s ceiling. --- src/backend/replication/logical/worker.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c index 9f2a16b1..dd6fc38a 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -4997,9 +4997,10 @@ adjust_xid_advance_interval(RetainDeadTuplesData *rdt_data, bool new_xid_found) /* * Ensure the wait time remains within the maximum retention time limit - * when retention is active. + * when retention is active. Skip this cap when maxretention is zero. */ - if (MySubscription->retentionactive) + if (MySubscription->retentionactive && MySubscription->maxretention > 0) rdt_data->xid_advance_interval = Min(rdt_data->xid_advance_interval, MySubscription->maxretention); } -- 2.43.0