]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Add parallel vacuum worker usage to VACUUM (VERBOSE) and autovacuum logs.
authorMasahiko Sawada <msawada@postgresql.org>
Thu, 19 Mar 2026 22:01:47 +0000 (15:01 -0700)
committerMasahiko Sawada <msawada@postgresql.org>
Thu, 19 Mar 2026 22:01:47 +0000 (15:01 -0700)
This commit adds both the number of parallel workers planned and the
number of parallel workers actually launched to the output of
VACUUM (VERBOSE) and autovacuum logs.

Previously, this information was only reported as an INFO message
during VACUUM (VERBOSE), which meant it was not included in autovacuum
logs in practice. Although autovacuum does not yet support parallel
vacuum, a subsequent patch will enable it and utilize these logs in
its regression tests. This change also improves observability by
making it easier to verify if parallel vacuum is utilizing the
expected number of workers.

Author: Daniil Davydov <3danissimo@gmail.com>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-by: Sami Imseih <samimseih@gmail.com>
Discussion: https://postgr.es/m/CACG=ezZOrNsuLoETLD1gAswZMuH2nGGq7Ogcc0QOE5hhWaw=cw@mail.gmail.com

src/backend/access/heap/vacuumlazy.c
src/backend/commands/vacuumparallel.c
src/include/commands/vacuum.h
src/tools/pgindent/typedefs.list

index 82c5b28e0ad55b9bd75435c8bbcb450fc88688aa..c57432670e71a3e0eed15678324274c1860214b5 100644 (file)
@@ -343,6 +343,13 @@ typedef struct LVRelState
        int                     num_index_scans;
        int                     num_dead_items_resets;
        Size            total_dead_items_bytes;
+
+       /*
+        * Total number of planned and actually launched parallel workers for
+        * index vacuuming and index cleanup.
+        */
+       PVWorkerUsage worker_usage;
+
        /* Counters that follow are only for scanned_pages */
        int64           tuples_deleted; /* # deleted from table */
        int64           tuples_frozen;  /* # newly frozen */
@@ -781,6 +788,11 @@ heap_vacuum_rel(Relation rel, const VacuumParams params,
        vacrel->new_all_visible_all_frozen_pages = 0;
        vacrel->new_all_frozen_pages = 0;
 
+       vacrel->worker_usage.vacuum.nlaunched = 0;
+       vacrel->worker_usage.vacuum.nplanned = 0;
+       vacrel->worker_usage.cleanup.nlaunched = 0;
+       vacrel->worker_usage.cleanup.nplanned = 0;
+
        /*
         * Get cutoffs that determine which deleted tuples are considered DEAD,
         * not just RECENTLY_DEAD, and which XIDs/MXIDs to freeze.  Then determine
@@ -1123,6 +1135,19 @@ heap_vacuum_rel(Relation rel, const VacuumParams params,
                                                         orig_rel_pages == 0 ? 100.0 :
                                                         100.0 * vacrel->lpdead_item_pages / orig_rel_pages,
                                                         vacrel->lpdead_items);
+
+                       if (vacrel->worker_usage.vacuum.nplanned > 0)
+                               appendStringInfo(&buf,
+                                                                _("parallel workers: index vacuum: %d planned, %d launched in total\n"),
+                                                                vacrel->worker_usage.vacuum.nplanned,
+                                                                vacrel->worker_usage.vacuum.nlaunched);
+
+                       if (vacrel->worker_usage.cleanup.nplanned > 0)
+                               appendStringInfo(&buf,
+                                                                _("parallel workers: index cleanup: %d planned, %d launched\n"),
+                                                                vacrel->worker_usage.cleanup.nplanned,
+                                                                vacrel->worker_usage.cleanup.nlaunched);
+
                        for (int i = 0; i < vacrel->nindexes; i++)
                        {
                                IndexBulkDeleteResult *istat = vacrel->indstats[i];
@@ -2669,7 +2694,8 @@ lazy_vacuum_all_indexes(LVRelState *vacrel)
        {
                /* Outsource everything to parallel variant */
                parallel_vacuum_bulkdel_all_indexes(vacrel->pvs, old_live_tuples,
-                                                                                       vacrel->num_index_scans);
+                                                                                       vacrel->num_index_scans,
+                                                                                       &(vacrel->worker_usage.vacuum));
 
                /*
                 * Do a postcheck to consider applying wraparound failsafe now.  Note
@@ -3103,7 +3129,8 @@ lazy_cleanup_all_indexes(LVRelState *vacrel)
                /* Outsource everything to parallel variant */
                parallel_vacuum_cleanup_all_indexes(vacrel->pvs, reltuples,
                                                                                        vacrel->num_index_scans,
-                                                                                       estimated_count);
+                                                                                       estimated_count,
+                                                                                       &(vacrel->worker_usage.cleanup));
        }
 
        /* Reset the progress counters */
