From a7b21c3cd9ba898c7da72ece98cbc3ddfffc46c2 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Fri, 25 Sep 2026 18:52:57 +0000
Subject: [PATCH v6] Refresh autovacuum costs while waiting for parallel
 workers.

Commit 1ff3180ca01 made a parallel autovacuum leader propagate changes
to the cost-based delay parameters to its workers only from
vacuum_delay_point(), which it no longer reaches once it is waiting in
WaitForParallelWorkersToFinish(). While waiting, the leader neither
processed a config reload nor noticed a change in the number of
autovacuum workers sharing the cost limit, so its workers kept running
with stale parameters until they finished.

Fix by refreshing and propagating the parameters on every wakeup of
that wait loop, and by setting the latches of the balanced autovacuum
workers when their count changes so that a waiting leader wakes up.

A regression test will be added in a separate commit.

Backpatch to v19, where parallel autovacuum was introduced.

Reported-by: Nikolay Samokhvalov <nik@postgres.ai>
Author: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Reviewed-by: Manu <manuelreyesbravo@gmail.com>
Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Discussion: https://postgr.es/m/CAM527d-GL=Jp2EJXBSnVBGPK-4XEZwWof5Cv8P0hghS_og6oAg@mail.gmail.com
Backpatch-through: 19
---
 src/backend/access/transam/parallel.c | 11 +++++++++
 src/backend/commands/vacuumparallel.c | 35 +++++++++++++++++++++++++++
 src/backend/postmaster/autovacuum.c   | 25 +++++++++++++++++++
 src/include/commands/vacuum.h         |  1 +
 4 files changed, 72 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 b8ceb5a7d29..b07124d1467 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"
@@ -734,6 +735,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..0ec01c5da6f 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -1814,8 +1814,33 @@ 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.
+		 *
+		 * 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.55.0

