Hi,

On Wed, Sep 9, 2026 at 12:01 PM Masahiko Sawada <[email protected]> wrote:
>
> I'm studying the patch and discussion so I might be missing something,
> but let me share my thoughts on this patch:
>
> I think it's fine for a progress view to have an entry per backend,
> including parallel workers, so more than one row for a single command.
> If we ever implement parallel index rebuilding for REINDEX TABLE,
> where different workers rebuild different indexes, having one entry
> per worker in pg_stat_progress_create_index seems the straightforward
> thing to do. A dedicated view for workers, say
> pg_stat_progress_create_index_worker, would end up with mostly the
> same columns as pg_stat_progress_create_index.

Thanks for sharing the thoughts.

> I can also see Sami's point that the patch makes many of the existing
> columns of pg_stat_progress_vacuum no-op. But I'm not sure a dedicated
> worker view really avoids that. If a user wants the progress of one
> vacuum command they would join the two views, get one row per
> participant anyway, and the leader's heap columns would be repeated on
> every row. That's better than reporting them as 0, but the user still
> has to know which columns are command-level and which are
> backend-local. It might be worth clarifying the actual query and its
> output for each approach and comparing them.

Here's the sample output [1] with the two approaches, and yes, the
separate view for workers has repeated columns when joined to get the
progress report of a single vacuum command.

That said, I would like to mention an interesting and closely related
discussion on single view vs. separate view to show wait event info of
different processes in pg_stat_activity. The alignment there (almost
unanimously) was to go with the single view even if some of the
columns are not meaningful for certain processes (for example, most of
the pg_stat_activity columns are not applicable to auxiliary processes
such as the checkpointer, background writer, autovacuum launcher,
etc.): 
https://www.postgresql.org/message-id/CA%2BTgmoYES5nhkEGw9nZXU8\_FhA8XEm8NTm3-SO%2B3ML1B81Hkww%40mail.gmail.com.

As suggested upthread by Michael, I have merged the two patches (index
being vacuumed and index progress report) into a single patch since
they are closely related and there is no strong reason to keep them
separate. I also attached a 0002 patch that removes the now-unused
IndexVacuumInfo.report_progress field. Please find the attached v6
patch.

Note that I haven't added tests for pg_stat_progress_vacuum. It looks
like we have lived without them so far. I'm happy to add a simple
progress report test with parallel index vacuuming (I haven't checked,
but we may need an injection point to hold the parallel workers during
index vacuuming).

[1]
-- One row per worker
select * from pg_stat_progress_vacuum;

  pid  | datid | datname  | relid |       phase       |
heap_blks_total | heap_blks_scanned | heap_blks_vacuumed |
index_vacuum_count | max_dead_tuple_bytes | dead_tuple_bytes |
num_dead_item_ids | indexes_total | indexes_processed | delay_time |
mode  | started_by | current_index_relid | index_blks_total |
index_blks_done
-------+-------+----------+-------+-------------------+-----------------+-------------------+--------------------+--------------------+----------------------+------------------+-------------------+---------------+-------------------+------------+--------+------------+---------------------+------------------+-----------------
 24598 |     5 | postgres | 16408 | vacuuming indexes |
16667 |             12862 |                  0 |                  0 |
            1048576 |          1310720 |            352797 |
  4 |                 0 |          0 | normal | manual     |
    16413 |             5487 |             303
 24600 |     5 | postgres | 16408 | vacuuming indexes |
0 |                 0 |                  0 |                  0 |
              0 |                0 |                 0 |             0
|                 0 |          0 | (null) | (null)     |
16416 |             1754 |             130
 24601 |     5 | postgres | 16408 | vacuuming indexes |
0 |                 0 |                  0 |                  0 |
              0 |                0 |                 0 |             0
|                 0 |          0 | (null) | (null)     |
16414 |             5487 |             335
 24602 |     5 | postgres | 16408 | vacuuming indexes |