index 279108ca89f0b4e1af1101c412439893a4ee1e4f..77834b96a21c1d3f2a8d0b8f93150e1eec55fb84 100644 (file)
@@ -225,7 +225,7 @@ struct ParallelVacuumState
 static int     parallel_vacuum_compute_workers(Relation *indrels, int nindexes, int nrequested,
                                                                                        bool *will_parallel_vacuum);
 static void parallel_vacuum_process_all_indexes(ParallelVacuumState *pvs, int num_index_scans,
-                                                                                               bool vacuum);
+                                                                                               bool vacuum, PVWorkerStats *wstats);
 static void parallel_vacuum_process_safe_indexes(ParallelVacuumState *pvs);
 static void parallel_vacuum_process_unsafe_indexes(ParallelVacuumState *pvs);
 static void parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel,
@@ -499,7 +499,7 @@ parallel_vacuum_reset_dead_items(ParallelVacuumState *pvs)
  */
 void
 parallel_vacuum_bulkdel_all_indexes(ParallelVacuumState *pvs, long num_table_tuples,
-                                                                       int num_index_scans)
+                                                                       int num_index_scans, PVWorkerStats *wstats)
 {
        Assert(!IsParallelWorker());
 
@@ -510,7 +510,7 @@ parallel_vacuum_bulkdel_all_indexes(ParallelVacuumState *pvs, long num_table_tup
        pvs->shared->reltuples = num_table_tuples;
        pvs->shared->estimated_count = true;
 
-       parallel_vacuum_process_all_indexes(pvs, num_index_scans, true);
+       parallel_vacuum_process_all_indexes(pvs, num_index_scans, true, wstats);
 }
 
 /*
@@ -518,7 +518,8 @@ parallel_vacuum_bulkdel_all_indexes(ParallelVacuumState *pvs, long num_table_tup
  */
 void
 parallel_vacuum_cleanup_all_indexes(ParallelVacuumState *pvs, long num_table_tuples,
-                                                                       int num_index_scans, bool estimated_count)
+                                                                       int num_index_scans, bool estimated_count,
+                                                                       PVWorkerStats *wstats)
 {
        Assert(!IsParallelWorker());
 
@@ -530,7 +531,7 @@ parallel_vacuum_cleanup_all_indexes(ParallelVacuumState *pvs, long num_table_tup
        pvs->shared->reltuples = num_table_tuples;
        pvs->shared->estimated_count = estimated_count;
 
-       parallel_vacuum_process_all_indexes(pvs, num_index_scans, false);
+       parallel_vacuum_process_all_indexes(pvs, num_index_scans, false, wstats);
 }
 
 /*
@@ -607,10 +608,12 @@ parallel_vacuum_compute_workers(Relation *indrels, int nindexes, int nrequested,
 /*
  * Perform index vacuum or index cleanup with parallel workers.  This function
  * must be used by the parallel vacuum leader process.
+ *
+ * If wstats is not NULL, the parallel worker statistics are updated.
  */
 static void
 parallel_vacuum_process_all_indexes(ParallelVacuumState *pvs, int num_index_scans,
-                                                                       bool vacuum)
+                                                                       bool vacuum, PVWorkerStats *wstats)
 {
        int                     nworkers;
        PVIndVacStatus new_status;
@@ -647,6 +650,10 @@ parallel_vacuum_process_all_indexes(ParallelVacuumState *pvs, int num_index_scan
         */
        nworkers = Min(nworkers, pvs->pcxt->nworkers);
 
+       /* Update the statistics, if we asked to */
+       if (wstats != NULL && nworkers > 0)
+               wstats->nplanned += nworkers;
+
        /*
         * Set index vacuum status and mark whether parallel vacuum worker can
         * process it.
@@ -703,6 +710,10 @@ parallel_vacuum_process_all_indexes(ParallelVacuumState *pvs, int num_index_scan
                        /* Enable shared cost balance for leader backend */
                        VacuumSharedCostBalance = &(pvs->shared->cost_balance);
                        VacuumActiveNWorkers = &(pvs->shared->active_nworkers);
+
+                       /* Update the statistics, if we asked to */
+                       if (wstats != NULL)
+                               wstats->nlaunched += pvs->pcxt->nworkers_launched;
                }
 
                if (vacuum)
index e885a4b9c77d8f69cce317bc20442bd45d5c5a54..953a506181eee4821f5984376037d9a9fa1635d3 100644 (file)
@@ -300,6 +300,28 @@ typedef struct VacDeadItemsInfo
        int64           num_items;              /* current # of entries */
 } VacDeadItemsInfo;
 
