From 9b84c51678e2406eed092d56d8fbdfbb08a164a5 Mon Sep 17 00:00:00 2001
From: Manu <manuelreyesbravo@gmail.com>
Date: Thu, 15 Oct 2026 23:55:41 -0300
Subject: [PATCH] Count the last block of the validation scan of a concurrent
 index build

heapam_index_validate_scan() reports PROGRESS_SCAN_BLOCKS_DONE as the
number of the block that the scan starts on, and never again once the
scan ends.  So for CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY,
blocks_done in pg_stat_progress_create_index stops one block short of
blocks_total in the phase "index validation: scanning table".  The
phases that follow ("waiting for old snapshots", and for REINDEX
CONCURRENTLY "waiting for readers before marking dead" and "waiting for
readers before dropping") do not touch the block counters, so the view
keeps showing that, e.g. 789 of 790 blocks, for as long as they wait.

Report the scan's total as done when it ends, as
heapam_index_build_range_scan() already does for the build scan.  The
validation scan does not use syncscan, so it starts at block 0 and
rs_nblocks is the total it reported at its start.

This is the same kind of blip as the one fixed for the build scan in
3be29d9346d.
---
 src/backend/access/heap/heapam_handler.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index 7d2065dec37..5cfdbcd4468 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -1931,6 +1931,13 @@ heapam_index_validate_scan(Relation heapRelation,
 		}
 	}
 
+	/*
+	 * Report scan progress one last time.  Each block is reported when the
+	 * scan starts on it, so the last one would not be counted as done.
+	 */
+	pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+								 hscan->rs_nblocks);
+
 	table_endscan(scan);
 
 	ExecDropSingleTupleTableSlot(slot);
-- 
2.56.0