0 |                 0 |                  0 |                  0 |
              0 |                0 |                 0 |          0 |
               0 |          0 | (null) | (null)     |
16415 |             5487 |             291
(4 rows)

-- Separate views for leader and worker vacuum progress
select * from pg_stat_progress_vacuum v
     left join pg_stat_progress_vacuum_worker w
       on w.leader_pid = v.pid;

  pid  | datid | datname  | relid |       phase       |
heap_blks_total | heap_blks_scanned | heap_blks_vacuumed |
index_vacuum_count | max_dead_tuple_bytes | dead_tuple_bytes |
num_dead_item_ids | indexes_total | indexes_processed | delay_time |
mode  | started_by | current_index_relid | index_blks_total |
index_blks_done |  pid  | leader_pid | datid | datname  | relid |
 phase       | current_index_relid | index_blks_total |
index_blks_done
-------+-------+----------+-------+-------------------+-----------------+-------------------+--------------------+--------------------+----------------------+------------------+-------------------+---------------+-------------------+------------+--------+------------+---------------------+------------------+-----------------+-------+------------+-------+----------+-------+-------------------+---------------------+------------------+-----------------
 27109 |     5 | postgres | 16384 | vacuuming indexes |
16667 |             12862 |                  0 |                  0 |
            1048576 |          1310720 |            205920 |
  4 |                 0 |          0 | normal | manual     |
    16389 |             5487 |            1577 | 27110 |      27109 |
   5 | postgres | 16384 | vacuuming indexes |               16392 |
         1754 |            1070
 27109 |     5 | postgres | 16384 | vacuuming indexes |
16667 |             12862 |                  0 |                  0 |
            1048576 |          1310720 |            205920 |
  4 |                 0 |          0 | normal | manual     |
    16389 |             5487 |            1577 | 27111 |      27109 |
   5 | postgres | 16384 | vacuuming indexes |               16390 |
         5487 |            1583
 27109 |     5 | postgres | 16384 | vacuuming indexes |
16667 |             12862 |                  0 |                  0 |
            1048576 |          1310720 |            205920 |
  4 |                 0 |          0 | normal | manual     |
    16389 |             5487 |            1577 | 27112 |      27109 |
   5 | postgres | 16384 | vacuuming indexes |               16391 |
         5487 |            1599
(3 rows)

--
Bharath Rupireddy
Amazon Web Services: https://aws.amazon.com
From 39725d292975a40ba1245d4b9e254d16ecc31f59 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <[email protected]>
Date: Sun, 13 Sep 2026 05:19:26 +0000
Subject: [PATCH v6 1/2] Report per-index vacuum progress in
 pg_stat_progress_vacuum.

Previously, pg_stat_progress_vacuum showed the total and
processed index counts, but neither which index a backend was
working on nor how far it had gotten through it. On a table with
many indexes of different access methods, that made it hard to
tell which index a slow or stuck vacuum was spending its time on,
and for a large B-tree, at the scale of hundreds of GBs to TBs,
there was no way to estimate when the index phase, and together
with heap_blks_*, the whole vacuum would finish.

This commit adds three columns. current_index_relid reports the
OID of the index a backend is currently vacuuming or cleaning up.
index_blks_total and index_blks_done report block progress within
that index. All three are set before an index is processed and
reset once that index is done, so they do not report a stale
value after the phase moves on.

During parallel index vacuum the leader also participates, and
each participant processes a different set of indexes. That
per-index progress cannot be collapsed into a single leader row
without losing the detail that matters, so each participant, the
leader and the workers alike, now reports its own row and shows
the index it is processing and how far along it is. A worker row
carries the columns that come from its own backend state, pid,
datid, datname, relid, phase, current_index_relid,
index_blks_total and index_blks_done; the remaining columns track
command-level heap progress that only the leader maintains and
read as zero on worker rows. Because a table can be vacuumed by
only one VACUUM at a time, the rows sharing a datid and relid
make up a single vacuum, so they can be grouped that way to see
the leader together with all of its workers. If the exact
leader-to-worker mapping is wanted, it can be recovered from
leader_pid in pg_stat_activity.

