From c02d471a4371a5a5c2d7d5a2bc72ae450b6c699a Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Thu, 10 Sep 2026 14:21:17 -0400
Subject: [PATCH v1] Make on-access pruning pin visibility map before locking
 heap page

b46e1e54d078 pinned the VM after acquiring a cleanup lock on the heap
page when on-access pruning. This was not correct, as pinning the VM may
require I/O. Pin the VM before acquiring the lock. This could mean
occasional unneeded pinning when the buffer is under contention, but
that should be rare.
---
 src/backend/access/heap/pruneheap.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index 29f4722b02d..54c69b69346 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -325,6 +325,14 @@ heap_page_prune_opt(Relation relation, Buffer buffer, Buffer *vmbuffer,
 		bool		record_free_space = false;
 		Size		freespace = 0;
 
+		/*
+		 * Pin the VM page before taking the heap cleanup lock. This may
+		 * occasionally lead to an unnecessary pin when the buffer is
+		 * contended, but the same VM page covers many heap pages, so there is
+		 * a good chance for the work to be reusable.
+		 */
+		visibilitymap_pin(relation, BufferGetBlockNumber(buffer), vmbuffer);
+
 		/* OK, try to get exclusive buffer lock */
 		if (!ConditionalLockBufferForCleanup(buffer))
 			return;
@@ -340,9 +348,6 @@ heap_page_prune_opt(Relation relation, Buffer buffer, Buffer *vmbuffer,
 			PruneFreezeResult presult;
 			PruneFreezeParams params;
 
-			visibilitymap_pin(relation, BufferGetBlockNumber(buffer),
-							  vmbuffer);
-
 			params.relation = relation;
 			params.buffer = buffer;
 			params.vmbuffer = *vmbuffer;
-- 
2.43.0

