patch.txt

text/plain

Filename: patch.txt
Type: text/plain
Part: 0
Message: Add index scan progress to pg_stat_progress_vacuum
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index ccc9fa0959..a4025e376c 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -39,6 +39,8 @@
 #include "utils/index_selfuncs.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
+#include "commands/progress.h"
+#include "pgstat.h"
 
 
 /*
@@ -77,7 +79,7 @@ static void brinsummarize(Relation index, Relation heapRel, BlockNumber pageRang
 static void form_and_insert_tuple(BrinBuildState *state);
 static void union_tuples(BrinDesc *bdesc, BrinMemTuple *a,
 						 BrinTuple *b);
-static void brin_vacuum_scan(Relation idxrel, BufferAccessStrategy strategy);
+static void brin_vacuum_scan(Relation idxrel, BufferAccessStrategy strategy, bool report_progress);
 static bool add_values_to_range(Relation idxRel, BrinDesc *bdesc,
 								BrinMemTuple *dtup, Datum *values, bool *nulls);
 static bool check_null_keys(BrinValues *bval, ScanKey *nullkeys, int nnullkeys);
@@ -952,7 +954,7 @@ brinvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
 	heapRel = table_open(IndexGetRelation(RelationGetRelid(info->index), false),
 						 AccessShareLock);
 
-	brin_vacuum_scan(info->index, info->strategy);
+	brin_vacuum_scan(info->index, info->strategy, info->report_progress);
 
 	brinsummarize(info->index, heapRel, BRIN_ALL_BLOCKRANGES, false,
 				  &stats->num_index_tuples, &stats->num_index_tuples);
@@ -1634,7 +1636,7 @@ union_tuples(BrinDesc *bdesc, BrinMemTuple *a, BrinTuple *b)
  * and such.
  */
 static void
-brin_vacuum_scan(Relation idxrel, BufferAccessStrategy strategy)
+brin_vacuum_scan(Relation idxrel, BufferAccessStrategy strategy, bool report_progress)
 {
 	BlockNumber nblocks;
 	BlockNumber blkno;
@@ -1644,6 +1646,9 @@ brin_vacuum_scan(Relation idxrel, BufferAccessStrategy strategy)
 	 * each page.
 	 */
 	nblocks = RelationGetNumberOfBlocks(idxrel);
+	if (report_progress)
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL,
+									 nblocks);
 	for (blkno = 0; blkno < nblocks; blkno++)
 	{
 		Buffer		buf;
@@ -1655,9 +1660,21 @@ brin_vacuum_scan(Relation idxrel, BufferAccessStrategy strategy)
 
 		brin_page_cleanup(idxrel, buf);
 
+		if (report_progress)
+			pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+										 blkno + 1);
+
 		ReleaseBuffer(buf);
 	}
 
+	if (report_progress)
+	{
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+									 0);
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL,
+									 0);
+	}
+
 	/*
 	 * Update all upper pages in the index's FSM, as well.  This ensures not
 	 * only that we propagate leaf-page FSM updates made by brin_page_cleanup,
diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c
index a276eb020b..0171454999 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -24,6 +24,8 @@
 #include "storage/lmgr.h"
 #include "storage/predicate.h"
 #include "utils/memutils.h"
+#include "commands/progress.h"
+#include "pgstat.h"
 
 struct GinVacuumState
 {
@@ -571,6 +573,9 @@ ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 	Buffer		buffer;
 	BlockNumber rootOfPostingTree[BLCKSZ / (sizeof(IndexTupleData) + sizeof(ItemId))];
 	uint32		nRoot;
+	BlockNumber	num_pages;
+	bool		needLock;
+	int		blocks_scanned = 0;
 
 	gvs.tmpCxt = AllocSetContextCreate(CurrentMemoryContext,
 									   "Gin vacuum temporary context",
@@ -635,6 +640,19 @@ ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 									RBM_NORMAL, info->strategy);
 	}
 
+	needLock = !RELATION_IS_LOCAL(index);
+
+	/* Get the current relation length */
+	if (needLock)
+		LockRelationForExtension(index, ExclusiveLock);
+	num_pages = RelationGetNumberOfBlocks(index);
+	if (needLock)
+		UnlockRelationForExtension(index, ExclusiveLock);
+
+	if (info->report_progress)
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL,
+									 num_pages);
+
 	/* right now we found leftmost page in entry's BTree */
 
 	for (;;)