The block counters are the ones CREATE INDEX progress reporting
added in commit ab0dfc961b6a, PROGRESS_SCAN_BLOCKS_TOTAL and
PROGRESS_SCAN_BLOCKS_DONE. B-tree's index scan already knows how
to report them, so all that is needed here is turning that
reporting on in the serial and parallel index vacuum paths; other
access methods report nothing and leave the two columns at zero.
They are deliberately kept separate from heap_blks_*, which must
be retained across a multi-pass index vacuum, the case where the
dead-TID store fills, and which in the serial case belong to the
same backend that is doing the index vacuuming, so reusing them
for index blocks would destroy heap progress that is still needed.

No caller sets IndexVacuumInfo.report_progress to false anymore;
the next commit removes the field.

XXX: Bump catalog version.

Author: Bharath Rupireddy <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Sami Imseih <[email protected]>
Reviewed-by: Masahiko Sawada <[email protected]>
Discussion: https://postgr.es/m/CALj2ACUgwSchK6jQ2CdKLBWUADTOE_zKdTff2Zg3E6hOuXKv-w@mail.gmail.com
---
 doc/src/sgml/monitoring.sgml          | 93 ++++++++++++++++++++++++++-
 src/backend/access/heap/vacuumlazy.c  | 36 ++++++++++-
 src/backend/catalog/system_views.sql  |  5 +-
 src/backend/commands/vacuumparallel.c | 35 +++++++++-
 src/include/commands/progress.h       |  2 +
 src/test/regress/expected/rules.out   |  5 +-
 6 files changed, 169 insertions(+), 7 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 49bf6b51c49..a699d95514e 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -7670,8 +7670,11 @@ FROM pg_stat_get_backend_idset() AS backendid;
   <para>
    Whenever <command>VACUUM</command> is running, the
    <structname>pg_stat_progress_vacuum</structname> view will contain
-   one row for each backend (including autovacuum worker processes) that is
-   currently vacuuming.  The tables below describe the information
+   one row for each backend (including autovacuum worker processes and
+   parallel workers launched for
+   <link linkend="sql-vacuum">parallel vacuum</link>) that is currently
+   vacuuming; see the note following the view for the columns reported on
+   parallel worker rows. The tables below describe the information
    that will be reported and provide information about how to interpret it.
    Progress for <command>VACUUM FULL</command> commands is reported via
    <structname>pg_stat_progress_repack</structname>, and is also visible via
@@ -7929,10 +7932,96 @@ FROM pg_stat_get_backend_idset() AS backendid;
        </itemizedlist>
       </para></entry>
      </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>current_index_relid</structfield> <type>oid</type>
+      </para>
+      <para>
+       If <command>VACUUM</command> is currently processing an index, this
+       column shows the OID of the index being vacuumed. The value is set
+       when the phase is <literal>vacuuming indexes</literal> or
+       <literal>cleaning up indexes</literal>, and is reset to 0 once that
+       index has been processed, so it does not show a stale index while the
+       backend is between indexes or has moved on to another phase. During
+       parallel index vacuum, each parallel worker row shows the index that
+       particular worker is processing.
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>index_blks_total</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Total number of blocks in the index identified by
+       <structfield>current_index_relid</structfield>. This is reported only
+       for B-tree indexes, and only while the index is being scanned; it is 0
+       for other index access methods, for a B-tree whose scan
+       <command>VACUUM</command> was able to skip during cleanup, and once
+       the index has been processed.
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>index_blks_done</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of blocks of the index identified by
+       <structfield>current_index_relid</structfield> scanned so far. This is
+       reported only for B-tree indexes, and only while the index is being
+       scanned; it is 0 for other index access methods, for a B-tree whose
+       scan <command>VACUUM</command> was able to skip during cleanup, and
+       once the index has been processed. Together with
+       <structfield>index_blks_total</structfield> this gives per-index vacuum
+       progress, which is useful for estimating completion of large indexes.
+       The index metapage is counted in
+       <structfield>index_blks_total</structfield> but is never scanned, so
+       this column stops one block short of it.
+      </para></entry>
+     </row>
+
     </tbody>
    </tgroup>
   </table>
 
