From 81b0875be30bd83452aa78756355fa4d3b481d7b Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Fri, 29 Mar 2024 19:43:09 -0400
Subject: [PATCH v10 06/10] Introduce PRUNE_DO_* actions

We will eventually take additional actions in heap_page_prune() at the
discretion of the caller. For now, introduce these PRUNE_DO_* macros and
turn mark_unused_now, a paramter to heap_page_prune(), into a PRUNE_DO_
action.
---
 src/backend/access/heap/pruneheap.c  | 51 ++++++++++++++--------------
 src/backend/access/heap/vacuumlazy.c | 11 ++++--
 src/include/access/heapam.h          | 13 ++++++-
 3 files changed, 46 insertions(+), 29 deletions(-)

diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index 159f847689..20d5ad7b80 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -29,10 +29,11 @@
 /* Working data for heap_page_prune and subroutines */
 typedef struct
 {
+	/* PRUNE_DO_* arguments */
+	uint8		actions;
+
 	/* tuple visibility test, initialized for the relation */
 	GlobalVisState *vistest;
-	/* whether or not dead items can be set LP_UNUSED during pruning */
-	bool		mark_unused_now;
 
 	TransactionId new_prune_xid;	/* new prune hint value for page */
 	TransactionId snapshotConflictHorizon;	/* latest xid removed */
@@ -167,11 +168,12 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
 			PruneResult presult;
 
 			/*
-			 * For now, pass mark_unused_now as false regardless of whether or
-			 * not the relation has indexes, since we cannot safely determine
-			 * that during on-access pruning with the current implementation.
+			 * For now, do not set PRUNE_DO_MARK_UNUSED_NOW regardless of
+			 * whether or not the relation has indexes, since we cannot safely
+			 * determine that during on-access pruning with the current
+			 * implementation.
 			 */
-			heap_page_prune(relation, buffer, vistest, false,
+			heap_page_prune(relation, buffer, vistest, 0,
 							&presult, PRUNE_ON_ACCESS, NULL);
 
 			/*
@@ -216,8 +218,7 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
  * vistest is used to distinguish whether tuples are DEAD or RECENTLY_DEAD
  * (see heap_prune_satisfies_vacuum).
  *
- * mark_unused_now indicates whether or not dead items can be set LP_UNUSED
- * during pruning.
+ * actions are the pruning actions that heap_page_prune() should take.
  *
  * presult contains output parameters needed by callers such as the number of
  * tuples removed and the number of line pointers newly marked LP_DEAD.
@@ -232,7 +233,7 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
 void
 heap_page_prune(Relation relation, Buffer buffer,
 				GlobalVisState *vistest,
-				bool mark_unused_now,
+				uint8 actions,
 				PruneResult *presult,
 				PruneReason reason,
 				OffsetNumber *off_loc)
@@ -257,7 +258,7 @@ heap_page_prune(Relation relation, Buffer buffer,
 	 */
 	prstate.new_prune_xid = InvalidTransactionId;
 	prstate.vistest = vistest;
-	prstate.mark_unused_now = mark_unused_now;
+	prstate.actions = actions;
 	prstate.snapshotConflictHorizon = InvalidTransactionId;
 	prstate.nredirected = prstate.ndead = prstate.nunused = 0;
 	memset(prstate.marked, 0, sizeof(prstate.marked));
@@ -318,10 +319,10 @@ heap_page_prune(Relation relation, Buffer buffer,
 		if (ItemIdIsDead(itemid))
 		{
 			/*
-			 * If the caller set mark_unused_now true, we can set dead line
-			 * pointers LP_UNUSED now.
+			 * If the caller set PRUNE_DO_MARK_UNUSED_NOW, we can set dead
+			 * line pointers LP_UNUSED now.
 			 */
-			if (unlikely(prstate.mark_unused_now))
+			if (unlikely(prstate.actions & PRUNE_DO_MARK_UNUSED_NOW))
 				heap_prune_record_unused(&prstate, offnum, false);
 			else
 				heap_prune_record_unchanged_lp_dead(&prstate, offnum);
@@ -864,22 +865,22 @@ heap_prune_record_dead(PruneState *prstate, OffsetNumber offnum,
 }
 
 /*
- * Depending on whether or not the caller set mark_unused_now to true, record that a
- * line pointer should be marked LP_DEAD or LP_UNUSED. There are other cases in
- * which we will mark line pointers LP_UNUSED, but we will not mark line
- * pointers LP_DEAD if mark_unused_now is true.
+ * Depending on whether or not the caller set PRUNE_DO_MARK_UNUSED_NOW, record
+ * that a line pointer should be marked LP_DEAD or LP_UNUSED. There are other
+ * cases in which we will mark line pointers LP_UNUSED, but we will not mark
+ * line pointers LP_DEAD if PRUNE_DO_MARK_UNUSED_NOW is set.
  */
 static void
 heap_prune_record_dead_or_unused(PruneState *prstate, OffsetNumber offnum,
 								 bool was_normal)
 {
 	/*
-	 * If the caller set mark_unused_now to true, we can remove dead tuples
+	 * If the caller set PRUNE_DO_MARK_UNUSED_NOW, we can remove dead tuples
 	 * during pruning instead of marking their line pointers dead. Set this
 	 * tuple's line pointer LP_UNUSED. We hint that this option is less
 	 * likely.
 	 */
-	if (unlikely(prstate->mark_unused_now))
+	if (unlikely(prstate->actions & PRUNE_DO_MARK_UNUSED_NOW))
 		heap_prune_record_unused(prstate, offnum, was_normal);
 	else
 		heap_prune_record_dead(prstate, offnum, was_normal);
@@ -1113,12 +1114,12 @@ heap_page_prune_execute(Buffer buffer, bool lp_truncate_only,
 		else
 		{
 			/*
-			 * When heap_page_prune() was called, mark_unused_now may have
-			 * been passed as true, which allows would-be LP_DEAD items to be
-			 * made LP_UNUSED instead.  This is only possible if the relation
-			 * has no indexes.  If there are any dead items, then
-			 * mark_unused_now was not true and every item being marked
-			 * LP_UNUSED must refer to a heap-only tuple.
+			 * When heap_page_prune() was called, PRUNE_DO_MARK_UNUSED_NOW may
+			 * have been set, which allows would-be LP_DEAD items to be made
+			 * LP_UNUSED instead.  This is only possible if the relation has
+			 * no indexes.  If there are any dead items, then
+			 * PRUNE_DO_MARK_UNUSED_NOW was not set and every item being
+			 * marked LP_UNUSED must refer to a heap-only tuple.
 			 */
 			if (ndead > 0)
 			{
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index ba5b7083a3..880a218cb4 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -1425,6 +1425,7 @@ lazy_scan_prune(LVRelState *vacrel,
 	bool		all_visible,
 				all_frozen;
 	TransactionId visibility_cutoff_xid;
+	uint8		actions = 0;
 	int64		fpi_before = pgWalUsage.wal_fpi;
 	OffsetNumber deadoffsets[MaxHeapTuplesPerPage];
 	HeapTupleFreeze frozen[MaxHeapTuplesPerPage];
@@ -1458,10 +1459,14 @@ lazy_scan_prune(LVRelState *vacrel,
 	 * that were deleted from indexes.
 	 *
 	 * If the relation has no indexes, we can immediately mark would-be dead
-	 * items LP_UNUSED, so mark_unused_now should be true if no indexes and
-	 * false otherwise.
+	 * items LP_UNUSED, so PRUNE_DO_MARK_UNUSED_NOW should be set if no
+	 * indexes and unset otherwise.
 	 */
-	heap_page_prune(rel, buf, vacrel->vistest, vacrel->nindexes == 0,
+
+	if (vacrel->nindexes == 0)
+		actions |= PRUNE_DO_MARK_UNUSED_NOW;
+
+	heap_page_prune(rel, buf, vacrel->vistest, actions,
 					&presult, PRUNE_VACUUM_SCAN, &vacrel->offnum);
 
 	/*
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index f112245373..b5c711e790 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -191,6 +191,17 @@ typedef struct HeapPageFreeze
 
 } HeapPageFreeze;
 
+/*
+ * Actions that can be taken during pruning and freezing. By default, we will
+ * at least attempt regular pruning.
+ */
+
+/*
+ * PRUNE_DO_MARK_UNUSED_NOW indicates whether or not dead items can be set
+ * LP_UNUSED during pruning.
+ */
+#define		PRUNE_DO_MARK_UNUSED_NOW (1 << 1)
+
 /*
  * Per-page state returned from pruning
  */
@@ -331,7 +342,7 @@ struct GlobalVisState;
 extern void heap_page_prune_opt(Relation relation, Buffer buffer);
 extern void heap_page_prune(Relation relation, Buffer buffer,
 							struct GlobalVisState *vistest,
-							bool mark_unused_now,
+							uint8 actions,
 							PruneResult *presult,
 							PruneReason reason,
 							OffsetNumber *off_loc);
-- 
2.40.1