@@ -676,9 +694,21 @@ ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 
 		buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
 									RBM_NORMAL, info->strategy);
+		blocks_scanned++;
+		if (info->report_progress)
+			pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+										 blocks_scanned + 1);
 		LockBuffer(buffer, GIN_EXCLUSIVE);
 	}
 
+	if (info->report_progress)
+	{
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+									 0);
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL,
+									 0);
+	}
+
 	MemoryContextDelete(gvs.tmpCxt);
 
 	return gvs.result;
@@ -694,6 +724,7 @@ ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
 	BlockNumber totFreePages;
 	GinState	ginstate;
 	GinStatsData idxStat;
+	int         blocks_scanned = 0;
 
 	/*
 	 * In an autovacuum analyze, we want to clean up pending insertions.
@@ -744,6 +775,9 @@ ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
 
 	totFreePages = 0;
 
+	if (info->report_progress)
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL,
+									 npages);
 	for (blkno = GIN_ROOT_BLKNO; blkno < npages; blkno++)
 	{
 		Buffer		buffer;
@@ -774,9 +808,22 @@ ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
 				idxStat.nEntries += PageGetMaxOffsetNumber(page);
 		}
 
+		blocks_scanned++;
+		if (info->report_progress)
+			pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+										 blocks_scanned + 1);
+
 		UnlockReleaseBuffer(buffer);
 	}
 
+	if (info->report_progress)
+	{
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+									 0);
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL,
+									 0);
+	}
+
 	/* Update the metapage with accurate page and entry counts */
 	idxStat.nTotalPages = npages;
 	ginUpdateStats(info->index, &idxStat, false);
diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c
index 0663193531..3be8bb4282 100644
--- a/src/backend/access/gist/gistvacuum.c
+++ b/src/backend/access/gist/gistvacuum.c
@@ -23,6 +23,8 @@
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
 #include "utils/memutils.h"
+#include "commands/progress.h"
+#include "pgstat.h"
 
 /* Working state needed by gistbulkdelete */
 typedef struct
@@ -215,9 +217,27 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 		/* Quit if we've scanned the whole relation */
 		if (blkno >= num_pages)
 			break;
+
+		if (info->report_progress)
+			pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL,
+										 num_pages);
+
 		/* Iterate over pages, then loop back to recheck length */
 		for (; blkno < num_pages; blkno++)
+		{
 			gistvacuumpage(&vstate, blkno, blkno);
+			if (info->report_progress)
+				pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+											 blkno + 1);
+		}
+	}
+
+	if (info->report_progress)
+	{
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+									 0);
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL,
+									 0);
 	}
 
 	/*
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index eb3810494f..851f33fd97 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -31,6 +31,7 @@
 #include "utils/builtins.h"
 #include "utils/index_selfuncs.h"
 #include "utils/rel.h"
+#include "storage/lmgr.h"
 
 /* Working state for hashbuild and its callback */
 typedef struct
@@ -468,9 +469,15 @@ hashbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 	Buffer		metabuf = InvalidBuffer;
 	HashMetaPage metap;
 	HashMetaPage cachedmetap;
+	int         blocks_scanned;
+	int         bucket_blocks_scanned;
+	BlockNumber num_pages;
+	bool		needLock;
 
 	tuples_removed = 0;
 	num_index_tuples = 0;
