From 657c240c704f4784a165d4efe0c4564aa13a8a0a Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Wed, 26 Feb 2025 11:31:55 -0800
Subject: [PATCH v15 3/4] Move lazy heap scan related variables to new struct
 LVScanData.

This is a pure refactoring for upcoming parallel heap scan, which
requires storing relation statistics collected during lazy heap scan
to a shared memory area.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch-through:
---
 src/backend/access/heap/vacuumlazy.c | 343 ++++++++++++++-------------
 src/tools/pgindent/typedefs.list     |   1 +
 2 files changed, 181 insertions(+), 163 deletions(-)

diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 3b948970437..aebc7c91379 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -256,6 +256,56 @@ typedef enum
 #define VAC_BLK_WAS_EAGER_SCANNED (1 << 0)
 #define VAC_BLK_ALL_VISIBLE_ACCORDING_TO_VM (1 << 1)
 
+/*
+ * Data and counters updated during lazy heap scan.
+ */
+typedef struct LVScanData
+{
+	BlockNumber rel_pages;		/* total number of pages */
+
+	BlockNumber scanned_pages;	/* # pages examined (not skipped via VM) */
+
+	/*
+	 * Count of all-visible blocks eagerly scanned (for logging only). This
+	 * does not include skippable blocks scanned due to SKIP_PAGES_THRESHOLD.
+	 */
+	BlockNumber eager_scanned_pages;
+
+	BlockNumber removed_pages;	/* # pages removed by relation truncation */
+	BlockNumber new_frozen_tuple_pages; /* # pages with newly frozen tuples */
+
+	/* # pages newly set all-visible in the VM */
+	BlockNumber vm_new_visible_pages;
+
+	/*
+	 * # pages newly set all-visible and all-frozen in the VM. This is a
+	 * subset of vm_new_visible_pages. That is, vm_new_visible_pages includes
+	 * all pages set all-visible, but vm_new_visible_frozen_pages includes
+	 * only those which were also set all-frozen.
+	 */
+	BlockNumber vm_new_visible_frozen_pages;
+
+	/* # all-visible pages newly set all-frozen in the VM */
+	BlockNumber vm_new_frozen_pages;
+
+	BlockNumber lpdead_item_pages;	/* # pages with LP_DEAD items */
+	BlockNumber missed_dead_pages;	/* # pages with missed dead tuples */
+	BlockNumber nonempty_pages; /* actually, last nonempty page + 1 */
+
+	/* Counters that follow are only for scanned_pages */
+	int64		tuples_deleted; /* # deleted from table */
+	int64		tuples_frozen;	/* # newly frozen */
+	int64		lpdead_items;	/* # deleted from indexes */
+	int64		live_tuples;	/* # live tuples remaining */
+	int64		recently_dead_tuples;	/* # dead, but not yet removable */
+	int64		missed_dead_tuples; /* # removable, but not removed */
+
+	/* Tracks oldest extant XID/MXID for setting relfrozenxid/relminmxid. */
+	TransactionId NewRelfrozenXid;
+	MultiXactId NewRelminMxid;
+	bool		skippedallvis;
+} LVScanData;
+
 typedef struct LVRelState
 {
 	/* Target heap relation and its indexes */
@@ -282,10 +332,6 @@ typedef struct LVRelState
 	/* VACUUM operation's cutoffs for freezing and pruning */
 	struct VacuumCutoffs cutoffs;
 	GlobalVisState *vistest;
-	/* Tracks oldest extant XID/MXID for setting relfrozenxid/relminmxid */
-	TransactionId NewRelfrozenXid;
-	MultiXactId NewRelminMxid;
-	bool		skippedallvis;
 
 	/* Error reporting state */
 	char	   *dbname;
@@ -310,35 +356,8 @@ typedef struct LVRelState
 	TidStore   *dead_items;		/* TIDs whose index tuples we'll delete */
 	VacDeadItemsInfo *dead_items_info;
 
-	BlockNumber rel_pages;		/* total number of pages */
-	BlockNumber scanned_pages;	/* # pages examined (not skipped via VM) */
-
-	/*
-	 * Count of all-visible blocks eagerly scanned (for logging only). This
-	 * does not include skippable blocks scanned due to SKIP_PAGES_THRESHOLD.
-	 */
-	BlockNumber eager_scanned_pages;
-
-	BlockNumber removed_pages;	/* # pages removed by relation truncation */
-	BlockNumber new_frozen_tuple_pages; /* # pages with newly frozen tuples */
-
-	/* # pages newly set all-visible in the VM */
-	BlockNumber vm_new_visible_pages;
-
-	/*
-	 * # pages newly set all-visible and all-frozen in the VM. This is a
-	 * subset of vm_new_visible_pages. That is, vm_new_visible_pages includes
-	 * all pages set all-visible, but vm_new_visible_frozen_pages includes
-	 * only those which were also set all-frozen.
-	 */
-	BlockNumber vm_new_visible_frozen_pages;
-
-	/* # all-visible pages newly set all-frozen in the VM */
-	BlockNumber vm_new_frozen_pages;
-
-	BlockNumber lpdead_item_pages;	/* # pages with LP_DEAD items */
-	BlockNumber missed_dead_pages;	/* # pages with missed dead tuples */
-	BlockNumber nonempty_pages; /* actually, last nonempty page + 1 */
+	/* Data and counters updated during lazy heap scan */
+	LVScanData *scan_data;
 
 	/* Statistics output by us, for table */
 	double		new_rel_tuples; /* new estimated total # of tuples */
@@ -348,13 +367,6 @@ typedef struct LVRelState
 
 	/* Instrumentation counters */
 	int			num_index_scans;
-	/* Counters that follow are only for scanned_pages */
-	int64		tuples_deleted; /* # deleted from table */
-	int64		tuples_frozen;	/* # newly frozen */
-	int64		lpdead_items;	/* # deleted from indexes */
-	int64		live_tuples;	/* # live tuples remaining */
-	int64		recently_dead_tuples;	/* # dead, but not yet removable */
-	int64		missed_dead_tuples; /* # removable, but not removed */
 
 	/* State maintained by heap_vac_scan_next_block() */
 	BlockNumber current_block;	/* last block returned */
@@ -524,7 +536,7 @@ heap_vacuum_eager_scan_setup(LVRelState *vacrel, VacuumParams *params)
 	 * the first region, making the second region the first to be eager
 	 * scanned normally.
 	 */
-	if (vacrel->rel_pages < 2 * EAGER_SCAN_REGION_SIZE)
+	if (vacrel->scan_data->rel_pages < 2 * EAGER_SCAN_REGION_SIZE)
 		return;
 
 	/*
@@ -616,6 +628,7 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 				BufferAccessStrategy bstrategy)
 {
 	LVRelState *vacrel;
+	LVScanData *scan_data;
 	bool		verbose,
 				instrument,
 				skipwithvm,
@@ -730,14 +743,25 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 	}
 
 	/* Initialize page counters explicitly (be tidy) */
-	vacrel->scanned_pages = 0;
-	vacrel->eager_scanned_pages = 0;
-	vacrel->removed_pages = 0;
-	vacrel->new_frozen_tuple_pages = 0;
-	vacrel->lpdead_item_pages = 0;
-	vacrel->missed_dead_pages = 0;
-	vacrel->nonempty_pages = 0;
-	/* dead_items_alloc allocates vacrel->dead_items later on */
+	scan_data = palloc(sizeof(LVScanData));
+	scan_data->scanned_pages = 0;
+	scan_data->eager_scanned_pages = 0;
+	scan_data->removed_pages = 0;
+	scan_data->new_frozen_tuple_pages = 0;
+	scan_data->lpdead_item_pages = 0;
+	scan_data->missed_dead_pages = 0;
+	scan_data->nonempty_pages = 0;
+	scan_data->tuples_deleted = 0;
+	scan_data->tuples_frozen = 0;
+	scan_data->lpdead_items = 0;
+	scan_data->live_tuples = 0;
+	scan_data->recently_dead_tuples = 0;
+	scan_data->missed_dead_tuples = 0;
+	scan_data->vm_new_visible_pages = 0;
+	scan_data->vm_new_visible_frozen_pages = 0;
+	scan_data->vm_new_frozen_pages = 0;
+	scan_data->rel_pages = orig_rel_pages = RelationGetNumberOfBlocks(rel);
+	vacrel->scan_data = scan_data;
 
 	/* Allocate/initialize output statistics state */
 	vacrel->new_rel_tuples = 0;
@@ -747,17 +771,8 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 
 	/* Initialize remaining counters (be tidy) */
 	vacrel->num_index_scans = 0;
-	vacrel->tuples_deleted = 0;
-	vacrel->tuples_frozen = 0;
-	vacrel->lpdead_items = 0;
-	vacrel->live_tuples = 0;
-	vacrel->recently_dead_tuples = 0;
-	vacrel->missed_dead_tuples = 0;
-
-	vacrel->vm_new_visible_pages = 0;
-	vacrel->vm_new_visible_frozen_pages = 0;
-	vacrel->vm_new_frozen_pages = 0;
-	vacrel->rel_pages = orig_rel_pages = RelationGetNumberOfBlocks(rel);
+
+	/* dead_items_alloc allocates vacrel->dead_items later on */
 
 	/*
 	 * Get cutoffs that determine which deleted tuples are considered DEAD,
@@ -778,15 +793,15 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 	vacrel->aggressive = vacuum_get_cutoffs(rel, params, &vacrel->cutoffs);
 	vacrel->vistest = GlobalVisTestFor(rel);
 	/* Initialize state used to track oldest extant XID/MXID */
-	vacrel->NewRelfrozenXid = vacrel->cutoffs.OldestXmin;
-	vacrel->NewRelminMxid = vacrel->cutoffs.OldestMxact;
+	vacrel->scan_data->NewRelfrozenXid = vacrel->cutoffs.OldestXmin;
+	vacrel->scan_data->NewRelminMxid = vacrel->cutoffs.OldestMxact;
 
 	/*
 	 * Initialize state related to tracking all-visible page skipping. This is
 	 * very important to determine whether or not it is safe to advance the
 	 * relfrozenxid/relminmxid.
 	 */
-	vacrel->skippedallvis = false;
+	vacrel->scan_data->skippedallvis = false;
 	skipwithvm = true;
 	if (params->options & VACOPT_DISABLE_PAGE_SKIPPING)
 	{
@@ -874,15 +889,15 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 	 * value >= FreezeLimit, and relminmxid to a value >= MultiXactCutoff.
 	 * Non-aggressive VACUUMs may advance them by any amount, or not at all.
 	 */
-	Assert(vacrel->NewRelfrozenXid == vacrel->cutoffs.OldestXmin ||
+	Assert(vacrel->scan_data->NewRelfrozenXid == vacrel->cutoffs.OldestXmin ||
 		   TransactionIdPrecedesOrEquals(vacrel->aggressive ? vacrel->cutoffs.FreezeLimit :
 										 vacrel->cutoffs.relfrozenxid,
-										 vacrel->NewRelfrozenXid));
-	Assert(vacrel->NewRelminMxid == vacrel->cutoffs.OldestMxact ||
+										 vacrel->scan_data->NewRelfrozenXid));
+	Assert(vacrel->scan_data->NewRelminMxid == vacrel->cutoffs.OldestMxact ||
 		   MultiXactIdPrecedesOrEquals(vacrel->aggressive ? vacrel->cutoffs.MultiXactCutoff :
 									   vacrel->cutoffs.relminmxid,
-									   vacrel->NewRelminMxid));
-	if (vacrel->skippedallvis)
+									   vacrel->scan_data->NewRelminMxid));
+	if (vacrel->scan_data->skippedallvis)
 	{
 		/*
 		 * Must keep original relfrozenxid in a non-aggressive VACUUM that
@@ -890,15 +905,16 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 		 * values will have missed unfrozen XIDs from the pages we skipped.
 		 */
 		Assert(!vacrel->aggressive);
-		vacrel->NewRelfrozenXid = InvalidTransactionId;
-		vacrel->NewRelminMxid = InvalidMultiXactId;
+		vacrel->scan_data->NewRelfrozenXid = InvalidTransactionId;
+		vacrel->scan_data->NewRelminMxid = InvalidMultiXactId;
 	}
 
 	/*
 	 * For safety, clamp relallvisible to be not more than what we're setting
 	 * pg_class.relpages to
 	 */
