From 51f3c2856a2b583dc83c477cb03add67f363c058 Mon Sep 17 00:00:00 2001 From: Daniil Davidov Date: Sun, 23 Nov 2025 01:07:47 +0700 Subject: [PATCH v25 2/5] Logging for parallel autovacuum --- src/backend/access/heap/vacuumlazy.c | 54 ++++++++++++++++++++++++++- src/backend/commands/vacuumparallel.c | 32 +++++++++++++--- src/include/commands/vacuum.h | 39 ++++++++++++++++++- src/tools/pgindent/typedefs.list | 2 + 4 files changed, 117 insertions(+), 10 deletions(-) diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index 82c5b28e0ad..28624d3ba25 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -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 scans. + */ + PVWorkersUsage workers_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->workers_usage.vacuum.nlaunched = 0; + vacrel->workers_usage.vacuum.nplanned = 0; + vacrel->workers_usage.cleanup.nlaunched = 0; + vacrel->workers_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,42 @@ 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->workers_usage.vacuum.nplanned > 0) + { + if (AmAutoVacuumWorkerProcess()) + { + appendStringInfo(&buf, + _("parallel workers: index vacuum: %d planned, %d reserved, %d launched in total\n"), + vacrel->workers_usage.vacuum.nplanned, + vacrel->workers_usage.vacuum.nreserved, + vacrel->workers_usage.vacuum.nlaunched); + } + else + { + appendStringInfo(&buf, + _("parallel workers: index vacuum: %d planned, %d launched in total\n"), + vacrel->workers_usage.vacuum.nplanned, + vacrel->workers_usage.vacuum.nlaunched); + } + } + if (vacrel->workers_usage.cleanup.nplanned > 0) + { + if (AmAutoVacuumWorkerProcess()) + { + appendStringInfo(&buf, + _("parallel workers: index cleanup: %d planned, %d reserved, %d launched\n"), + vacrel->workers_usage.cleanup.nplanned, + vacrel->workers_usage.cleanup.nreserved, + vacrel->workers_usage.cleanup.nlaunched); + } + else + { + appendStringInfo(&buf, + _("parallel workers: index cleanup: %d planned, %d launched\n"), + vacrel->workers_usage.cleanup.nplanned, + vacrel->workers_usage.cleanup.nlaunched); + } + } for (int i = 0; i < vacrel->nindexes; i++) { IndexBulkDeleteResult *istat = vacrel->indstats[i]; @@ -2669,7 +2717,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->workers_usage); /* * Do a postcheck to consider applying wraparound failsafe now. Note @@ -3103,7 +3152,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->workers_usage); } /* Reset the progress counters */ diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c index 806a7f48326..643849b2fb8 100644 --- a/src/backend/commands/vacuumparallel.c +++ b/src/backend/commands/vacuumparallel.c @@ -228,7 +228,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, PVWorkersStats *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, @@ -503,7 +503,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, PVWorkersUsage *wusage) { Assert(!IsParallelWorker()); @@ -514,7 +514,8 @@ 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, + &wusage->vacuum); } /* @@ -522,7 +523,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, + PVWorkersUsage *wusage) { Assert(!IsParallelWorker()); @@ -534,7 +536,8 @@ 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, + &wusage->cleanup); } /* @@ -616,10 +619,13 @@ 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 statistics it stores will be updated according + * to what happens during function execution. */ static void parallel_vacuum_process_all_indexes(ParallelVacuumState *pvs, int num_index_scans, - bool vacuum) + bool vacuum, PVWorkersStats *wstats) { int nworkers; PVIndVacStatus new_status; @@ -656,13 +662,23 @@ parallel_vacuum_process_all_indexes(ParallelVacuumState *pvs, int num_index_scan */ nworkers = Min(nworkers, pvs->pcxt->nworkers); + /* Remember this value, if we asked to */ + if (wstats != NULL && nworkers > 0) + wstats->nplanned += nworkers; + /* * Reserve workers in autovacuum global state. Note that we may be given * fewer workers than we requested. */ if (AmAutoVacuumWorkerProcess() && nworkers > 0) + { AutoVacuumReserveParallelWorkers(&nworkers); + /* Remember this value, if we asked to */ + if (wstats != NULL) + wstats->nreserved += nworkers; + } + /* * Set index vacuum status and mark whether parallel vacuum worker can * process it. @@ -729,6 +745,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); + + /* Remember this value, if we asked to */ + if (wstats != NULL) + wstats->nlaunched += pvs->pcxt->nworkers_launched; } if (vacuum) diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index e885a4b9c77..1b1fb625cb2 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -300,6 +300,39 @@ typedef struct VacDeadItemsInfo int64 num_items; /* current # of entries */ } VacDeadItemsInfo; +/* + * Helper for the PVWorkersUsage structure (see below), to avoid repetition. + */ +typedef struct PVWorkersStats +{ + /* Number of parallel workers we are planned to launch */ + int nplanned; + + /* + * Number of parallel workers we have managed to reserve. + * + * Note, that we collect this stats only for the parallel *autovacuum* + * since during it we must reserve workers in shared state before actually + * trying to launch them (in order to meet the + * autovacuum_max_parallel_workers limit). Manual VACUUM (PARALLEL), on + * the contrary, doesn't need to reserve workers. + */ + int nreserved; + + /* Number of launched parallel workers */ + int nlaunched; +} PVWorkersStats; + +/* + * PVWorkersUsage stores information about total number of launched, reserved + * and planned workers during parallel vacuum (both for vacuum and cleanup). + */ +typedef struct PVWorkersUsage +{ + PVWorkersStats vacuum; + PVWorkersStats cleanup; +} PVWorkersUsage; + /* GUC parameters */ extern PGDLLIMPORT int default_statistics_target; /* PGDLLIMPORT for PostGIS */ extern PGDLLIMPORT int vacuum_freeze_min_age; @@ -394,11 +427,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, + PVWorkersUsage *wusage); extern void parallel_vacuum_cleanup_all_indexes(ParallelVacuumState *pvs, long num_table_tuples, int num_index_scans, - bool estimated_count); + bool estimated_count, + PVWorkersUsage *wusage); extern void parallel_vacuum_main(dsm_segment *seg, shm_toc *toc); /* in commands/analyze.c */ diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 3da19d41413..0fb40f3c07f 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2071,6 +2071,8 @@ PVIndStats PVIndVacStatus PVOID PVShared +PVWorkersUsage +PVWorkersStats PX_Alias PX_Cipher PX_Combo -- 2.43.0