From 3291d70db1523fca0fb9226543fb02e647d675f2 Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Mon, 23 Feb 2026 18:13:27 -0500
Subject: [PATCH v0 01/17] Save prune cycles by consistently clearing prune
 hints on all-visible pages

All-visible pages can't contain prunable tuples. We already clear the prune hint
(pd_prune_xid) during pruning of all-visible pages,
but we were not doing so in vacuum phase three, nor initializing it for
all-frozen pages created by COPY FREEZE, and we were not clearing it on
standbys.

Because page hints are not WAL-logged, pages on a standby carry stale
pd_prune_xid values. After promotion, that stale hint triggers
unnecessary on-access pruning.

Fix this by clearing the prune hint everywhere we currently mark a heap
page all-visible. Clearing it when setting PD_ALL_VISIBLE ensures no
extra overhead.
---
 src/backend/access/heap/heapam.c      | 1 +
 src/backend/access/heap/heapam_xlog.c | 7 +++++++
 src/backend/access/heap/vacuumlazy.c  | 2 ++
 3 files changed, 10 insertions(+)

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 98d53caeea8..d1e9eb3e2ca 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2577,6 +2577,7 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
 		else if (all_frozen_set)
 		{
 			PageSetAllVisible(page);
+			PageClearPrunable(page);
 			visibilitymap_set_vmbits(BufferGetBlockNumber(buffer),
 									 vmbuffer,
 									 VISIBILITYMAP_ALL_VISIBLE |
diff --git a/src/backend/access/heap/heapam_xlog.c b/src/backend/access/heap/heapam_xlog.c
index f765345e9e4..6d39a5fff7c 100644
--- a/src/backend/access/heap/heapam_xlog.c
+++ b/src/backend/access/heap/heapam_xlog.c
@@ -164,7 +164,10 @@ heap_xlog_prune_freeze(XLogReaderState *record)
 		 * modification would fail to clear the visibility map bit.
 		 */
 		if (vmflags & VISIBILITYMAP_VALID_BITS)
+		{
 			PageSetAllVisible(page);
+			PageClearPrunable(page);
+		}
 
 		MarkBufferDirty(buffer);
 
@@ -305,6 +308,7 @@ heap_xlog_visible(XLogReaderState *record)
 		page = BufferGetPage(buffer);
 
 		PageSetAllVisible(page);
+		PageClearPrunable(page);
 
 		if (XLogHintBitIsNeeded())
 			PageSetLSN(page, lsn);
@@ -734,7 +738,10 @@ heap_xlog_multi_insert(XLogReaderState *record)
 
 		/* XLH_INSERT_ALL_FROZEN_SET implies that all tuples are visible */
 		if (xlrec->flags & XLH_INSERT_ALL_FROZEN_SET)
+		{
 			PageSetAllVisible(page);
+			PageClearPrunable(page);
+		}
 
 		MarkBufferDirty(buffer);
 	}
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index dcbaf49401b..88bcbf55ed7 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -1932,6 +1932,7 @@ lazy_scan_new_or_empty(LVRelState *vacrel, Buffer buf, BlockNumber blkno,
 				log_newpage_buffer(buf, true);
 
 			PageSetAllVisible(page);
+			PageClearPrunable(page);
 			visibilitymap_set(vacrel->rel, blkno, buf,
 							  InvalidXLogRecPtr,
 							  vmbuffer, InvalidTransactionId,
@@ -2943,6 +2944,7 @@ lazy_vacuum_heap_page(LVRelState *vacrel, BlockNumber blkno, Buffer buffer,
 		 * set PD_ALL_VISIBLE.
 		 */
 		PageSetAllVisible(page);
+		PageClearPrunable(page);
 		visibilitymap_set_vmbits(blkno,
 								 vmbuffer, vmflags,
 								 vacrel->rel->rd_locator);
-- 
2.43.0