-	new_rel_pages = vacrel->rel_pages;	/* After possible rel truncation */
+	new_rel_pages = vacrel->scan_data->rel_pages;	/* After possible rel
+													 * truncation */
 	visibilitymap_count(rel, &new_rel_allvisible, &new_rel_allfrozen);
 	if (new_rel_allvisible > new_rel_pages)
 		new_rel_allvisible = new_rel_pages;
@@ -921,7 +937,8 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 	vac_update_relstats(rel, new_rel_pages, vacrel->new_live_tuples,
 						new_rel_allvisible, new_rel_allfrozen,
 						vacrel->nindexes > 0,
-						vacrel->NewRelfrozenXid, vacrel->NewRelminMxid,
+						vacrel->scan_data->NewRelfrozenXid,
+						vacrel->scan_data->NewRelminMxid,
 						&frozenxid_updated, &minmulti_updated, false);
 
 	/*
@@ -937,8 +954,8 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 	pgstat_report_vacuum(RelationGetRelid(rel),
 						 rel->rd_rel->relisshared,
 						 Max(vacrel->new_live_tuples, 0),
-						 vacrel->recently_dead_tuples +
-						 vacrel->missed_dead_tuples,
+						 vacrel->scan_data->recently_dead_tuples +
+						 vacrel->scan_data->missed_dead_tuples,
 						 starttime);
 	pgstat_progress_end_command();
 
@@ -1012,23 +1029,23 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 							 vacrel->relname,
 							 vacrel->num_index_scans);
 			appendStringInfo(&buf, _("pages: %u removed, %u remain, %u scanned (%.2f%% of total), %u eagerly scanned\n"),
-							 vacrel->removed_pages,
+							 vacrel->scan_data->removed_pages,
 							 new_rel_pages,
-							 vacrel->scanned_pages,
+							 vacrel->scan_data->scanned_pages,
 							 orig_rel_pages == 0 ? 100.0 :
-							 100.0 * vacrel->scanned_pages /
+							 100.0 * vacrel->scan_data->scanned_pages /
 							 orig_rel_pages,
-							 vacrel->eager_scanned_pages);
+							 vacrel->scan_data->eager_scanned_pages);
 			appendStringInfo(&buf,
 							 _("tuples: %" PRId64 " removed, %" PRId64 " remain, %" PRId64 " are dead but not yet removable\n"),
-							 vacrel->tuples_deleted,
+							 vacrel->scan_data->tuples_deleted,
 							 (int64) vacrel->new_rel_tuples,
-							 vacrel->recently_dead_tuples);
-			if (vacrel->missed_dead_tuples > 0)
+							 vacrel->scan_data->recently_dead_tuples);
+			if (vacrel->scan_data->missed_dead_tuples > 0)
 				appendStringInfo(&buf,
 								 _("tuples missed: %" PRId64 " dead from %u pages not removed due to cleanup lock contention\n"),
-								 vacrel->missed_dead_tuples,
-								 vacrel->missed_dead_pages);
+								 vacrel->scan_data->missed_dead_tuples,
+								 vacrel->scan_data->missed_dead_pages);
 			diff = (int32) (ReadNextTransactionId() -
 							vacrel->cutoffs.OldestXmin);
 			appendStringInfo(&buf,
@@ -1036,33 +1053,33 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 							 vacrel->cutoffs.OldestXmin, diff);
 			if (frozenxid_updated)
 			{
-				diff = (int32) (vacrel->NewRelfrozenXid -
+				diff = (int32) (vacrel->scan_data->NewRelfrozenXid -
 								vacrel->cutoffs.relfrozenxid);
 				appendStringInfo(&buf,
 								 _("new relfrozenxid: %u, which is %d XIDs ahead of previous value\n"),
-								 vacrel->NewRelfrozenXid, diff);
+								 vacrel->scan_data->NewRelfrozenXid, diff);
 			}
 			if (minmulti_updated)
 			{
-				diff = (int32) (vacrel->NewRelminMxid -
+				diff = (int32) (vacrel->scan_data->NewRelminMxid -
 								vacrel->cutoffs.relminmxid);
 				appendStringInfo(&buf,
 								 _("new relminmxid: %u, which is %d MXIDs ahead of previous value\n"),
-								 vacrel->NewRelminMxid, diff);
+								 vacrel->scan_data->NewRelminMxid, diff);
 			}
 			appendStringInfo(&buf, _("frozen: %u pages from table (%.2f%% of total) had %" PRId64 " tuples frozen\n"),
-							 vacrel->new_frozen_tuple_pages,
+							 vacrel->scan_data->new_frozen_tuple_pages,
 							 orig_rel_pages == 0 ? 100.0 :
-							 100.0 * vacrel->new_frozen_tuple_pages /
+							 100.0 * vacrel->scan_data->new_frozen_tuple_pages /
 							 orig_rel_pages,
-							 vacrel->tuples_frozen);
+							 vacrel->scan_data->tuples_frozen);
 
 			appendStringInfo(&buf,
 							 _("visibility map: %u pages set all-visible, %u pages set all-frozen (%u were all-visible)\n"),
-							 vacrel->vm_new_visible_pages,
-							 vacrel->vm_new_visible_frozen_pages +
-							 vacrel->vm_new_frozen_pages,
-							 vacrel->vm_new_frozen_pages);
+							 vacrel->scan_data->vm_new_visible_pages,
+							 vacrel->scan_data->vm_new_visible_frozen_pages +
+							 vacrel->scan_data->vm_new_frozen_pages,
+							 vacrel->scan_data->vm_new_frozen_pages);
 			if (vacrel->do_index_vacuuming)
 			{
 				if (vacrel->nindexes == 0 || vacrel->num_index_scans == 0)
@@ -1082,10 +1099,10 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 				msgfmt = _("%u pages from table (%.2f%% of total) have %" PRId64 " dead item identifiers\n");
 			}
 			appendStringInfo(&buf, msgfmt,
-							 vacrel->lpdead_item_pages,
+							 vacrel->scan_data->lpdead_item_pages,
 							 orig_rel_pages == 0 ? 100.0 :
-							 100.0 * vacrel->lpdead_item_pages / orig_rel_pages,
-							 vacrel->lpdead_items);
+							 100.0 * vacrel->scan_data->lpdead_item_pages / orig_rel_pages,
+							 vacrel->scan_data->lpdead_items);
 			for (int i = 0; i < vacrel->nindexes; i++)
 			{
 				IndexBulkDeleteResult *istat = vacrel->indstats[i];
@@ -1199,7 +1216,7 @@ static void
 lazy_scan_heap(LVRelState *vacrel)
 {
 	ReadStream *stream;
-	BlockNumber rel_pages = vacrel->rel_pages,
+	BlockNumber rel_pages = vacrel->scan_data->rel_pages,
 				blkno = 0,
 				next_fsm_block_to_vacuum = 0;
 	BlockNumber orig_eager_scan_success_limit =
@@ -1260,8 +1277,8 @@ lazy_scan_heap(LVRelState *vacrel)
 		 * one-pass strategy, and the two-pass strategy with the index_cleanup
 		 * param set to 'off'.
 		 */
