From 54dbd9cbe68cbe7f9aa2a7c4d8f262b15410d3e6 Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Fri, 18 Sep 2026 15:45:03 -0400 Subject: [PATCH 4/4] Retain newest live xid as prune hint after visibility horizon rejection When a page contains committed live tuples that are not yet visible to all snapshots, pruning cannot mark it all-visible. These tuples do not contribute to new_prune_xid, so pruning can clear pd_prune_xid and prevent subsequent on-access scans from reconsidering the page after the horizon advances. Vacuum scans the page regardless of pd_prune_xid, so the only change to its behavior is that it may dirty the page to set pd_prune_xid when it otherwise wouldn't have. Record the newest live xmin as a retry hint when the visibility horizon prevents setting the VM. Preserve any earlier pruning opportunity already recorded so that dead tuples can still be reclaimed sooner. --- src/backend/access/heap/pruneheap.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c index 07ef563b874..4c8ddc4f743 100644 --- a/src/backend/access/heap/pruneheap.c +++ b/src/backend/access/heap/pruneheap.c @@ -1209,8 +1209,20 @@ heap_page_prune_and_freeze(PruneFreezeParams *params, GlobalVisTestXidConsideredRunning(prstate.vistest, prstate.newest_live_xid, true)) + { prstate.set_all_visible = prstate.set_all_frozen = false; + /* + * Preserve an opportunity to set the VM on-access once the newest + * live xmin is visible to everyone. Retain any earlier pruning + * opportunity already recorded, so that we can still reclaim dead + * tuples sooner. + */ + if (!TransactionIdIsValid(prstate.new_prune_xid) || + TransactionIdPrecedes(prstate.newest_live_xid, prstate.new_prune_xid)) + prstate.new_prune_xid = prstate.newest_live_xid; + } + /* * If checksums are enabled, calling heap_prune_satisfies_vacuum() while * checking tuple visibility information in prune_freeze_plan() may have -- 2.43.0