From 4e6fefb064323566826dcb483b38357607d0972a Mon Sep 17 00:00:00 2001 From: Bharath Rupireddy Date: Fri, 25 Sep 2026 18:52:57 +0000 Subject: [PATCH v4 1/2] Refresh autovacuum costs while waiting for parallel workers. Previously, an autovacuum worker running a parallel vacuum (leader) propagated changes to the cost-based delay parameters to its parallel workers only from vacuum_delay_point(). Once the leader had finished its own share of the indexes and was waiting for the parallel workers in WaitForParallelWorkersToFinish(), it no longer reached vacuum_delay_point(), so the parallel workers did not receive any changes until the wait ended, which could take as long as the largest index. As a result, a configuration reload during the wait stayed pending, since SIGHUP woke up the leader but the wait loop only called CHECK_FOR_INTERRUPTS(), which does not process ConfigReloadPending. Likewise, a change in the number of autovacuum workers sharing the cost limit did not reach the leader, since nothing signaled it, and its parallel workers kept running at the old share of the limit. This commit fixes the issue in two parts. First, the wait loop in WaitForParallelWorkersToFinish() now refreshes the cost-based delay parameters and propagates them to the parallel workers on every wakeup, when the process is an autovacuum worker. Second, autovac_recalculate_workers_for_balance() now sets the latch of the autovacuum workers sharing the cost limit when the count changes, so that a leader waiting for its parallel workers wakes up and picks up the new count. A worker that is not waiting on its latch is not signaled and picks up the new count on its next nap as before. Backpatch to 19, where parallel autovacuum was introduced. Reported-by: Nikolay Samokhvalov Author: Bharath Rupireddy Reviewed-by: Manu Reviewed-by: Zsolt Parragi Reviewed-by: Daniel Gustafsson Reviewed-by: Masahiko Sawada Discussion: https://postgr.es/m/CAM527d-GL%3DJp2EJXBSnVBGPK-4XEZwWof5Cv8P0hghS_og6oAg%40mail.gmail.com Backpatch-through: 19 --- src/backend/access/transam/parallel.c | 11 +++++++++ src/backend/commands/vacuumparallel.c | 35 +++++++++++++++++++++++++++ src/backend/postmaster/autovacuum.c | 27 +++++++++++++++++++++ src/include/commands/vacuum.h | 1 + 4 files changed, 74 insertions(+) diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c index e1806a9a28a..b51df2a4606 100644 --- a/src/backend/access/transam/parallel.c +++ b/src/backend/access/transam/parallel.c @@ -812,6 +812,17 @@ WaitForParallelWorkersToFinish(ParallelContext *pcxt) */ CHECK_FOR_INTERRUPTS(); + /* + * An autovacuum worker running a parallel vacuum (leader) propagates + * changes to the cost-based delay parameters to its parallel workers + * at its own cost delay points, which it no longer reaches while + * waiting here. Do it here instead, on every wakeup, so that a config + * reload or a change in the number of autovacuum workers sharing the + * cost limit reaches the parallel workers before they finish. + */ + if (AmAutoVacuumWorkerProcess()) + parallel_vacuum_refresh_cost_params(); + for (i = 0; i < pcxt->nworkers_launched; ++i) { /* diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c index 4532da60c84..2dd127e9118 100644 --- a/src/backend/commands/vacuumparallel.c +++ b/src/backend/commands/vacuumparallel.c @@ -43,6 +43,7 @@ #include "executor/instrument.h" #include "optimizer/paths.h" #include "pgstat.h" +#include "postmaster/interrupt.h" #include "storage/bufmgr.h" #include "storage/proc.h" #include "tcop/tcopprot.h" @@ -725,6 +726,40 @@ parallel_vacuum_propagate_shared_delay_params(void) pg_atomic_fetch_add_u32(&pv_shared_cost_params->generation, 1); } +/* + * Reload the configuration file if requested, and refresh the cost-based + * delay parameters of an autovacuum worker running a parallel vacuum + * (leader), propagating any change to its parallel workers. + */ +void +parallel_vacuum_refresh_cost_params(void) +{ + Assert(AmAutoVacuumWorkerProcess()); + + /* + * Quick return if the leader is not sharing the delay parameters with + * parallel workers. + */ + if (pv_shared_cost_params == NULL) + return; + + if (ConfigReloadPending) + { + ConfigReloadPending = false; + ProcessConfigFile(PGC_SIGHUP); + + /* This re-divides the cost limit too */ + VacuumUpdateCosts(); + } + else + { + /* The number of workers sharing the cost limit may have changed */ + AutoVacuumUpdateCostLimit(); + } + + parallel_vacuum_propagate_shared_delay_params(); +} + /* * Compute the number of parallel worker processes to request. Both index * vacuum and index cleanup can be executed with parallel workers. diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 60ebe828900..11da648e4a2 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -1814,8 +1814,35 @@ autovac_recalculate_workers_for_balance(void) } if (nworkers_for_balance != orig_nworkers_for_balance) + { pg_atomic_write_u32(&AutoVacuumShmem->av_nworkersForBalance, nworkers_for_balance); + + /* + * Wake up the autovacuum workers sharing the cost limit so that they + * pick up the new count. An autovacuum worker that is vacuuming does + * that on its next nap anyway, but one running a parallel vacuum + * (leader) that is only waiting for its parallel workers to finish + * never naps, and nothing else would tell it. The count is written + * above, before the latches are set, so a woken leader always reads + * the new value. + * + * Only the waiting leaders need this, but knowing which ones are + * waiting would need more state. For an autovacuum worker that is not + * in a latch wait, SetLatch() sends no signal and only marks the + * latch set, which costs one early return from its next latch wait. + */ + dlist_foreach(iter, &AutoVacuumShmem->av_runningWorkers) + { + WorkerInfo worker = dlist_container(WorkerInfoData, wi_links, iter.cur); + + if (worker->wi_proc == NULL || + pg_atomic_unlocked_test_flag(&worker->wi_dobalance)) + continue; + + SetLatch(&worker->wi_proc->procLatch); + } + } } /* diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 6e3c912bf5c..89fa1fcd261 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -432,6 +432,7 @@ extern void parallel_vacuum_cleanup_all_indexes(ParallelVacuumState *pvs, PVWorkerStats *wstats); extern void parallel_vacuum_update_shared_delay_params(void); extern void parallel_vacuum_propagate_shared_delay_params(void); +extern void parallel_vacuum_refresh_cost_params(void); extern void parallel_vacuum_main(dsm_segment *seg, shm_toc *toc); /* in commands/analyze.c */ -- 2.47.3