+/*
+ * Statistics for parallel vacuum workers (planned vs. actual)
+ */
+typedef struct PVWorkerStats
+{
+       /* Number of parallel workers planned to launch */
+       int                     nplanned;
+
+       /* Number of parallel workers that were successfully launched */
+       int                     nlaunched;
+} PVWorkerStats;
+
+/*
+ * PVWorkerUsage stores information about total number of launched and
+ * planned workers during parallel vacuum (both for index vacuum and cleanup).
+ */
+typedef struct PVWorkerUsage
+{
+       PVWorkerStats vacuum;
+       PVWorkerStats cleanup;
+} PVWorkerUsage;
+
 /* GUC parameters */
 extern PGDLLIMPORT int default_statistics_target;      /* PGDLLIMPORT for PostGIS */
 extern PGDLLIMPORT int vacuum_freeze_min_age;
@@ -394,11 +416,13 @@ extern TidStore *parallel_vacuum_get_dead_items(ParallelVacuumState *pvs,
 extern void parallel_vacuum_reset_dead_items(ParallelVacuumState *pvs);
 extern void parallel_vacuum_bulkdel_all_indexes(ParallelVacuumState *pvs,
                                                                                                long num_table_tuples,
-                                                                                               int num_index_scans);
+                                                                                               int num_index_scans,
+                                                                                               PVWorkerStats *wstats);
 extern void parallel_vacuum_cleanup_all_indexes(ParallelVacuumState *pvs,
                                                                                                long num_table_tuples,
                                                                                                int num_index_scans,
-                                                                                               bool estimated_count);
+                                                                                               bool estimated_count,
+                                                                                               PVWorkerStats *wstats);
 extern void parallel_vacuum_main(dsm_segment *seg, shm_toc *toc);
 
 /* in commands/analyze.c */
index 4673eca9cd61806bc829026cf926596549d50c6b..a4a2ed0781695d9aefb26e9b2848fab226cfacd3 100644 (file)
@@ -2090,6 +2090,8 @@ PVIndStats
 PVIndVacStatus
 PVOID
 PVShared
+PVWorkerUsage
+PVWorkerStats
 PX_Alias
 PX_Cipher
 PX_Combo