-		if (vacrel->scanned_pages > 0 &&
-			vacrel->scanned_pages % FAILSAFE_EVERY_PAGES == 0)
+		if (vacrel->scan_data->scanned_pages > 0 &&
+			vacrel->scan_data->scanned_pages % FAILSAFE_EVERY_PAGES == 0)
 			lazy_check_wraparound_failsafe(vacrel);
 
 		/*
@@ -1316,9 +1333,9 @@ lazy_scan_heap(LVRelState *vacrel)
 		page = BufferGetPage(buf);
 		blkno = BufferGetBlockNumber(buf);
 
-		vacrel->scanned_pages++;
+		vacrel->scan_data->scanned_pages++;
 		if (blk_info & VAC_BLK_WAS_EAGER_SCANNED)
-			vacrel->eager_scanned_pages++;
+			vacrel->scan_data->eager_scanned_pages++;
 
 		/* Report as block scanned, update error traceback information */
 		pgstat_progress_update_param(PROGRESS_VACUUM_HEAP_BLKS_SCANNED, blkno);
@@ -1500,16 +1517,16 @@ lazy_scan_heap(LVRelState *vacrel)
 
 	/* now we can compute the new value for pg_class.reltuples */
 	vacrel->new_live_tuples = vac_estimate_reltuples(vacrel->rel, rel_pages,
-													 vacrel->scanned_pages,
-													 vacrel->live_tuples);
+													 vacrel->scan_data->scanned_pages,
+													 vacrel->scan_data->live_tuples);
 
 	/*
 	 * Also compute the total number of surviving heap entries.  In the
 	 * (unlikely) scenario that new_live_tuples is -1, take it as zero.
 	 */
 	vacrel->new_rel_tuples =
