From 1c3b831bf7eaf1c76fe8b7d6cc763721655e6f0d Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Fri, 29 Mar 2024 19:29:46 -0400
Subject: [PATCH v10 05/10] Invoke heap_prune_record_prunable() during record
 unchanged

Recording the lowest soon-to-be prunable xid is one of the actions we
take for item pointers we will not be changing during pruning. Move this
to the recently introduced heap_prune_record_unchanged() function so
that we group all actions we take for unchanged LP_NORMAL line pointers
together.
---
 src/backend/access/heap/pruneheap.c | 72 ++++++++++++++++++-----------
 1 file changed, 44 insertions(+), 28 deletions(-)

diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index 9e6cfbf9f9..159f847689 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -82,7 +82,7 @@ static void heap_prune_record_dead(PruneState *prstate, OffsetNumber offnum, boo
 static void heap_prune_record_dead_or_unused(PruneState *prstate, OffsetNumber offnum, bool was_normal);
 static void heap_prune_record_unused(PruneState *prstate, OffsetNumber offnum, bool was_normal);
 
-static void heap_prune_record_unchanged(Page page, PruneState *prstate, OffsetNumber offnum);
+static void heap_prune_record_unchanged(Page page, int8 *htsv, PruneState *prstate, OffsetNumber offnum);
 static void heap_prune_record_unchanged_lp_dead(PruneState *prstate, OffsetNumber offnum);
 static void heap_prune_record_unchanged_lp_redirect(PruneState *prstate, OffsetNumber offnum);
 
@@ -453,7 +453,7 @@ heap_page_prune(Relation relation, Buffer buffer,
 		 * marked by heap_prune_chain() and heap_prune_record_unchanged() will
 		 * return immediately.
 		 */
-		heap_prune_record_unchanged(page, &prstate, offnum);
+		heap_prune_record_unchanged(page, presult->htsv, &prstate, offnum);
 	}
 
 /* We should now have processed every tuple exactly once  */
@@ -675,9 +675,6 @@ heap_prune_chain(Buffer buffer, OffsetNumber rootoffnum,
 		 */
 		chainitems[nchain++] = offnum;
 
-		/*
-		 * Check tuple's visibility status.
-		 */
 		switch (htsv_get_valid_status(htsv[offnum]))
 		{
 			case HEAPTUPLE_DEAD:
@@ -699,9 +696,6 @@ heap_prune_chain(Buffer buffer, OffsetNumber rootoffnum,
 			case HEAPTUPLE_RECENTLY_DEAD:
 
 				/*
-				 * This tuple may soon become DEAD.  Update the hint field so
-				 * that the page is reconsidered for pruning in future.
-				 *
 				 * We don't need to advance the conflict horizon for
 				 * RECENTLY_DEAD tuples, even if we are removing them. This is
 				 * because we only remove RECENTLY_DEAD tuples if they precede
@@ -710,28 +704,11 @@ heap_prune_chain(Buffer buffer, OffsetNumber rootoffnum,
 				 * of being later in the chain. We will have advanced the
 				 * conflict horizon for the DEAD tuple.
 				 */
-				heap_prune_record_prunable(prstate,
-										   HeapTupleHeaderGetUpdateXid(htup));
 				break;
 
 			case HEAPTUPLE_DELETE_IN_PROGRESS:
-
-				/*
-				 * This tuple may soon become DEAD.  Update the hint field so
-				 * that the page is reconsidered for pruning in future.
-				 */
-				heap_prune_record_prunable(prstate,
-										   HeapTupleHeaderGetUpdateXid(htup));
-
 			case HEAPTUPLE_LIVE:
 			case HEAPTUPLE_INSERT_IN_PROGRESS:
-
-				/*
-				 * If we wanted to optimize for aborts, we might consider
-				 * marking the page prunable when we see INSERT_IN_PROGRESS.
-				 * But we don't.  See related decisions about when to mark the
-				 * page prunable in heapam.c.
-				 */
 				goto process_chains;
 
 			default:
@@ -786,7 +763,7 @@ process_chains:
 
 		/* the rest of tuples in the chain are normal, unchanged tuples */
 		for (; i < nchain; i++)
-			heap_prune_record_unchanged(page, prstate, chainitems[i]);
+			heap_prune_record_unchanged(page, htsv, prstate, chainitems[i]);
 	}
 	else if (ndeadchain == nchain)
 	{
@@ -818,7 +795,7 @@ process_chains:
 
 		/* the rest of tuples in the chain are normal, unchanged tuples */
 		for (int i = ndeadchain; i < nchain; i++)
-			heap_prune_record_unchanged(page, prstate, chainitems[i]);
+			heap_prune_record_unchanged(page, htsv, prstate, chainitems[i]);
 	}
 }
 
@@ -932,10 +909,49 @@ heap_prune_record_unused(PruneState *prstate, OffsetNumber offnum, bool was_norm
  * Record LP_NORMAL line pointer that is left unchanged.
  */
 static void
-heap_prune_record_unchanged(Page page, PruneState *prstate, OffsetNumber offnum)
+heap_prune_record_unchanged(Page page, int8 *htsv, PruneState *prstate, OffsetNumber offnum)
 {
+	HeapTupleHeader htup;
+
 	Assert(!prstate->marked[offnum]);
 	prstate->marked[offnum] = true;
+
+	switch (htsv[offnum])
+	{
+		case HEAPTUPLE_LIVE:
+		case HEAPTUPLE_INSERT_IN_PROGRESS:
+
+			/*
+			 * If we wanted to optimize for aborts, we might consider marking
+			 * the page prunable when we see INSERT_IN_PROGRESS.  But we
+			 * don't.  See related decisions about when to mark the page
+			 * prunable in heapam.c.
+			 */
+			break;
+
+		case HEAPTUPLE_RECENTLY_DEAD:
+		case HEAPTUPLE_DELETE_IN_PROGRESS:
+
+			htup = (HeapTupleHeader) PageGetItem(page, PageGetItemId(page, offnum));
+
+			/*
+			 * This tuple may soon become DEAD.  Update the hint field so that
+			 * the page is reconsidered for pruning in future.
+			 */
+			heap_prune_record_prunable(prstate,
+									   HeapTupleHeaderGetUpdateXid(htup));
+			break;
+
+
+		default:
+
+			/*
+			 * DEAD tuples should've been passed to heap_prune_record_dead()
+			 * or heap_prune_record_unused() instead.
+			 */
+			elog(ERROR, "unexpected HeapTupleSatisfiesVacuum result %d", htsv[offnum]);
+			break;
+	}
 }
 
 
-- 
2.40.1

