From 848d628a56d78b38b21b5a83d1f63e03075171af Mon Sep 17 00:00:00 2001
From: Daniil Davidov <d.davydov@postgrespro.ru>
Date: Wed, 4 Mar 2026 02:50:39 +0700
Subject: [PATCH] fixes for 0003

---
 src/backend/commands/vacuum.c         |  10 +-
 src/backend/commands/vacuumparallel.c | 132 ++++++++++++--------------
 src/tools/pgindent/typedefs.list      |   1 -
 3 files changed, 67 insertions(+), 76 deletions(-)

diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index e94e35481a2..5fba48d0536 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -2440,10 +2440,8 @@ vacuum_delay_point(bool is_analyze)
 	if (IsParallelWorker())
 	{
 		/*
-		 * Possibly update cost-based delay parameters.
-		 *
-		 * Do it before checking VacuumCostActive, because its value might be
-		 * changed after calling this function.
+		 * Update cost-based vacuum delay parameters for a parallel autovacuum
+		 * worker if any changes are detected.
 		 */
 		parallel_vacuum_update_shared_delay_params();
 	}
@@ -2464,8 +2462,8 @@ vacuum_delay_point(bool is_analyze)
 		VacuumUpdateCosts();
 
 		/*
-		 * If we are parallel autovacuum leader and some of cost-based
-		 * parameters had changed, let other parallel workers know.
+		 * Propagate cost-based vacuum delay parameters to shared memory if
+		 * any of them have changed during the config reload.
 		 */
 		parallel_vacuum_propagate_shared_delay_params();
 	}
diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c
index 80b57bf9da3..13304c40b59 100644
--- a/src/backend/commands/vacuumparallel.c
+++ b/src/backend/commands/vacuumparallel.c
@@ -18,6 +18,13 @@
  * the parallel context is re-initialized so that the same DSM can be used for
  * multiple passes of index bulk-deletion and index cleanup.
  *
+ * For parallel autovacuum, we need to propagate cost-based vacuum delay
+ * parameters from the leader to its workers, as the leader's parameters can
+ * change even while processing a table (e.g., due to a config reload).
+ * The PVSharedCostParams struct manages these parameters using a
+ * generation counter. Each parallel worker polls this shared state and
+ * refreshes its local delay parameters whenever a change is detected.
+ *
  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
@@ -54,26 +61,6 @@
 #define PARALLEL_VACUUM_KEY_WAL_USAGE		4
 #define PARALLEL_VACUUM_KEY_INDEX_STATS		5
 
-/*
- * Helper for the PVSharedCostParams structure (see below), to avoid
- * repetition.
- */
-typedef struct VacuumCostParams
-{
-	double		cost_delay;
-	int			cost_limit;
-	int			cost_page_dirty;
-	int			cost_page_hit;
-	int			cost_page_miss;
-} VacuumCostParams;
-
-#define	FillVacCostParams(cost_params) \
-	(cost_params)->cost_delay = vacuum_cost_delay; \
-	(cost_params)->cost_limit = vacuum_cost_limit; \
-	(cost_params)->cost_page_dirty = VacuumCostPageDirty; \
-	(cost_params)->cost_page_hit = VacuumCostPageHit; \
-	(cost_params)->cost_page_miss = VacuumCostPageMiss
-
 /*
  * Struct for cost-based vacuum delay related parameters to share among an
  * autovacuum worker and its parallel vacuum workers.
@@ -81,23 +68,22 @@ typedef struct VacuumCostParams
 typedef struct PVSharedCostParams
 {
 	/*
-	 * Each time leader worker updates its parameters, it must increase
-	 * generation. Every parallel worker keeps the generation
-	 * (shared_params_local_generation) at which it had last time received
-	 * parameters from the leader.
-	 *
-	 * It is enough for worker to compare it's local_generation with the field
-	 * below to determine whether it needs to receive new parameters' values.
+	 * The generation counter is incremented by the leader process each time
+	 * it updates the shared cost-based vacuum delay parameters. Paralell
+	 * vacuum workers compares it with their local generation,
+	 * shared_params_generation_local, to detect whether they need to refresh
+	 * their local parameters.
 	 */
 	pg_atomic_uint32 generation;
 
 	slock_t		mutex;			/* protects all fields below */
 