+  <note>
+   <para>
+    During a parallel vacuum, each participating backend (the leader and each
+    parallel worker) reports its own row. On a worker row the meaningful
+    columns are <structfield>pid</structfield>, <structfield>datid</structfield>,
+    <structfield>datname</structfield>, <structfield>relid</structfield>,
+    <structfield>phase</structfield>, <structfield>current_index_relid</structfield>,
+    <structfield>index_blks_total</structfield> and
+    <structfield>index_blks_done</structfield>. The remaining columns track
+    command-level heap progress that only the leader maintains; they read as
+    zero on worker rows. A participant row showing
+    <literal>vacuuming indexes</literal> or
+    <literal>cleaning up indexes</literal> with a zero
+    <structfield>current_index_relid</structfield> is between indexes, or has
+    finished its share of the indexes while other participants are still
+    working. A worker row with a <literal>NULL</literal>
+    <structfield>phase</structfield> is a worker that has been launched but has
+    not started on an index yet, which also happens when every index was
+    claimed by another participant before this worker got to it. Because a
+    table can be vacuumed by only one
+    <command>VACUUM</command> at a time, the rows sharing a given
+    <structfield>datid</structfield> and <structfield>relid</structfield>
+    together make up a single vacuum, so they can be grouped that way to see
+    the leader and all of its workers. The leader and worker process IDs can be
+    correlated with <structfield>leader_pid</structfield> in
+    <link linkend="monitoring-pg-stat-activity-view"><structname>pg_stat_activity</structname></link>
+    if needed. Because the worker rows are separate backends, a role that does
+    not have privileges of the <literal>pg_read_all_stats</literal> role and
+    does not own those backends sees only their <structfield>pid</structfield>,
+    <structfield>datid</structfield> and <structfield>datname</structfield>,
+    with the remaining columns <literal>NULL</literal>, so such a role can tell
+    that a parallel vacuum is running in a database but not which table or
+    index it is working on.
+   </para>
+  </note>
+
   <table id="vacuum-phases">
    <title>VACUUM Phases</title>
    <tgroup cols="2">
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 063ef2208de..459fff8df1d 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -3038,16 +3038,26 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat,
 {
 	IndexVacuumInfo ivinfo;
 	LVSavedErrInfo saved_err_info;
+	const int	reset_index[] = {
+		PROGRESS_VACUUM_CURRENT_INDEX_RELID,
+		PROGRESS_SCAN_BLOCKS_TOTAL,
+		PROGRESS_SCAN_BLOCKS_DONE
+	};
+	const int64 reset_val[] = {(int64) InvalidOid, 0, 0};
 
 	ivinfo.index = indrel;
 	ivinfo.heaprel = vacrel->rel;
 	ivinfo.analyze_only = false;
-	ivinfo.report_progress = false;
+	ivinfo.report_progress = true;
 	ivinfo.estimated_count = true;
 	ivinfo.message_level = DEBUG2;
 	ivinfo.num_heap_tuples = reltuples;
 	ivinfo.strategy = vacrel->bstrategy;
 
+	/* Report which index we're currently processing */
+	pgstat_progress_update_param(PROGRESS_VACUUM_CURRENT_INDEX_RELID,
+								 (int64) RelationGetRelid(indrel));
+
 	/*
 	 * Update error traceback information.
 	 *
@@ -3069,6 +3079,12 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat,
 	pfree(vacrel->indname);
 	vacrel->indname = NULL;
 
+	/*
+	 * Reset the current index progress parameters to avoid reporting stale
+	 * values.
+	 */
+	pgstat_progress_update_multi_param(3, reset_index, reset_val);
+
 	return istat;
 }
 
