From 3064f77620653b9cd0faf07f43c975449612c8b3 Mon Sep 17 00:00:00 2001
From: jcoleman <jtc331@gmail.com>
Date: Fri, 2 Jun 2023 10:01:06 -0400
Subject: [PATCH v1 1/2] Allow getting lock before calling
 heap_page_prune_opt()

---
 src/backend/access/heap/heapam.c         |  2 +-
 src/backend/access/heap/heapam_handler.c |  4 ++--
 src/backend/access/heap/pruneheap.c      | 10 ++++++----
 src/include/access/heapam.h              |  2 +-
 4 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 7ed72abe59..51f645dda0 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -415,7 +415,7 @@ heapgetpage(TableScanDesc sscan, BlockNumber block)
 	/*
 	 * Prune and repair fragmentation for the whole page, if possible.
 	 */
-	heap_page_prune_opt(scan->rs_base.rs_rd, buffer);
+	heap_page_prune_opt(scan->rs_base.rs_rd, buffer, false);
 
 	/*
 	 * We must hold share lock on the buffer content while examining tuple
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index 646135cc21..b1be2e1897 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -135,7 +135,7 @@ heapam_index_fetch_tuple(struct IndexFetchTableData *scan,
 		 * Prune page, but only if we weren't already on this page
 		 */
 		if (prev_buf != hscan->xs_cbuf)
-			heap_page_prune_opt(hscan->xs_base.rel, hscan->xs_cbuf);
+			heap_page_prune_opt(hscan->xs_base.rel, hscan->xs_cbuf, false);
 	}
 
 	/* Obtain share-lock on the buffer so we can examine visibility */
@@ -2157,7 +2157,7 @@ heapam_scan_bitmap_next_block(TableScanDesc scan,
 	/*
 	 * Prune and repair fragmentation for the whole page, if possible.
 	 */
-	heap_page_prune_opt(scan->rs_rd, buffer);
+	heap_page_prune_opt(scan->rs_rd, buffer, false);
 
 	/*
 	 * We must hold share lock on the buffer content while examining tuple
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index 47b9e20915..af052f94af 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -102,10 +102,11 @@ static void page_verify_redirects(Page page);
  * Note: this is called quite often.  It's important that it fall out quickly
  * if there's not any use in pruning.
  *
- * Caller must have pin on the buffer, and must *not* have a lock on it.
+ * Caller must have pin on the buffer, and must either have an exclusive lock
+ * (and pass already_locked = true) or not have a lock on it.
  */
 void
-heap_page_prune_opt(Relation relation, Buffer buffer)
+heap_page_prune_opt(Relation relation, Buffer buffer, bool already_locked)
 {
 	Page		page = BufferGetPage(buffer);
 	TransactionId prune_xid;
@@ -191,8 +192,9 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
 
 	if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree)
 	{
-		/* OK, try to get exclusive buffer lock */
-		if (!ConditionalLockBufferForCleanup(buffer))
+		/* OK, try to get exclusive buffer lock if necessary */
+		if ((!already_locked && !ConditionalLockBufferForCleanup(buffer)) ||
+				(already_locked && !IsBufferCleanupOK(buffer)))
 			return;
 
 		/*
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index faf5026519..d72b476920 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -283,7 +283,7 @@ extern TransactionId heap_index_delete_tuples(Relation rel,
 
 /* in heap/pruneheap.c */
 struct GlobalVisState;
-extern void heap_page_prune_opt(Relation relation, Buffer buffer);
+extern void	heap_page_prune_opt(Relation relation, Buffer buffer, bool already_locked);
 extern int	heap_page_prune(Relation relation, Buffer buffer,
 							struct GlobalVisState *vistest,
 							TransactionId old_snap_xmin,
-- 
2.39.2 (Apple Git-143)

