From 98e63807d9dbbf2d6153ce4b8139a49f84339a07 Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Wed, 25 Mar 2026 14:49:12 -0700 Subject: [PATCH v31 2/2] fixup: several changes. - use opt-out style. - adjust default values. - improve comments. - fixes typos etc. --- src/backend/access/common/reloptions.c | 2 +- src/backend/access/heap/vacuumlazy.c | 5 +- src/backend/commands/vacuumparallel.c | 52 +++++++++++++------ src/backend/postmaster/autovacuum.c | 36 +++++++------ src/backend/utils/init/globals.c | 2 +- src/backend/utils/misc/guc.c | 7 +-- src/backend/utils/misc/guc_parameters.dat | 2 +- src/backend/utils/misc/postgresql.conf.sample | 2 +- .../t/001_parallel_autovacuum.pl | 22 ++++---- 9 files changed, 82 insertions(+), 48 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index ce41b015b32..cee705500f8 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -243,7 +243,7 @@ static relopt_int intRelOpts[] = RELOPT_KIND_HEAP, ShareUpdateExclusiveLock }, - 0, -1, 1024 + -1, -1, 1024 }, { { diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index 8c7de657976..9fd4f6febbe 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -864,8 +864,11 @@ heap_vacuum_rel(Relation rel, const VacuumParams params, dead_items_alloc(vacrel, params.nworkers); #ifdef USE_INJECTION_POINTS + /* - * Trigger injection point, if parallel autovacuum is about to be started. + * Used by tests to pause before parallel vacuum is launched, allowing + * test code to modify configuration that the leader then propagates to + * workers. */ if (AmAutoVacuumWorkerProcess() && ParallelVacuumIsActive(vacrel)) INJECTION_POINT("autovacuum-start-parallel-vacuum", NULL); diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c index 62b6f50b538..13544de5b93 100644 --- a/src/backend/commands/vacuumparallel.c +++ b/src/backend/commands/vacuumparallel.c @@ -69,10 +69,12 @@ typedef struct PVSharedCostParams { /* * The generation counter is incremented by the leader process each time - * it updates the shared cost-based vacuum delay parameters. Paralell + * it updates the shared cost-based vacuum delay parameters. Parallel * vacuum workers compares it with their local generation, * shared_params_generation_local, to detect whether they need to refresh - * their local parameters. + * their local parameters. The generation starts from 1 so that a freshly + * started worker (whose local copy is 0) will always load the initial + * parameters on its first check. */ pg_atomic_uint32 generation; @@ -158,13 +160,13 @@ typedef struct PVShared /* * If 'true' then we are running parallel autovacuum. Otherwise, we are - * running parallel maintenence VACUUM. + * running parallel maintenance VACUUM. */ bool is_autovacuum; /* - * Struct for syncing cost-based vacuum delay parameters between - * supportive parallel autovacuum workers with leader worker. + * Cost-based vacuum delay parameters shared between the autovacuum leader + * and its parallel workers. */ PVSharedCostParams cost_params; } PVShared; @@ -271,7 +273,13 @@ struct ParallelVacuumState static PVSharedCostParams *pv_shared_cost_params = NULL; -/* See comments in the PVSharedCostParams for the details */ +/* + * Worker-local copy of the last cost-parameter generation this worker has + * applied. Initialized to 0; since the leader initializes the shared + * generation counter to 1, the first call to + * parallel_vacuum_update_shared_delay_params() will always detect a + * mismatch and read the initial parameters from shared memory. + */ static uint32 shared_params_generation_local = 0; static int parallel_vacuum_compute_workers(Relation *indrels, int nindexes, int nrequested, @@ -455,7 +463,7 @@ parallel_vacuum_init(Relation rel, Relation *indrels, int nindexes, if (shared->is_autovacuum) { parallel_vacuum_set_cost_parameters(&shared->cost_params); - pg_atomic_init_u32(&shared->cost_params.generation, 0); + pg_atomic_init_u32(&shared->cost_params.generation, 1); SpinLockInit(&shared->cost_params.mutex); pv_shared_cost_params = &(shared->cost_params); @@ -623,7 +631,7 @@ parallel_vacuum_set_cost_parameters(PVSharedCostParams *params) * Updates the cost-based vacuum delay parameters for parallel autovacuum * workers. * - * For non-autovacuum parallel worker this function will have no effect. + * For non-autovacuum parallel workers, this function will have no effect. */ void parallel_vacuum_update_shared_delay_params(void) @@ -632,7 +640,7 @@ parallel_vacuum_update_shared_delay_params(void) Assert(IsParallelWorker()); - /* Quick return if the wokrer is not running for the autovacuum */ + /* Quick return if the worker is not running for the autovacuum */ if (pv_shared_cost_params == NULL) return; @@ -681,7 +689,7 @@ parallel_vacuum_propagate_shared_delay_params(void) return; /* - * Check if any delay parameters has changed. We can read them without + * Check if any delay parameters have changed. We can read them without * locks as only the leader can modify them. */ if (vacuum_cost_delay == pv_shared_cost_params->cost_delay && @@ -905,9 +913,10 @@ parallel_vacuum_process_all_indexes(ParallelVacuumState *pvs, int num_index_scan } #ifdef USE_INJECTION_POINTS + /* - * This injection point is used to wait until parallel autovacuum workers - * finishes their part of index processing. + * Used by tests to pause after workers are launched but before index + * vacuuming begins. */ if (nworkers > 0) INJECTION_POINT("autovacuum-leader-before-indexes-processing", NULL); @@ -1247,15 +1256,26 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc) shared->dead_items_handle); /* Set cost-based vacuum delay */ - VacuumUpdateCosts(); + if (shared->is_autovacuum) + { + /* + * Parallel autovacuum workers initialize cost-based delay parameters + * from the leader's shared state rather than GUC defaults, because + * the leader may have applied per-table or autovacuum-specific + * overrides. pv_shared_cost_params must be set before calling + * parallel_vacuum_update_shared_delay_params(). + */ + pv_shared_cost_params = &(shared->cost_params); + parallel_vacuum_update_shared_delay_params(); + } + else + VacuumUpdateCosts(); + VacuumCostBalance = 0; VacuumCostBalanceLocal = 0; VacuumSharedCostBalance = &(shared->cost_balance); VacuumActiveNWorkers = &(shared->active_nworkers); - if (shared->is_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 562514e2ece..ce893db1ab5 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -2797,7 +2797,6 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, int multixact_freeze_table_age; int log_vacuum_min_duration; int log_analyze_min_duration; - int nparallel_workers = -1; /* disabled by default */ /* * Calculate the vacuum cost parameters and the freeze ages. If there @@ -2858,19 +2857,6 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, tab->at_params.index_cleanup = VACOPTVALUE_UNSPECIFIED; tab->at_params.truncate = VACOPTVALUE_UNSPECIFIED; - /* Decide whether we need to process indexes of table in parallel. */ - if (avopts) - { - if (avopts->autovacuum_parallel_workers > 0) - nparallel_workers = avopts->autovacuum_parallel_workers; - else if (avopts->autovacuum_parallel_workers == -1) - { - nparallel_workers = autovacuum_max_parallel_workers > 0 - ? autovacuum_max_parallel_workers - : -1; /* disable parallelism if parameter's value is 0 */ - } - } - tab->at_params.freeze_min_age = freeze_min_age; tab->at_params.freeze_table_age = freeze_table_age; tab->at_params.multixact_freeze_min_age = multixact_freeze_min_age; @@ -2879,7 +2865,27 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, tab->at_params.log_vacuum_min_duration = log_vacuum_min_duration; tab->at_params.log_analyze_min_duration = log_analyze_min_duration; tab->at_params.toast_parent = InvalidOid; - tab->at_params.nworkers = nparallel_workers; + + /* Determine the number of parallel vacuum workers to use */ + tab->at_params.nworkers = 0; + if (avopts) + { + if (avopts->autovacuum_parallel_workers == 0) + { + /* + * Disable parallel vacuum, if the reloption sets the parallel + * degree as zero. + */ + tab->at_params.nworkers = -1; + } + else if (avopts->autovacuum_parallel_workers > 0) + tab->at_params.nworkers = avopts->autovacuum_parallel_workers; + + /* + * autovacuum_parallel_workers == -1 falls through, keep + * nworkers=0 + */ + } /* * Later, in vacuum_rel(), we check reloptions for any diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index 8265a82b639..24ddb276f0c 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -143,7 +143,7 @@ int NBuffers = 16384; int MaxConnections = 100; int max_worker_processes = 8; int max_parallel_workers = 8; -int autovacuum_max_parallel_workers = 2; +int autovacuum_max_parallel_workers = 0; int MaxBackends = 0; /* GUC parameters for vacuum */ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 45b39b7c47f..1ac8e8fc3be 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -3359,9 +3359,10 @@ set_config_with_handle(const char *name, config_handle *handle, * Also allow normal setting if the GUC is marked GUC_ALLOW_IN_PARALLEL. * * Other changes might need to affect other workers, so forbid them. Note, - * that parallel autovacuum leader is an exception, because only - * cost-based delays need to be affected also to parallel autovacuum - * workers, and we will handle it elsewhere if appropriate. + * that parallel autovacuum leader is an exception because only cost-based + * delays need to be affected also to parallel autovacuum workers. These + * parameters are propagated to its workers during parallel vacuum (see + * vacuumparallel.c for details). */ if (IsInParallelMode() && !AmAutoVacuumWorkerProcess() && changeVal && action != GUC_ACTION_SAVE && diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat index 3d2fd35a004..275198f2023 100644 --- a/src/backend/utils/misc/guc_parameters.dat +++ b/src/backend/utils/misc/guc_parameters.dat @@ -157,7 +157,7 @@ { name => 'autovacuum_max_parallel_workers', type => 'int', context => 'PGC_SIGHUP', group => 'VACUUM_AUTOVACUUM', short_desc => 'Maximum number of parallel workers that can be used by a single autovacuum worker.', variable => 'autovacuum_max_parallel_workers', - boot_val => '2', + boot_val => '0', min => '0', max => 'MAX_PARALLEL_WORKER_LIMIT', }, diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 11d96f4dd4f..9853df0bdf7 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -713,7 +713,7 @@ #autovacuum_worker_slots = 16 # autovacuum worker slots to allocate # (change requires restart) #autovacuum_max_workers = 3 # max number of autovacuum subprocesses -#autovacuum_max_parallel_workers = 2 # limited by max_parallel_workers +#autovacuum_max_parallel_workers = 0 # limited by max_parallel_workers #autovacuum_naptime = 1min # time between autovacuum runs #autovacuum_vacuum_threshold = 50 # min number of row updates before # vacuum diff --git a/src/test/modules/test_autovacuum/t/001_parallel_autovacuum.pl b/src/test/modules/test_autovacuum/t/001_parallel_autovacuum.pl index 0364019d5f0..2aca32374a2 100644 --- a/src/test/modules/test_autovacuum/t/001_parallel_autovacuum.pl +++ b/src/test/modules/test_autovacuum/t/001_parallel_autovacuum.pl @@ -12,7 +12,7 @@ if ($ENV{enable_injection_points} ne 'yes') # Before each test we should disable autovacuum for 'test_autovac' table and # generate some dead tuples in it. Returns the current autovacuum_count of -# the table tset_autovac. +# the table test_autovac. sub prepare_for_next_test { my ($node, $test_number) = @_; @@ -47,16 +47,20 @@ my $psql_out; my $node = PostgreSQL::Test::Cluster->new('main'); $node->init; -# Configure postgres, so it can launch parallel autovacuum workers, log all -# information we are interested in and autovacuum works frequently +# Limit to one autovacuum worker and disable autovacuum logging globally +# (enabled only on the test table) so that log checks below match only +# activity on the expected table. $node->append_conf( 'postgresql.conf', qq{ - max_worker_processes = 20 - max_parallel_workers = 20 - autovacuum_max_parallel_workers = 4 - log_min_messages = debug2 - autovacuum_naptime = '1s' - min_parallel_index_scan_size = 0 +autovacuum_max_workers = 1 +autovacuum_worker_slots = 1 +autovacuum_max_parallel_workers = 2 +max_worker_processes = 10 +max_parallel_workers = 10 +log_min_messages = debug2 +autovacuum_naptime = '1s' +min_parallel_index_scan_size = 0 +log_autovacuum_min_duration = -1 }); $node->start; -- 2.53.0