From 41b2088e4e781cb0f403d6429a05559543831b7a Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Fri, 18 Sep 2026 15:45:03 -0400 Subject: [PATCH v3 1/2] Retain newest live xid as prune hint after visibility horizon rejection When live tuples are too young to mark a page all-visible, pruning can clear pd_prune_xid and prevent on-access retries after the horizon advances. Instead, retain the newest live xmin as a retry hint, unless LP_DEAD items remain. Remaining LP_DEAD items prevent setting the VM until VACUUM removes them. VACUUM also records this hint. Setting a previously invalid pd_prune_xid can dirty an otherwise unchanged page and emit a heap FPI when hint logging is required; retaining an existing hint can avoid dirtying the page just to clear it. Reviewed-by: Andrey Borodin Discussion: https://postgr.es/m/CAAKRu_amj7qLF4c=9ijd=708Fu2G8gg-2EqwBu=aCdAHU2sPHg@mail.gmail.com --- 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 98fba4bb7c1..b541c6d709b 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, unless LP_DEAD items remain. + */ + if (prstate.lpdead_items == 0) + { + Assert(!TransactionIdIsValid(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