@@ -3088,17 +3104,27 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
 {
 	IndexVacuumInfo ivinfo;
 	LVSavedErrInfo saved_err_info;
+	const int	reset_index[] = {
+		PROGRESS_VACUUM_CURRENT_INDEX_RELID,
+		PROGRESS_SCAN_BLOCKS_TOTAL,
+		PROGRESS_SCAN_BLOCKS_DONE
+	};
+	const int64 reset_val[] = {(int64) InvalidOid, 0, 0};
 
 	ivinfo.index = indrel;
 	ivinfo.heaprel = vacrel->rel;
 	ivinfo.analyze_only = false;
-	ivinfo.report_progress = false;
+	ivinfo.report_progress = true;
 	ivinfo.estimated_count = estimated_count;
 	ivinfo.message_level = DEBUG2;
 
 	ivinfo.num_heap_tuples = reltuples;
 	ivinfo.strategy = vacrel->bstrategy;
 
+	/* Report which index we're currently processing */
+	pgstat_progress_update_param(PROGRESS_VACUUM_CURRENT_INDEX_RELID,
+								 (int64) RelationGetRelid(indrel));
+
 	/*
 	 * Update error traceback information.
 	 *
@@ -3118,6 +3144,12 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
 	pfree(vacrel->indname);
 	vacrel->indname = NULL;
 
+	/*
+	 * Reset the current index progress parameters to avoid reporting stale
+	 * values.
+	 */
+	pgstat_progress_update_multi_param(3, reset_index, reset_val);
+
 	return istat;
 }
 
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index ad340887f54..809b9c0f1e4 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1353,7 +1353,10 @@ CREATE VIEW pg_stat_progress_vacuum AS
         CASE S.param13 WHEN 1 THEN 'manual'
                        WHEN 2 THEN 'autovacuum'
                        WHEN 3 THEN 'autovacuum_wraparound'
-                       ELSE NULL END AS started_by
+                       ELSE NULL END AS started_by,
+        CAST(S.param14 AS oid) AS current_index_relid,
+        S.param16 AS index_blks_total,
+        S.param17 AS index_blks_done
     FROM pg_stat_get_progress_info('VACUUM') AS S
         LEFT JOIN pg_database D ON S.datid = D.oid;
 
diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c
index 767d162e578..be87b1937ad 100644
--- a/src/backend/commands/vacuumparallel.c
+++ b/src/backend/commands/vacuumparallel.c
@@ -1076,6 +1076,17 @@ parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel,
 	IndexBulkDeleteResult *istat = NULL;
 	IndexBulkDeleteResult *istat_res;
 	IndexVacuumInfo ivinfo;
+	const int	progress_index[] = {
+		PROGRESS_VACUUM_PHASE,
+		PROGRESS_VACUUM_CURRENT_INDEX_RELID
+	};
+	int64		progress_val[2];
+	const int	reset_index[] = {
+		PROGRESS_VACUUM_CURRENT_INDEX_RELID,
+		PROGRESS_SCAN_BLOCKS_TOTAL,
+		PROGRESS_SCAN_BLOCKS_DONE
+	};
+	const int64 reset_val[] = {(int64) InvalidOid, 0, 0};
 
 	/*
 	 * Update the pointer to the corresponding bulk-deletion result if someone
@@ -1087,7 +1098,7 @@ parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel,
 	ivinfo.index = indrel;
 	ivinfo.heaprel = pvs->heaprel;
 	ivinfo.analyze_only = false;
-	ivinfo.report_progress = false;
+	ivinfo.report_progress = true;
 	ivinfo.message_level = DEBUG2;
 	ivinfo.estimated_count = pvs->shared->estimated_count;
 	ivinfo.num_heap_tuples = pvs->shared->reltuples;
@@ -1097,6 +1108,16 @@ parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel,
 	pvs->indname = pstrdup(RelationGetRelationName(indrel));
 	pvs->status = indstats->status;
 
+	/*
+	 * Report the phase and the index we're about to process before we start,
+	 * so that it is visible for the whole duration of the index scan.
+	 */
+	progress_val[0] = (indstats->status == PARALLEL_INDVAC_STATUS_NEED_BULKDELETE)
+		? PROGRESS_VACUUM_PHASE_VACUUM_INDEX
+		: PROGRESS_VACUUM_PHASE_INDEX_CLEANUP;
+	progress_val[1] = (int64) RelationGetRelid(indrel);
+	pgstat_progress_update_multi_param(2, progress_index, progress_val);
+
 	switch (indstats->status)
 	{
 		case PARALLEL_INDVAC_STATUS_NEED_BULKDELETE:
@@ -1112,6 +1133,12 @@ parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel,
 				 RelationGetRelationName(indrel));
 	}
 