+	blocks_scanned = 0;
+	bucket_blocks_scanned = 0;
 
 	/*
 	 * We need a copy of the metapage so that we can use its hashm_spares[]
@@ -488,6 +495,19 @@ hashbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 	cur_bucket = 0;
 	cur_maxbucket = orig_maxbucket;
 
+	needLock = !RELATION_IS_LOCAL(rel);
+
+	/* Get the current relation length */
+	if (needLock)
+		LockRelationForExtension(rel, ExclusiveLock);
+	num_pages = RelationGetNumberOfBlocks(rel);
+	if (needLock)
+		UnlockRelationForExtension(rel, ExclusiveLock);
+
+	if (info->report_progress)
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL,
+									num_pages);
+
 loop_top:
 	while (cur_bucket <= cur_maxbucket)
 	{
@@ -503,6 +523,7 @@ loop_top:
 		bucket_blkno = BUCKET_TO_BLKNO(cachedmetap, cur_bucket);
 
 		blkno = bucket_blkno;
+		blocks_scanned++;
 
 		/*
 		 * We need to acquire a cleanup lock on the primary bucket page to out
@@ -549,10 +570,14 @@ loop_top:
 						  cachedmetap->hashm_highmask,
 						  cachedmetap->hashm_lowmask, &tuples_removed,
 						  &num_index_tuples, split_cleanup,
-						  callback, callback_state);
+						  callback, callback_state, info->report_progress,
+						  &bucket_blocks_scanned);
 
 		_hash_dropbuf(rel, bucket_buf);
 
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+									blocks_scanned + bucket_blocks_scanned);
+
 		/* Advance to next bucket */
 		cur_bucket++;
 	}
@@ -632,6 +657,14 @@ loop_top:
 	stats->tuples_removed += tuples_removed;
 	/* hashvacuumcleanup will fill in num_pages */
 
+	if (info->report_progress)
+	{
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+									 0);
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL,
+									 0);
+	}
+
 	return stats;
 }
 
@@ -685,7 +718,8 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
 				  uint32 maxbucket, uint32 highmask, uint32 lowmask,
 				  double *tuples_removed, double *num_index_tuples,
 				  bool split_cleanup,
-				  IndexBulkDeleteCallback callback, void *callback_state)
+				  IndexBulkDeleteCallback callback, void *callback_state,
+				  bool report_progress, int *bucket_blocks_scanned)
 {
 	BlockNumber blkno;
 	Buffer		buf;
@@ -717,6 +751,8 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
 		page = BufferGetPage(buf);
 		opaque = (HashPageOpaque) PageGetSpecialPointer(page);
 
+		bucket_blocks_scanned++;
+
 		/* Scan each tuple in page */
 		maxoffno = PageGetMaxOffsetNumber(page);
 		for (offno = FirstOffsetNumber;
@@ -915,4 +951,5 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
 							bstrategy);
 	else
 		LockBuffer(bucket_buf, BUFFER_LOCK_UNLOCK);
+
 }
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index 159646c7c3..538d153df7 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -758,7 +758,7 @@ restart_expand:
 
 		hashbucketcleanup(rel, old_bucket, buf_oblkno, start_oblkno, NULL,
 						  maxbucket, highmask, lowmask, NULL, NULL, true,
-						  NULL, NULL);
+						  NULL, NULL, NULL, NULL);
 
 		_hash_dropbuf(rel, buf_oblkno);
 
@@ -1326,7 +1326,7 @@ _hash_splitbucket(Relation rel,
 		hashbucketcleanup(rel, obucket, bucket_obuf,
 						  BufferGetBlockNumber(bucket_obuf), NULL,
 						  maxbucket, highmask, lowmask, NULL, NULL, true,
-						  NULL, NULL);
+						  NULL, NULL, NULL, NULL);
 	}
 	else
 	{
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index a00947ea1c..28a3797088 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -528,6 +528,9 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 	pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM,
 								  RelationGetRelid(rel));
 
+	pgstat_progress_update_param(PROGRESS_VACUUM_LEADER_PID,
+								 MyProcPid);
+
 	vacuum_set_xid_limits(rel,
 						  params->freeze_min_age,
 						  params->freeze_table_age,
@@ -3025,12 +3028,17 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat,
 	IndexVacuumInfo ivinfo;
 	PGRUsage	ru0;
 	LVSavedErrInfo saved_err_info;
+	const int    initprog_index[] = {
+		PROGRESS_VACUUM_PHASE,
+		PROGRESS_VACUUM_CURRENT_INDRELID
+	};
+	int64        initprog_val[2];
 
 	pg_rusage_init(&ru0);
 
 	ivinfo.index = indrel;
 	ivinfo.analyze_only = false;
-	ivinfo.report_progress = false;
+	ivinfo.report_progress = true;
 	ivinfo.estimated_count = true;
 	ivinfo.message_level = elevel;
 	ivinfo.num_heap_tuples = reltuples;
@@ -3048,10 +3056,18 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat,
 							 VACUUM_ERRCB_PHASE_VACUUM_INDEX,
 							 InvalidBlockNumber, InvalidOffsetNumber);
 
