diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 0d038de1a23..6337d2a3d25 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -7685,8 +7685,10 @@ FROM pg_stat_get_backend_idset() AS backendid;
Whenever VACUUM is running, the
pg_stat_progress_vacuum 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
+ parallel vacuum) that is currently
+ vacuuming. The tables below describe the information
that will be reported and provide information about how to interpret it.
Progress for VACUUM FULL commands is reported via
pg_stat_progress_repack, and is also visible via
@@ -7944,10 +7946,61 @@ FROM pg_stat_get_backend_idset() AS backendid;
+
+
+
+ current_index_relidoid
+
+
+ OID of the index currently being vacuumed, or 0 if none is. This
+ field is only valid when the phase is
+ vacuuming indexes or
+ cleaning up indexes.
+
+
+
+
+
+ index_blks_totalbigint
+
+
+ Total number of blocks in the index identified by
+ current_index_relid. Only B-tree indexes
+ report this; it is 0 for other index access methods, and when no index
+ scan is in progress.
+
+
+
+
+
+ index_blks_donebigint
+
+
+ Number of blocks of that index scanned so far. It stops one block
+ short of index_blks_total, which counts the
+ index metapage, never scanned.
+
+
+
+
+
+ During a parallel vacuum, the leader and each of its workers reports its
+ own row, all sharing the same relid.
+ Only phase,
+ current_index_relid,
+ index_blks_total and
+ index_blks_done are maintained on a worker row;
+ the remaining columns track command-level progress that only the leader
+ maintains. Use leader_pid in
+ pg_stat_activity
+ to tell the leader row from its worker rows.
+
+
+
VACUUM Phases
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 997d84a77b3..1f684b81f82 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -3038,17 +3038,27 @@ 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.is_autovacuum = AmAutoVacuumWorkerProcess();
- 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.
*
@@ -3070,6 +3080,8 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat,
pfree(vacrel->indname);
vacrel->indname = NULL;
+ pgstat_progress_update_multi_param(3, reset_index, reset_val);
+
return istat;
}
@@ -3089,18 +3101,28 @@ 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.is_autovacuum = AmAutoVacuumWorkerProcess();
- 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.
*
@@ -3120,6 +3142,8 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
pfree(vacrel->indname);
vacrel->indname = NULL;
+ 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 da0ec3cc8ee..ac8ad6637b5 100644
--- a/src/backend/commands/vacuumparallel.c
+++ b/src/backend/commands/vacuumparallel.c
@@ -1115,6 +1115,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
@@ -1127,7 +1138,7 @@ parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel,
ivinfo.heaprel = pvs->heaprel;
ivinfo.analyze_only = false;
ivinfo.is_autovacuum = pvs->shared->is_autovacuum;
- 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;
@@ -1137,6 +1148,13 @@ 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 */
+ 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:
@@ -1152,6 +1170,8 @@ parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel,
RelationGetRelationName(indrel));
}
+ 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
@@ -1230,8 +1250,8 @@ parallel_vacuum_index_is_parallel_safe(Relation indrel, int num_index_scans,
/*
* Perform work within a launched parallel process.
*
- * Since parallel vacuum workers perform only index vacuum or index cleanup,
- * we don't need to report progress information.
+ * Parallel vacuum workers perform only index vacuum or index cleanup; they
+ * report progress for the index they are processing.
*/
void
parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
@@ -1355,6 +1375,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);
@@ -1374,6 +1397,8 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
/* Pop the error context stack */
error_context_stack = errcallback.previous;
+ pgstat_progress_end_command();
+
vac_close_indexes(nindexes, indrels, RowExclusiveLock);
table_close(rel, ShareUpdateExclusiveLock);
FreeAccessStrategy(pvs.bstrategy);
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 6f3e526de96..7f7667f6179 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -57,6 +57,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202609152
+#define CATALOG_VERSION_NO 202610021
#endif
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,