+	/*
+	 * Reset the current index progress parameters to avoid reporting stale
+	 * values.
+	 */
+	pgstat_progress_update_multi_param(3, reset_index, reset_val);
+
 	/*
 	 * Copy the index bulk-deletion result returned from ambulkdelete and
 	 * amvacuumcleanup to the DSM segment if it's the first cycle because they
@@ -1315,6 +1342,9 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
 	/* Prepare to track buffer usage during parallel execution */
 	InstrStartParallelQuery();
 
+	/* Register this worker for vacuum progress reporting */
+	pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM, shared->relid);
+
 	/* Process indexes to perform vacuum/cleanup */
 	parallel_vacuum_process_safe_indexes(&pvs);
 
@@ -1334,6 +1364,9 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
 	/* Pop the error context stack */
 	error_context_stack = errcallback.previous;
 
+	/* Unregister this worker from vacuum progress reporting */
+	pgstat_progress_end_command();
+
 	vac_close_indexes(nindexes, indrels, RowExclusiveLock);
 	table_close(rel, ShareUpdateExclusiveLock);
 	FreeAccessStrategy(pvs.bstrategy);
diff --git a/src/include/commands/progress.h b/src/include/commands/progress.h
index 2a12920c75f..bf91455eff9 100644
--- a/src/include/commands/progress.h
+++ b/src/include/commands/progress.h
@@ -31,6 +31,8 @@
 #define PROGRESS_VACUUM_DELAY_TIME				10
 #define PROGRESS_VACUUM_MODE					11
 #define PROGRESS_VACUUM_STARTED_BY				12
+#define PROGRESS_VACUUM_CURRENT_INDEX_RELID		13
+/* 15 and 16 reserved for "block number" metrics */
 
 /* Phases of vacuum (as advertised via PROGRESS_VACUUM_PHASE) */
 #define PROGRESS_VACUUM_PHASE_SCAN_HEAP			1
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 4a8cc759d7b..0addd043e68 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -2214,7 +2214,10 @@ pg_stat_progress_vacuum| SELECT s.pid,
             WHEN 2 THEN 'autovacuum'::text
             WHEN 3 THEN 'autovacuum_wraparound'::text
             ELSE NULL::text
-        END AS started_by
+        END AS started_by,
+    (s.param14)::oid AS current_index_relid,
+    s.param16 AS index_blks_total,
+    s.param17 AS index_blks_done
    FROM (pg_stat_get_progress_info('VACUUM'::text) s(pid, datid, relid, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20)
      LEFT JOIN pg_database d ON ((s.datid = d.oid)));
 pg_stat_recovery| SELECT promote_triggered,
-- 
2.47.3

From e25111f8b4142e2087ee0e38b23b406bef74f871 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <[email protected]>
Date: Sun, 13 Sep 2026 06:58:05 +0000
Subject: [PATCH v6 2/2] Remove IndexVacuumInfo.report_progress.

Commit ab0dfc961b6a, which added progress reporting for CREATE
INDEX, introduced report_progress so that the block counters
PROGRESS_SCAN_BLOCKS_TOTAL and PROGRESS_SCAN_BLOCKS_DONE were
reported only during index validation. Commit XXXX now enables
vacuum to report them as well, so every caller sets the field to
true. B-tree is the only access method that reads it.