+	/* Report that we're vacuuming the index, advertising the indrelid */
+	initprog_val[0] = PROGRESS_VACUUM_PHASE_VACUUM_INDEX;
+	initprog_val[1] = RelationGetRelid(indrel);
+	pgstat_progress_update_multi_param(2, initprog_index, initprog_val);
+
 	/* Do bulk deletion */
 	istat = index_bulk_delete(&ivinfo, istat, lazy_tid_reaped,
 							  (void *) vacrel->dead_tuples);
 
+	/* Report that we're done vacuuming the index */
+	pgstat_progress_update_param(PROGRESS_VACUUM_CURRENT_INDRELID,
+								 0);
 	ereport(elevel,
 			(errmsg("scanned index \"%s\" to remove %d row versions",
 					vacrel->indname, vacrel->dead_tuples->num_tuples),
@@ -3081,12 +3097,17 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
 	IndexVacuumInfo ivinfo;
 	PGRUsage	ru0;
 	LVSavedErrInfo saved_err_info;
+	const int    initprog_index[] = {
+		PROGRESS_VACUUM_PHASE,
+		PROGRESS_VACUUM_CURRENT_INDRELID
+	};
+	int64        initprog_val[2];
 
 	pg_rusage_init(&ru0);
 
 	ivinfo.index = indrel;
 	ivinfo.analyze_only = false;
-	ivinfo.report_progress = false;
+	ivinfo.report_progress = true;
 	ivinfo.estimated_count = estimated_count;
 	ivinfo.message_level = elevel;
 
@@ -3105,8 +3126,18 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
 							 VACUUM_ERRCB_PHASE_INDEX_CLEANUP,
 							 InvalidBlockNumber, InvalidOffsetNumber);
 
+	/* Report that we're cleaning the index, advertising the indrelid */
+	initprog_val[0] = PROGRESS_VACUUM_PHASE_INDEX_CLEANUP;
+	initprog_val[1] = RelationGetRelid(indrel);
+	pgstat_progress_update_multi_param(2, initprog_index, initprog_val);
+
 	istat = index_vacuum_cleanup(&ivinfo, istat);
 
+	/* Report that we're done cleaning the index */
+	initprog_val[0] = 0;
+	initprog_val[1] = 0;
+	pgstat_progress_update_multi_param(2, initprog_index, initprog_val);
+
 	if (istat)
 	{
 		ereport(elevel,
@@ -4158,6 +4189,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
 	char	   *sharedquery;
 	LVRelState	vacrel;
 	ErrorContextCallback errcallback;
+	PGPROC     *leader = MyProc->lockGroupLeader;
 
 	/*
 	 * A parallel vacuum worker must have only PROC_IN_VACUUM flag since we
@@ -4186,6 +4218,14 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
 	 */
 	rel = table_open(lvshared->relid, ShareUpdateExclusiveLock);
 
+	/*
+	 * Track progress of current index being vacuumed
+	 */
+	pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM,
+								  RelationGetRelid(rel));
+
+	pgstat_progress_update_param(PROGRESS_VACUUM_LEADER_PID, leader->pid);
+
 	/*
 	 * Open all indexes. indrels are sorted in order by OID, which should be
 	 * matched to the leader's one.
@@ -4252,6 +4292,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
 	vac_close_indexes(nindexes, indrels, RowExclusiveLock);
 	table_close(rel, ShareUpdateExclusiveLock);
 	FreeAccessStrategy(vacrel.bstrategy);
+	pgstat_progress_end_command();
 	pfree(vacrel.indstats);
 }
 
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 40ad0956e0..e90fd77b86 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -996,10 +996,18 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 			btvacuumpage(&vstate, scanblkno);
 			if (info->report_progress)
 				pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
-											 scanblkno);
+											 scanblkno + 1);
 		}
 	}
 
+	if (info->report_progress)
+	{
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+									 0);
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL,
+									 0);
+	}
+
 	/* Set statistics num_pages field to final size of index */
 	stats->num_pages = num_pages;
 
diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c
index 76fb0374c4..19768f11ce 100644
--- a/src/backend/access/spgist/spgvacuum.c
+++ b/src/backend/access/spgist/spgvacuum.c
@@ -27,6 +27,8 @@
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
 #include "utils/snapmgr.h"
+#include "commands/progress.h"
+#include "pgstat.h"
 
 
 /* Entry in pending-list of TIDs we need to revisit */
@@ -797,6 +799,7 @@ spgvacuumscan(spgBulkDeleteState *bds)
 	bool		needLock;
 	BlockNumber num_pages,
 				blkno;
+	int         blocks_scanned = 0;
 
 	/* Finish setting up spgBulkDeleteState */
 	initSpGistState(&bds->spgstate, index);
@@ -836,6 +839,11 @@ spgvacuumscan(spgBulkDeleteState *bds)
 		/* Quit if we've scanned the whole relation */
 		if (blkno >= num_pages)
 			break;
+
+		if (bds->info->report_progress)
+			pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL,
+										num_pages);
+
 		/* Iterate over pages, then loop back to recheck length */
 		for (; blkno < num_pages; blkno++)
 		{
@@ -843,9 +851,22 @@ spgvacuumscan(spgBulkDeleteState *bds)
 			/* empty the pending-list after each page */
 			if (bds->pendingList != NULL)
 				spgprocesspending(bds);
+
+			blocks_scanned++;
+			if (bds->info->report_progress)
+				pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+										 blocks_scanned + 1);
 		}
 	}
 