-		Max(vacrel->new_live_tuples, 0) + vacrel->recently_dead_tuples +
-		vacrel->missed_dead_tuples;
+		Max(vacrel->new_live_tuples, 0) + vacrel->scan_data->recently_dead_tuples +
+		vacrel->scan_data->missed_dead_tuples;
 
 	read_stream_end(stream);
 
@@ -1556,7 +1573,7 @@ lazy_scan_heap(LVRelState *vacrel)
  * callback_private_data contains a reference to the LVRelState, passed to the
  * read stream API during stream setup. The LVRelState is an in/out parameter
  * here (locally named `vacrel`). Vacuum options and information about the
- * relation are read from it. vacrel->skippedallvis is set if we skip a block
+ * relation are read from it. vacrel->scan_data->skippedallvis is set if we skip a block
  * that's all-visible but not all-frozen (to ensure that we don't update
  * relfrozenxid in that case). vacrel also holds information about the next
  * unskippable block -- as bookkeeping for this function.
@@ -1574,7 +1591,7 @@ heap_vac_scan_next_block(ReadStream *stream,
 	next_block = vacrel->current_block + 1;
 
 	/* Have we reached the end of the relation? */
-	if (next_block >= vacrel->rel_pages)
+	if (next_block >= vacrel->scan_data->rel_pages)
 	{
 		if (BufferIsValid(vacrel->next_unskippable_vmbuffer))
 		{
@@ -1618,7 +1635,7 @@ heap_vac_scan_next_block(ReadStream *stream,
 		{
 			next_block = vacrel->next_unskippable_block;
 			if (skipsallvis)
-				vacrel->skippedallvis = true;
+				vacrel->scan_data->skippedallvis = true;
 		}
 	}
 
@@ -1669,7 +1686,7 @@ heap_vac_scan_next_block(ReadStream *stream,
 static void
 find_next_unskippable_block(LVRelState *vacrel, bool *skipsallvis)
 {
-	BlockNumber rel_pages = vacrel->rel_pages;
+	BlockNumber rel_pages = vacrel->scan_data->rel_pages;
 	BlockNumber next_unskippable_block = vacrel->next_unskippable_block + 1;
 	Buffer		next_unskippable_vmbuffer = vacrel->next_unskippable_vmbuffer;
 	bool		next_unskippable_eager_scanned = false;
@@ -1900,11 +1917,11 @@ lazy_scan_new_or_empty(LVRelState *vacrel, Buffer buf, BlockNumber blkno,
 			 */
 			if ((old_vmbits & VISIBILITYMAP_ALL_VISIBLE) == 0)
 			{
-				vacrel->vm_new_visible_pages++;
-				vacrel->vm_new_visible_frozen_pages++;
+				vacrel->scan_data->vm_new_visible_pages++;
+				vacrel->scan_data->vm_new_visible_frozen_pages++;
 			}
 			else if ((old_vmbits & VISIBILITYMAP_ALL_FROZEN) == 0)
-				vacrel->vm_new_frozen_pages++;
+				vacrel->scan_data->vm_new_frozen_pages++;
 		}
 
 		freespace = PageGetHeapFreeSpace(page);
@@ -1979,10 +1996,10 @@ lazy_scan_prune(LVRelState *vacrel,
 	heap_page_prune_and_freeze(rel, buf, vacrel->vistest, prune_options,
 							   &vacrel->cutoffs, &presult, PRUNE_VACUUM_SCAN,
 							   &vacrel->offnum,
-							   &vacrel->NewRelfrozenXid, &vacrel->NewRelminMxid);
+							   &vacrel->scan_data->NewRelfrozenXid, &vacrel->scan_data->NewRelminMxid);
 
-	Assert(MultiXactIdIsValid(vacrel->NewRelminMxid));
-	Assert(TransactionIdIsValid(vacrel->NewRelfrozenXid));
+	Assert(MultiXactIdIsValid(vacrel->scan_data->NewRelminMxid));
+	Assert(TransactionIdIsValid(vacrel->scan_data->NewRelfrozenXid));
 
 	if (presult.nfrozen > 0)
 	{
@@ -1992,7 +2009,7 @@ lazy_scan_prune(LVRelState *vacrel,
 		 * frozen tuples (don't confuse that with pages newly set all-frozen
 		 * in VM).
 		 */
-		vacrel->new_frozen_tuple_pages++;
+		vacrel->scan_data->new_frozen_tuple_pages++;
 	}
 
 	/*
@@ -2027,7 +2044,7 @@ lazy_scan_prune(LVRelState *vacrel,
 	 */
 	if (presult.lpdead_items > 0)
 	{
-		vacrel->lpdead_item_pages++;
+		vacrel->scan_data->lpdead_item_pages++;
 
 		/*
 		 * deadoffsets are collected incrementally in
@@ -2042,15 +2059,15 @@ lazy_scan_prune(LVRelState *vacrel,
 	}
 
 	/* Finally, add page-local counts to whole-VACUUM counts */
-	vacrel->tuples_deleted += presult.ndeleted;
-	vacrel->tuples_frozen += presult.nfrozen;
-	vacrel->lpdead_items += presult.lpdead_items;
-	vacrel->live_tuples += presult.live_tuples;
-	vacrel->recently_dead_tuples += presult.recently_dead_tuples;
+	vacrel->scan_data->tuples_deleted += presult.ndeleted;
+	vacrel->scan_data->tuples_frozen += presult.nfrozen;
+	vacrel->scan_data->lpdead_items += presult.lpdead_items;
+	vacrel->scan_data->live_tuples += presult.live_tuples;
+	vacrel->scan_data->recently_dead_tuples += presult.recently_dead_tuples;
 
 	/* Can't truncate this page */
 	if (presult.hastup)
-		vacrel->nonempty_pages = blkno + 1;
+		vacrel->scan_data->nonempty_pages = blkno + 1;
 
 	/* Did we find LP_DEAD items? */
 	*has_lpdead_items = (presult.lpdead_items > 0);
@@ -2099,17 +2116,17 @@ lazy_scan_prune(LVRelState *vacrel,
 		 */
 		if ((old_vmbits & VISIBILITYMAP_ALL_VISIBLE) == 0)
 		{
-			vacrel->vm_new_visible_pages++;
+			vacrel->scan_data->vm_new_visible_pages++;
 			if (presult.all_frozen)
 			{
-				vacrel->vm_new_visible_frozen_pages++;
+				vacrel->scan_data->vm_new_visible_frozen_pages++;
 				*vm_page_frozen = true;
 			}
 		}
 		else if ((old_vmbits & VISIBILITYMAP_ALL_FROZEN) == 0 &&
 				 presult.all_frozen)
 		{
-			vacrel->vm_new_frozen_pages++;
+			vacrel->scan_data->vm_new_frozen_pages++;
 			*vm_page_frozen = true;
 		}
 	}
@@ -2197,8 +2214,8 @@ lazy_scan_prune(LVRelState *vacrel,
 		 */
 		if ((old_vmbits & VISIBILITYMAP_ALL_VISIBLE) == 0)
 		{
-			vacrel->vm_new_visible_pages++;
-			vacrel->vm_new_visible_frozen_pages++;
+			vacrel->scan_data->vm_new_visible_pages++;
+			vacrel->scan_data->vm_new_visible_frozen_pages++;
 			*vm_page_frozen = true;
 		}
 
@@ -2208,7 +2225,7 @@ lazy_scan_prune(LVRelState *vacrel,
 		 */
 		else
 		{
-			vacrel->vm_new_frozen_pages++;
+			vacrel->scan_data->vm_new_frozen_pages++;
 			*vm_page_frozen = true;
 		}
 	}
@@ -2249,8 +2266,8 @@ lazy_scan_noprune(LVRelState *vacrel,
 				missed_dead_tuples;
 	bool		hastup;
 	HeapTupleHeader tupleheader;
-	TransactionId NoFreezePageRelfrozenXid = vacrel->NewRelfrozenXid;
-	MultiXactId NoFreezePageRelminMxid = vacrel->NewRelminMxid;
+	TransactionId NoFreezePageRelfrozenXid = vacrel->scan_data->NewRelfrozenXid;
+	MultiXactId NoFreezePageRelminMxid = vacrel->scan_data->NewRelminMxid;
 	OffsetNumber deadoffsets[MaxHeapTuplesPerPage];
 
 	Assert(BufferGetBlockNumber(buf) == blkno);
@@ -2377,8 +2394,8 @@ lazy_scan_noprune(LVRelState *vacrel,
 	 * this particular page until the next VACUUM.  Remember its details now.
 	 * (lazy_scan_prune expects a clean slate, so we have to do this last.)
 	 */
-	vacrel->NewRelfrozenXid = NoFreezePageRelfrozenXid;
-	vacrel->NewRelminMxid = NoFreezePageRelminMxid;
+	vacrel->scan_data->NewRelfrozenXid = NoFreezePageRelfrozenXid;
+	vacrel->scan_data->NewRelminMxid = NoFreezePageRelminMxid;
 
 	/* Save any LP_DEAD items found on the page in dead_items */
 	if (vacrel->nindexes == 0)
@@ -2405,25 +2422,25 @@ lazy_scan_noprune(LVRelState *vacrel,
 		 * indexes will be deleted during index vacuuming (and then marked
 		 * LP_UNUSED in the heap)
 		 */
-		vacrel->lpdead_item_pages++;
+		vacrel->scan_data->lpdead_item_pages++;
 
 		dead_items_add(vacrel, blkno, deadoffsets, lpdead_items);
 
-		vacrel->lpdead_items += lpdead_items;
+		vacrel->scan_data->lpdead_items += lpdead_items;
 	}
 
 	/*
 	 * Finally, add relevant page-local counts to whole-VACUUM counts
 	 */
-	vacrel->live_tuples += live_tuples;
-	vacrel->recently_dead_tuples += recently_dead_tuples;
-	vacrel->missed_dead_tuples += missed_dead_tuples;
+	vacrel->scan_data->live_tuples += live_tuples;
+	vacrel->scan_data->recently_dead_tuples += recently_dead_tuples;
+	vacrel->scan_data->missed_dead_tuples += missed_dead_tuples;
 	if (missed_dead_tuples > 0)
-		vacrel->missed_dead_pages++;
+		vacrel->scan_data->missed_dead_pages++;
 
 	/* Can't truncate this page */
 	if (hastup)
-		vacrel->nonempty_pages = blkno + 1;
+		vacrel->scan_data->nonempty_pages = blkno + 1;
 
 	/* Did we find LP_DEAD items? */
 	*has_lpdead_items = (lpdead_items > 0);
@@ -2452,7 +2469,7 @@ lazy_vacuum(LVRelState *vacrel)
 
 	/* Should not end up here with no indexes */
 	Assert(vacrel->nindexes > 0);
-	Assert(vacrel->lpdead_item_pages > 0);
+	Assert(vacrel->scan_data->lpdead_item_pages > 0);
 
 	if (!vacrel->do_index_vacuuming)
 	{
@@ -2481,12 +2498,12 @@ lazy_vacuum(LVRelState *vacrel)
 	 * HOT through careful tuning.
 	 */
 	bypass = false;
-	if (vacrel->consider_bypass_optimization && vacrel->rel_pages > 0)
+	if (vacrel->consider_bypass_optimization && vacrel->scan_data->rel_pages > 0)
 	{
 		BlockNumber threshold;
 
 		Assert(vacrel->num_index_scans == 0);
-		Assert(vacrel->lpdead_items == vacrel->dead_items_info->num_items);
+		Assert(vacrel->scan_data->lpdead_items == vacrel->dead_items_info->num_items);
 		Assert(vacrel->do_index_vacuuming);
 		Assert(vacrel->do_index_cleanup);
 
@@ -2512,8 +2529,8 @@ lazy_vacuum(LVRelState *vacrel)
 		 * be negligible.  If this optimization is ever expanded to cover more
 		 * cases then this may need to be reconsidered.
 		 */
-		threshold = (double) vacrel->rel_pages * BYPASS_THRESHOLD_PAGES;
-		bypass = (vacrel->lpdead_item_pages < threshold &&
+		threshold = (double) vacrel->scan_data->rel_pages * BYPASS_THRESHOLD_PAGES;
+		bypass = (vacrel->scan_data->lpdead_item_pages < threshold &&
 				  TidStoreMemoryUsage(vacrel->dead_items) < 32 * 1024 * 1024);
 	}
 
@@ -2651,7 +2668,7 @@ lazy_vacuum_all_indexes(LVRelState *vacrel)
 	 * place).
 	 */
 	Assert(vacrel->num_index_scans > 0 ||
-		   vacrel->dead_items_info->num_items == vacrel->lpdead_items);
+		   vacrel->dead_items_info->num_items == vacrel->scan_data->lpdead_items);
 	Assert(allindexes || VacuumFailsafeActive);
 
 	/*
@@ -2813,8 +2830,8 @@ lazy_vacuum_heap_rel(LVRelState *vacrel)
 	 * the second heap pass.  No more, no less.
 	 */
 	Assert(vacrel->num_index_scans > 1 ||
-		   (vacrel->dead_items_info->num_items == vacrel->lpdead_items &&
-			vacuumed_pages == vacrel->lpdead_item_pages));
+		   (vacrel->dead_items_info->num_items == vacrel->scan_data->lpdead_items &&
+			vacuumed_pages == vacrel->scan_data->lpdead_item_pages));
 
 	ereport(DEBUG2,
 			(errmsg("table \"%s\": removed %" PRId64 " dead item identifiers in %u pages",
@@ -2930,14 +2947,14 @@ lazy_vacuum_heap_page(LVRelState *vacrel, BlockNumber blkno, Buffer buffer,
 		 */
 		if ((old_vmbits & VISIBILITYMAP_ALL_VISIBLE) == 0)
 		{
-			vacrel->vm_new_visible_pages++;
+			vacrel->scan_data->vm_new_visible_pages++;
 			if (all_frozen)
-				vacrel->vm_new_visible_frozen_pages++;
+				vacrel->scan_data->vm_new_visible_frozen_pages++;
 		}
 
 		else if ((old_vmbits & VISIBILITYMAP_ALL_FROZEN) == 0 &&
 				 all_frozen)
-			vacrel->vm_new_frozen_pages++;
+			vacrel->scan_data->vm_new_frozen_pages++;
 	}
 
 	/* Revert to the previous phase information for error traceback */
@@ -3013,7 +3030,7 @@ static void
 lazy_cleanup_all_indexes(LVRelState *vacrel)
 {
 	double		reltuples = vacrel->new_rel_tuples;
-	bool		estimated_count = vacrel->scanned_pages < vacrel->rel_pages;
+	bool		estimated_count = vacrel->scan_data->scanned_pages < vacrel->scan_data->rel_pages;
 	const int	progress_start_index[] = {
 		PROGRESS_VACUUM_PHASE,
 		PROGRESS_VACUUM_INDEXES_TOTAL
@@ -3194,10 +3211,10 @@ should_attempt_truncation(LVRelState *vacrel)
 	if (!vacrel->do_rel_truncate || VacuumFailsafeActive)
 		return false;
 
-	possibly_freeable = vacrel->rel_pages - vacrel->nonempty_pages;
+	possibly_freeable = vacrel->scan_data->rel_pages - vacrel->scan_data->nonempty_pages;
 	if (possibly_freeable > 0 &&
 		(possibly_freeable >= REL_TRUNCATE_MINIMUM ||
-		 possibly_freeable >= vacrel->rel_pages / REL_TRUNCATE_FRACTION))
+		 possibly_freeable >= vacrel->scan_data->rel_pages / REL_TRUNCATE_FRACTION))
 		return true;
 
 	return false;
@@ -3209,7 +3226,7 @@ should_attempt_truncation(LVRelState *vacrel)
 static void
 lazy_truncate_heap(LVRelState *vacrel)
 {
-	BlockNumber orig_rel_pages = vacrel->rel_pages;
+	BlockNumber orig_rel_pages = vacrel->scan_data->rel_pages;
 	BlockNumber new_rel_pages;
 	bool		lock_waiter_detected;
 	int			lock_retry;
@@ -3220,7 +3237,7 @@ lazy_truncate_heap(LVRelState *vacrel)
 
 	/* Update error traceback information one last time */
 	update_vacuum_error_info(vacrel, NULL, VACUUM_ERRCB_PHASE_TRUNCATE,
-							 vacrel->nonempty_pages, InvalidOffsetNumber);
+							 vacrel->scan_data->nonempty_pages, InvalidOffsetNumber);
 
 	/*
 	 * Loop until no more truncating can be done.
@@ -3321,15 +3338,15 @@ lazy_truncate_heap(LVRelState *vacrel)
 		 * without also touching reltuples, since the tuple count wasn't
 		 * changed by the truncation.
 		 */
-		vacrel->removed_pages += orig_rel_pages - new_rel_pages;
-		vacrel->rel_pages = new_rel_pages;
+		vacrel->scan_data->removed_pages += orig_rel_pages - new_rel_pages;
+		vacrel->scan_data->rel_pages = new_rel_pages;
 
 		ereport(vacrel->verbose ? INFO : DEBUG2,
 				(errmsg("table \"%s\": truncated %u to %u pages",
 						vacrel->relname,
 						orig_rel_pages, new_rel_pages)));
 		orig_rel_pages = new_rel_pages;
-	} while (new_rel_pages > vacrel->nonempty_pages && lock_waiter_detected);
+	} while (new_rel_pages > vacrel->scan_data->nonempty_pages && lock_waiter_detected);
 }
 
 /*
@@ -3353,11 +3370,11 @@ count_nondeletable_pages(LVRelState *vacrel, bool *lock_waiter_detected)
 	 * unsigned.)  To make the scan faster, we prefetch a few blocks at a time
 	 * in forward direction, so that OS-level readahead can kick in.
 	 */
-	blkno = vacrel->rel_pages;
+	blkno = vacrel->scan_data->rel_pages;
 	StaticAssertStmt((PREFETCH_SIZE & (PREFETCH_SIZE - 1)) == 0,
 					 "prefetch size must be power of 2");
 	prefetchedUntil = InvalidBlockNumber;
-	while (blkno > vacrel->nonempty_pages)
+	while (blkno > vacrel->scan_data->nonempty_pages)
 	{
 		Buffer		buf;
 		Page		page;
@@ -3469,7 +3486,7 @@ count_nondeletable_pages(LVRelState *vacrel, bool *lock_waiter_detected)
 	 * pages still are; we need not bother to look at the last known-nonempty
 	 * page.
 	 */
-	return vacrel->nonempty_pages;
+	return vacrel->scan_data->nonempty_pages;
 }
 
 /*
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 9f52ceba1c6..4833bc70710 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1508,6 +1508,7 @@ LSEG
 LUID
 LVRelState
 LVSavedErrInfo
+LVScanData
 LWLock
 LWLockHandle
 LWLockMode
-- 
2.43.5