Remove the field and report the counters unconditionally in
btvacuumscan(). An out-of-tree index access method that sets
report_progress needs a trivial adjustment.

Author: Bharath Rupireddy <[email protected]>
Discussion: https://postgr.es/m/CALj2ACUgwSchK6jQ2CdKLBWUADTOE_zKdTff2Zg3E6hOuXKv-w@mail.gmail.com
---
 src/backend/access/heap/vacuumlazy.c  | 2 --
 src/backend/access/nbtree/nbtree.c    | 9 +++------
 src/backend/catalog/index.c           | 1 -
 src/backend/commands/vacuumparallel.c | 1 -
 src/include/access/genam.h            | 1 -
 5 files changed, 3 insertions(+), 11 deletions(-)

diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 459fff8df1d..dd6a37f65c1 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -3048,7 +3048,6 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat,
 	ivinfo.index = indrel;
 	ivinfo.heaprel = vacrel->rel;
 	ivinfo.analyze_only = false;
-	ivinfo.report_progress = true;
 	ivinfo.estimated_count = true;
 	ivinfo.message_level = DEBUG2;
 	ivinfo.num_heap_tuples = reltuples;
@@ -3114,7 +3113,6 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
 	ivinfo.index = indrel;
 	ivinfo.heaprel = vacrel->rel;
 	ivinfo.analyze_only = false;
-	ivinfo.report_progress = true;
 	ivinfo.estimated_count = estimated_count;
 	ivinfo.message_level = DEBUG2;
 
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 0abdd7b49f5..a4c3ad1b0f6 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -1339,9 +1339,7 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 		if (needLock)
 			UnlockRelationForExtension(rel, ExclusiveLock);
 
-		if (info->report_progress)
-			pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL,
-										 num_pages);
+		pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_TOTAL, num_pages);
 
 		/* Quit if we've scanned the whole relation */
 		if (p.current_blocknum >= num_pages)
@@ -1365,9 +1363,8 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 
 			current_block = btvacuumpage(&vstate, buf);
 
-			if (info->report_progress)
-				pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
-											 current_block);
+			pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
+										 current_block);
 		}
 
 		/*
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index ec21b83b6b8..a3768e8daf7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3455,7 +3455,6 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
 	ivinfo.index = indexRelation;
 	ivinfo.heaprel = heapRelation;
 	ivinfo.analyze_only = false;
-	ivinfo.report_progress = true;
 	ivinfo.estimated_count = true;
 	ivinfo.message_level = DEBUG2;
 	ivinfo.num_heap_tuples = heapRelation->rd_rel->reltuples;
diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c
index be87b1937ad..74f749de064 100644
--- a/src/backend/commands/vacuumparallel.c
+++ b/src/backend/commands/vacuumparallel.c
@@ -1098,7 +1098,6 @@ parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel,
 	ivinfo.index = indrel;
 	ivinfo.heaprel = pvs->heaprel;
 	ivinfo.analyze_only = false;
-	ivinfo.report_progress = true;
 	ivinfo.message_level = DEBUG2;
 	ivinfo.estimated_count = pvs->shared->estimated_count;
 	ivinfo.num_heap_tuples = pvs->shared->reltuples;
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index 68bfe405db3..64a44889ceb 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -54,7 +54,6 @@ typedef struct IndexVacuumInfo
 	Relation	index;			/* the index being vacuumed */
 	Relation	heaprel;		/* the heap relation the index belongs to */
 	bool		analyze_only;	/* ANALYZE (without any actual vacuum) */
-	bool		report_progress;	/* emit progress.h status reports */
 	bool		estimated_count;	/* num_heap_tuples is an estimate */
 	int			message_level;	/* ereport level for progress messages */
 	double		num_heap_tuples;	/* tuples remaining in heap */
-- 
2.47.3

Reply via email to