1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Report per-index vacuum progress in pg_stat_progress_vacuum

pg_stat_progress_vacuum gains three fields, reflecting some activity
related to index cleanups during VACUUM, which is a phase that could
take a long time depending on the quantity of data to treat and the
number of indexes:
- current_index_relid, the index being processed.
- index_blks_total, total number of blocks to process.
- index_blks_done, number of blocks already processed.

There fields are new, and do not reuse the existing fields related to
heap as index cleanups may need multiple passes, where knowing both the
heap activity and the index activity could be relevant.  This is
unlikely since tids are accumulated in the heap scanning phase using an
optimized radix tree, still possible.  VACUUM can spawn parallel workers
to clean indexes (each worker cleans a different index); these should up
in the progress view in the shape of one extra row for each worker.

Bump catalog version.

Author: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Reviewed-by: Sami Imseih <samimseih@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-by: Shihao Zhong <zhong950419@gmail.com>
Discussion: https://postgr.es/m/CALj2ACUgwSchK6jQ2CdKLBWUADTOE_zKdTff2Zg3E6hOuXKv-w@mail.gmail.com
This commit is contained in:
Michael Paquier
2026-10-02 07:29:22 +09:00
parent 42e96cf2fe
commit 1378aa1343
7 changed files with 120 additions and 10 deletions

View File

@@ -7685,8 +7685,10 @@ 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. 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
@@ -7944,10 +7946,61 @@ 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>
OID of the index currently being vacuumed, or 0 if none is. This
field is only valid when the phase is
<literal>vacuuming indexes</literal> or
<literal>cleaning up indexes</literal>.
</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>. Only B-tree indexes
report this; it is 0 for other index access methods, and when no index
scan is in progress.
</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 that index scanned so far. It stops one block
short of <structfield>index_blks_total</structfield>, which counts the
index metapage, never scanned.
</para></entry>
</row>
</tbody>
</tgroup>
</table>
<note>
<para>
During a parallel vacuum, the leader and each of its workers reports its
own row, all sharing the same <structfield>relid</structfield>.
Only <structfield>phase</structfield>,
<structfield>current_index_relid</structfield>,
<structfield>index_blks_total</structfield> and
<structfield>index_blks_done</structfield> are maintained on a worker row;
the remaining columns track command-level progress that only the leader
maintains. Use <structfield>leader_pid</structfield> in
<link linkend="monitoring-pg-stat-activity-view"><structname>pg_stat_activity</structname></link>
to tell the leader row from its worker rows.
</para>
</note>
<table id="vacuum-phases">
<title>VACUUM Phases</title>
<tgroup cols="2">

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -57,6 +57,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 202609152
#define CATALOG_VERSION_NO 202610021
#endif

View File

@@ -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

View File

@@ -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,