+	if (bds->info->report_progress)
+	{
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+									 0);
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL,
+									 0);
+	}
+
 	/* Propagate local lastUsedPages cache to metablock */
 	SpGistUpdateMetaPage(index);
 
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index eb560955cd..953d238925 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1124,7 +1124,10 @@ CREATE VIEW pg_stat_progress_vacuum AS
                       END AS phase,
         S.param2 AS heap_blks_total, S.param3 AS heap_blks_scanned,
         S.param4 AS heap_blks_vacuumed, S.param5 AS index_vacuum_count,
-        S.param6 AS max_dead_tuples, S.param7 AS num_dead_tuples
+        S.param6 AS max_dead_tuples, S.param7 AS num_dead_tuples,
+        S.param8 AS indrelid, S.param16 index_blks_total,
+        S.param17 AS index_blks_scanned,
+        CASE WHEN S.param9 = S.pid THEN NULL ELSE S.param9 END AS leader_pid
     FROM pg_stat_get_progress_info('VACUUM') AS S
         LEFT JOIN pg_database D ON S.datid = D.oid;
 
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index 1cce865be2..c00bb76e3e 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -478,6 +478,7 @@ extern void hashbucketcleanup(Relation rel, Bucket cur_bucket,
 							  uint32 maxbucket, uint32 highmask, uint32 lowmask,
 							  double *tuples_removed, double *num_index_tuples,
 							  bool split_cleanup,
-							  IndexBulkDeleteCallback callback, void *callback_state);
+							  IndexBulkDeleteCallback callback, void *callback_state,
+							  bool report_progress, int *bucket_blocks_scanned);
 
 #endif							/* HASH_H */
diff --git a/src/include/commands/progress.h b/src/include/commands/progress.h
index d7bf16368b..4387a7c1f1 100644
--- a/src/include/commands/progress.h
+++ b/src/include/commands/progress.h
@@ -25,6 +25,8 @@
 #define PROGRESS_VACUUM_NUM_INDEX_VACUUMS		4
 #define PROGRESS_VACUUM_MAX_DEAD_TUPLES			5
 #define PROGRESS_VACUUM_NUM_DEAD_TUPLES			6
+#define PROGRESS_VACUUM_CURRENT_INDRELID        7
+#define PROGRESS_VACUUM_LEADER_PID              8
 
 /* Phases of vacuum (as advertised via PROGRESS_VACUUM_PHASE) */
 #define PROGRESS_VACUUM_PHASE_SCAN_HEAP			1