From ba30e217073cee821cd842f12ed91e4c10adb255 Mon Sep 17 00:00:00 2001 From: Daniil Davidov Date: Thu, 15 Jan 2026 23:15:48 +0700 Subject: [PATCH v19 3/5] Cost based parameters propagation for parallel autovacuum --- src/backend/commands/vacuum.c | 29 +++++++- src/backend/commands/vacuumparallel.c | 99 +++++++++++++++++++++++++++ src/backend/postmaster/autovacuum.c | 2 +- src/include/commands/vacuum.h | 2 + 4 files changed, 129 insertions(+), 3 deletions(-) diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index aa4fbec143f..4622107734f 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2430,8 +2430,27 @@ vacuum_delay_point(bool is_analyze) /* Always check for interrupts */ CHECK_FOR_INTERRUPTS(); - if (InterruptPending || - (!VacuumCostActive && !ConfigReloadPending)) + if (InterruptPending) + return; + + if (!AmAutoVacuumWorkerProcess()) + { + /* + * If we are parallel *autovacuum* worker, check whether related to + * cost-based delay parameters had changed in the leader worker. If + * so, corresponding parameters will be updated to the values which + * leader worker is operating on. + * + * Do it before checking VacuumCostActive, because its value might be + * changed after leader's parameters consumption. + * + * Note, that this function has no effect if we are non-autovacuum + * parallel worker. + */ + parallel_vacuum_update_shared_delay_params(); + } + + if (!VacuumCostActive && !ConfigReloadPending) return; /* @@ -2445,6 +2464,12 @@ vacuum_delay_point(bool is_analyze) ConfigReloadPending = false; ProcessConfigFile(PGC_SIGHUP); VacuumUpdateCosts(); + + /* + * If we are parallel autovacuum leader and some of cost-based + * parameters had changed, let other parallel workers know. + */ + parallel_vacuum_propagate_cost_based_params(); } /* diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c index c32314f9731..71449630b63 100644 --- a/src/backend/commands/vacuumparallel.c +++ b/src/backend/commands/vacuumparallel.c @@ -53,6 +53,25 @@ #define PARALLEL_VACUUM_KEY_WAL_USAGE 4 #define PARALLEL_VACUUM_KEY_INDEX_STATS 5 +/* + * Only autovacuum leader can reload config file. We use this structure in + * parallel autovacuum for keeping worker's parameters in sync with leader's + * parameters. + */ +typedef struct PVSharedCostParams +{ + slock_t spinlock; /* protects all fields below */ + + /* Copies of corresponding parameters from autovacuum leader process */ + double cost_delay; + int cost_limit; + int cost_page_dirty; + int cost_page_hit; + int cost_page_miss; +} PVSharedCostParams; + +static PVSharedCostParams * pv_shared_cost_params = NULL; + /* * Shared information among parallel workers. So this is allocated in the DSM * segment. @@ -122,6 +141,18 @@ typedef struct PVShared /* Statistics of shared dead items */ VacDeadItemsInfo dead_items_info; + + /* + * If 'true' then we are running parallel autovacuum. Otherwise, we are + * running parallel maintenence VACUUM. + */ + bool am_parallel_autovacuum; + + /* + * Struct for syncing parameters between supportive parallel autovacuum + * workers with leader worker. + */ + PVSharedCostParams cost_params; } PVShared; /* Status used during parallel index vacuum or cleanup */ @@ -395,6 +426,19 @@ parallel_vacuum_init(Relation rel, Relation *indrels, int nindexes, pg_atomic_init_u32(&(shared->active_nworkers), 0); pg_atomic_init_u32(&(shared->idx), 0); + shared->am_parallel_autovacuum = AmAutoVacuumWorkerProcess(); + + if (shared->am_parallel_autovacuum) + { + shared->cost_params.cost_delay = vacuum_cost_delay; + shared->cost_params.cost_limit = vacuum_cost_limit; + shared->cost_params.cost_page_dirty = VacuumCostPageDirty; + shared->cost_params.cost_page_hit = VacuumCostPageHit; + shared->cost_params.cost_page_miss = VacuumCostPageMiss; + SpinLockInit(&shared->cost_params.spinlock); + pv_shared_cost_params = &(shared->cost_params); + } + shm_toc_insert(pcxt->toc, PARALLEL_VACUUM_KEY_SHARED, shared); pvs->shared = shared; @@ -537,6 +581,58 @@ parallel_vacuum_cleanup_all_indexes(ParallelVacuumState *pvs, long num_table_tup parallel_vacuum_process_all_indexes(pvs, num_index_scans, false, wusage); } +/* + * Function to be called from parallel autovacuum worker in order to sync + * some cost-based delay parameter with the leader worker. + */ +bool +parallel_vacuum_update_shared_delay_params(void) +{ + /* Check whether we are running parallel autovacuum */ + if (pv_shared_cost_params == NULL) + return false; + + Assert(IsParallelWorker() && !AmAutoVacuumWorkerProcess()); + + SpinLockAcquire(&pv_shared_cost_params->spinlock); + + VacuumCostDelay = pv_shared_cost_params->cost_delay; + VacuumCostLimit = pv_shared_cost_params->cost_limit; + VacuumCostPageDirty = pv_shared_cost_params->cost_page_dirty; + VacuumCostPageHit = pv_shared_cost_params->cost_page_hit; + VacuumCostPageMiss = pv_shared_cost_params->cost_page_miss; + + SpinLockRelease(&pv_shared_cost_params->spinlock); + + VacuumUpdateCosts(); + + return true; +} + +/* + * Function to be called from parallel autovacuum leader in order to propagate + * some cost-based parameters to the supportive workers. + */ +void +parallel_vacuum_propagate_cost_based_params(void) +{ + /* Check whether we are running parallel autovacuum */ + if (pv_shared_cost_params == NULL) + return; + + Assert(AmAutoVacuumWorkerProcess()); + + SpinLockAcquire(&pv_shared_cost_params->spinlock); + + pv_shared_cost_params->cost_delay = vacuum_cost_delay; + pv_shared_cost_params->cost_limit = vacuum_cost_limit; + pv_shared_cost_params->cost_page_dirty = VacuumCostPageDirty; + pv_shared_cost_params->cost_page_hit = VacuumCostPageHit; + pv_shared_cost_params->cost_page_miss = VacuumCostPageMiss; + + SpinLockRelease(&pv_shared_cost_params->spinlock); +} + /* * Compute the number of parallel worker processes to request. Both index * vacuum and index cleanup can be executed with parallel workers. @@ -1094,6 +1190,9 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc) VacuumSharedCostBalance = &(shared->cost_balance); VacuumActiveNWorkers = &(shared->active_nworkers); + if (shared->am_parallel_autovacuum) + pv_shared_cost_params = &(shared->cost_params); + /* Set parallel vacuum state */ pvs.indrels = indrels; pvs.nindexes = nindexes; diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 097b1dd55cf..98965fd8e2d 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -1693,7 +1693,7 @@ VacuumUpdateCosts(void) } else { - /* Must be explicit VACUUM or ANALYZE */ + /* Must be explicit VACUUM or ANALYZE or parallel autovacuum worker */ vacuum_cost_delay = VacuumCostDelay; vacuum_cost_limit = VacuumCostLimit; } diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index ec5d70aacdc..09696a8eafe 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -411,6 +411,8 @@ extern void parallel_vacuum_cleanup_all_indexes(ParallelVacuumState *pvs, int num_index_scans, bool estimated_count, PVWorkersUsage *wusage); +extern bool parallel_vacuum_update_shared_delay_params(void); +extern void parallel_vacuum_propagate_cost_based_params(void); extern void parallel_vacuum_main(dsm_segment *seg, shm_toc *toc); /* in commands/analyze.c */ -- 2.43.0