From 6dfae936a29e2d3479273f8ab47778a596258b16 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Wed, 6 Mar 2024 21:03:19 +0200
Subject: [PATCH v6 8/9] Track 'current_block' in the skip state

The caller was expected to always pass last blk + 1. It's not clear if
the next_unskippable block accounting would work correctly if you
passed something else. So rather than expecting the caller to do that,
have heap_vac_scan_get_next_block() keep track of the last returned
block itself, in the 'skip' state.

This is largely redundant with the LVRelState->blkno field. But that
one is currently only used for error reporting, so it feels best to
give heap_vac_scan_get_next_block() its own field that it owns.
---
 src/backend/access/heap/vacuumlazy.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 17e06065f7e..535d70b71c3 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -211,6 +211,8 @@ typedef struct LVRelState
 	 */
 	struct
 	{
+		BlockNumber current_block;
+
 		/* Next unskippable block */
 		BlockNumber next_unskippable_block;
 		/* Next unskippable block's visibility status */
@@ -228,7 +230,7 @@ typedef struct LVSavedErrInfo
 
 /* non-export function prototypes */
 static void lazy_scan_heap(LVRelState *vacrel);
-static bool heap_vac_scan_get_next_block(LVRelState *vacrel, BlockNumber next_block,
+static bool heap_vac_scan_get_next_block(LVRelState *vacrel,
 										 BlockNumber *blkno,
 										 bool *all_visible_according_to_vm,
 										 Buffer *vmbuffer);
@@ -831,10 +833,11 @@ lazy_scan_heap(LVRelState *vacrel)
 	initprog_val[2] = dead_items->max_items;
 	pgstat_progress_update_multi_param(3, initprog_index, initprog_val);
 
+	/* initialize for first heap_vac_scan_get_next_block() call */
+	vacrel->get_next_block_state.current_block = InvalidBlockNumber;
 	vacrel->get_next_block_state.next_unskippable_block = InvalidBlockNumber;
 
-	while (heap_vac_scan_get_next_block(vacrel, blkno + 1,
-										&blkno, &all_visible_according_to_vm, &vmbuffer))
+	while (heap_vac_scan_get_next_block(vacrel, &blkno, &all_visible_according_to_vm, &vmbuffer))
 	{
 		Buffer		buf;
 		Page		page;
@@ -1061,11 +1064,9 @@ lazy_scan_heap(LVRelState *vacrel)
  *	heap_vac_scan_get_next_block() -- get next block for vacuum to process
  *
  * lazy_scan_heap() calls here every time it needs to get the next block to
- * prune and vacuum, using the visibility map, vacuum options, and various
- * thresholds to skip blocks which do not need to be processed. Caller passes
- * next_block, the next block in line. This block may end up being skipped.
- * heap_vac_scan_get_next_block() sets blkno to next block that actually needs
- * to be processed.
+ * prune and vacuum.  We use the visibility map, vacuum options, and various
+ * thresholds to skip blocks which do not need to be processed, and set blkno
+ * to next block that actually needs to be processed.
  *
  * A block is unskippable if it is not all visible according to the visibility
  * map. It is also unskippable if it is the last block in the relation, if the
@@ -1104,14 +1105,16 @@ lazy_scan_heap(LVRelState *vacrel)
  * choice to skip such a range is actually made, making everything safe.)
  */
 static bool
-heap_vac_scan_get_next_block(LVRelState *vacrel, BlockNumber next_block,
-							 BlockNumber *blkno, bool *all_visible_according_to_vm, Buffer *vmbuffer)
+heap_vac_scan_get_next_block(LVRelState *vacrel, BlockNumber *blkno,
+							 bool *all_visible_according_to_vm, Buffer *vmbuffer)
 {
+	/* Relies on InvalidBlockNumber + 1 == 0 */
+	BlockNumber next_block = vacrel->get_next_block_state.current_block + 1;
 	bool		skipsallvis = false;
 
 	if (next_block >= vacrel->rel_pages)
 	{
-		*blkno = InvalidBlockNumber;
+		vacrel->get_next_block_state.current_block = *blkno = InvalidBlockNumber;
 		return false;
 	}
 
@@ -1206,7 +1209,7 @@ heap_vac_scan_get_next_block(LVRelState *vacrel, BlockNumber next_block,
 	else
 		*all_visible_according_to_vm = true;
 
-	*blkno = next_block;
+	vacrel->get_next_block_state.current_block = *blkno = next_block;
 	return true;
 }
 
-- 
2.39.2