-	/*
-	 * Copies of the corresponding cost-based vacuum delay parameters from
-	 * autovacuum leader process.
-	 */
-	VacuumCostParams params_data;
+	/* Parameters to share with parallel workers */
+	double		cost_delay;
+	int			cost_limit;
+	int			cost_page_dirty;
+	int			cost_page_hit;
+	int			cost_page_miss;
 } PVSharedCostParams;
 
 /*
@@ -285,7 +271,7 @@ struct ParallelVacuumState
 
 static PVSharedCostParams *pv_shared_cost_params = NULL;
 
-/* See comments for the PVSharedCostParams structure for the explanation. */
+/* See comments in the PVSharedCostParams for the details */
 static uint32 shared_params_generation_local = 0;
 
 static int	parallel_vacuum_compute_workers(Relation *indrels, int nindexes, int nrequested,
@@ -299,6 +285,7 @@ static void parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation
 static bool parallel_vacuum_index_is_parallel_safe(Relation indrel, int num_index_scans,
 												   bool vacuum);
 static void parallel_vacuum_error_callback(void *arg);
+static inline void parallel_vacuum_set_cost_parameters(PVSharedCostParams *params);
 
 /*
  * Try to enter parallel mode and create a parallel context.  Then initialize
@@ -461,9 +448,13 @@ parallel_vacuum_init(Relation rel, Relation *indrels, int nindexes,
 
 	shared->is_autovacuum = AmAutoVacuumWorkerProcess();
 
+	/*
+	 * Initialize shared cost-based vacuum delay parameters if it's for
+	 * autovacuum.
+	 */
 	if (shared->is_autovacuum)
 	{
-		FillVacCostParams(&shared->cost_params.params_data);
+		parallel_vacuum_set_cost_parameters(&shared->cost_params);
 		pg_atomic_init_u32(&shared->cost_params.generation, 0);
 		SpinLockInit(&shared->cost_params.mutex);
 
@@ -615,10 +606,21 @@ parallel_vacuum_cleanup_all_indexes(ParallelVacuumState *pvs, long num_table_tup
 }
 
 /*
- * If we are parallel *autovacuum* worker, check whether related to cost-based
- * vacuum delay parameters had changed in the leader worker. If so,
- * corresponding parameters will be updated to the values which leader worker
- * is operating on.
+ * Fill in the given structure with cost-based vacuum delay parameter values.
+ */
+static inline void
+parallel_vacuum_set_cost_parameters(PVSharedCostParams *params)
+{
+	params->cost_delay = vacuum_cost_delay;
+	params->cost_limit = vacuum_cost_limit;
+	params->cost_page_dirty = VacuumCostPageDirty;
+	params->cost_page_hit = VacuumCostPageHit;
+	params->cost_page_miss = VacuumCostPageMiss;
+}
+
+/*
+ * Updates the cost-based vacuum delay parameters for parallel autovacuum
+ * workers.
  *
  * For non-autovacuum parallel worker this function will have no effect.
  */
@@ -629,7 +631,7 @@ parallel_vacuum_update_shared_delay_params(void)
 
 	Assert(IsParallelWorker());
 
-	/* Check whether we are running parallel autovacuum */
+	/* Quick return if the wokrer is not running for the autovacuum */
 	if (pv_shared_cost_params == NULL)
 		return;
 
@@ -641,13 +643,11 @@ parallel_vacuum_update_shared_delay_params(void)
 		return;
 
 	SpinLockAcquire(&pv_shared_cost_params->mutex);
-
-	VacuumCostDelay = pv_shared_cost_params->params_data.cost_delay;
-	VacuumCostLimit = pv_shared_cost_params->params_data.cost_limit;
-	VacuumCostPageDirty = pv_shared_cost_params->params_data.cost_page_dirty;
-	VacuumCostPageHit = pv_shared_cost_params->params_data.cost_page_hit;
-	VacuumCostPageMiss = pv_shared_cost_params->params_data.cost_page_miss;
-
+	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->mutex);
 
 	VacuumUpdateCosts();
@@ -656,46 +656,40 @@ parallel_vacuum_update_shared_delay_params(void)
 }
 
 /*
- * Function to be called from parallel autovacuum leader in order to propagate
- * some cost-based vacuum delay parameters to the supportive workers.
+ * Store the cost-based vacuum delay parameters in the shared memory so that
+ * parallel vacuum workers can consume them (see
+ * parallel_vacuum_update_shared_delay_params()).
  */
 void
 parallel_vacuum_propagate_shared_delay_params(void)
 {
-	VacuumCostParams *params_data;
-
 	Assert(AmAutoVacuumWorkerProcess());
 
-	/* Check whether we are running parallel autovacuum */
+	/*
+	 * Quick return if the leader process is not sharing the delay parameters.
+	 */
 	if (pv_shared_cost_params == NULL)
 		return;
 
 	/*
-	 * Only leader worker can modify this shared structure, so we can read it
-	 * without acquiring a lock.
+	 * Check if any delay parameters has changed. We can read them without
+	 * locks as only the leader can modify them.
 	 */
-	params_data = &pv_shared_cost_params->params_data;
-
-	if (vacuum_cost_delay == params_data->cost_delay &&
-		vacuum_cost_limit == params_data->cost_limit &&
-		VacuumCostPageDirty == params_data->cost_page_dirty &&
-		VacuumCostPageHit == params_data->cost_page_hit &&
-		VacuumCostPageMiss == params_data->cost_page_miss)
-	{
-		/*
-		 * We don't need to update shared cost-based vacuum delay params if
-		 * they haven't changed.
-		 */
+	if (vacuum_cost_delay == pv_shared_cost_params->cost_delay &&
+		vacuum_cost_limit == 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)
 		return;
-	}
 
+	/* Update the shared delay parameters */
 	SpinLockAcquire(&pv_shared_cost_params->mutex);
-	FillVacCostParams(&pv_shared_cost_params->params_data);
+	parallel_vacuum_set_cost_parameters(pv_shared_cost_params);
 	SpinLockRelease(&pv_shared_cost_params->mutex);
 
 	/*
-	 * Increase generation of the parameters, i.e. let parallel workers know
-	 * that they should re-read shared cost params.
+	 * Increment the generation of the parameters, i.e. let parallel workers
+	 * know that they should re-read shared cost params.
 	 */
 	pg_atomic_fetch_add_u32(&pv_shared_cost_params->generation, 1);
 }
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index de9f576e0f3..1120646f2c8 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -3250,7 +3250,6 @@ VacAttrStatsP
 VacDeadItemsInfo
 VacErrPhase
 VacOptValue
-VacuumCostParams
 VacuumParams
 VacuumRelation
 VacuumStmt
-- 
2.43.0

