From 8b9fcf7c10353dcacb4ac16515aad0ce34565566 Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Fri, 24 Mar 2023 13:38:20 -0400 Subject: [PATCH v8 3/4] [auto]vacuum reloads config file more often Previously, VACUUM and autovacuum workers would reload the configuration file only between vacuuming tables. This precluded user updates to cost-based delay parameters from taking effect while vacuuming a table. Check if a reload is pending roughly once per block now, when checking if we need to delay. Reviewed-by: Masahiko Sawada Reviewed-by: Daniel Gustafsson Discussion: https://www.postgresql.org/message-id/flat/CAAKRu_buP5wzsho3qNw5o9_R0pF69FRM5hgCmr-mvXmGXwdA7A%40mail.gmail.com#5e6771d4cdca4db6efc2acec2dce0bc7 --- src/backend/commands/vacuum.c | 72 +++++++++++++++++++++++++---- src/backend/postmaster/autovacuum.c | 30 +++++++++++- src/include/postmaster/autovacuum.h | 3 +- 3 files changed, 92 insertions(+), 13 deletions(-) diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index eb126f2247..cb32078c19 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -48,6 +48,7 @@ #include "pgstat.h" #include "postmaster/autovacuum.h" #include "postmaster/bgworker_internals.h" +#include "postmaster/interrupt.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" #include "storage/pmsignal.h" @@ -76,6 +77,7 @@ int vacuum_multixact_failsafe_age; /* A few variables that don't seem worth passing around as parameters */ static MemoryContext vac_context = NULL; static BufferAccessStrategy vac_strategy; +static bool analyze_in_outer_xact = false; /* @@ -314,8 +316,7 @@ vacuum(List *relations, VacuumParams *params, static bool in_vacuum = false; const char *stmttype; - volatile bool in_outer_xact, - use_own_xacts; + volatile bool use_own_xacts; Assert(params != NULL); @@ -332,10 +333,10 @@ vacuum(List *relations, VacuumParams *params, if (params->options & VACOPT_VACUUM) { PreventInTransactionBlock(isTopLevel, stmttype); - in_outer_xact = false; + analyze_in_outer_xact = false; } else - in_outer_xact = IsInTransactionBlock(isTopLevel); + analyze_in_outer_xact = IsInTransactionBlock(isTopLevel); /* * Due to static variables vac_context, anl_context and vac_strategy, @@ -457,7 +458,7 @@ vacuum(List *relations, VacuumParams *params, Assert(params->options & VACOPT_ANALYZE); if (IsAutoVacuumWorkerProcess()) use_own_xacts = true; - else if (in_outer_xact) + else if (analyze_in_outer_xact) use_own_xacts = false; else if (list_length(relations) > 1) use_own_xacts = true; @@ -475,7 +476,7 @@ vacuum(List *relations, VacuumParams *params, */ if (use_own_xacts) { - Assert(!in_outer_xact); + Assert(!analyze_in_outer_xact); /* ActiveSnapshot is not set by autovacuum */ if (ActiveSnapshotSet()) @@ -544,7 +545,7 @@ vacuum(List *relations, VacuumParams *params, } analyze_rel(vrel->oid, vrel->relation, params, - vrel->va_cols, in_outer_xact, vac_strategy); + vrel->va_cols, analyze_in_outer_xact, vac_strategy); if (use_own_xacts) { @@ -568,6 +569,7 @@ vacuum(List *relations, VacuumParams *params, in_vacuum = false; VacuumCostInactive = VACUUM_COST_INACTIVE_AND_UNLOCKED; VacuumCostBalance = 0; + analyze_in_outer_xact = false; } PG_END_TRY(); @@ -2233,7 +2235,52 @@ vacuum_delay_point(void) /* Always check for interrupts */ CHECK_FOR_INTERRUPTS(); - if (VacuumCostInactive || InterruptPending) + if (InterruptPending || + (VacuumCostInactive && !ConfigReloadPending)) + return; + + /* + * Reload the configuration file if requested. This allows changes to + * [autovacuum_]vacuum_cost_limit and [autovacuum_]vacuum_cost_delay to + * take effect while a table is being vacuumed or analyzed. Analyze should + * not reload configuration file if it is in an outer transaction, as GUC + * values shouldn't be allowed to refer to some uncommitted state (e.g. + * database objects created in this transaction). + */ + if (ConfigReloadPending && !analyze_in_outer_xact) + { + ConfigReloadPending = false; + ProcessConfigFile(PGC_SIGHUP); + + /* + * Autovacuum workers must restore the correct values of + * VacuumCostLimit and VacuumCostDelay in case they were overwritten + * by reload. + */ + AutoVacuumUpdateCosts(); + AutoVacuumOverrideCosts(); + + /* + * If configuration changes are allowed to impact VacuumCostInactive, + * make sure it is updated. + */ + if (VacuumCostInactive == VACUUM_COST_INACTIVE_AND_LOCKED) + return; + + if (VacuumCostDelay > 0) + VacuumCostInactive = VACUUM_COST_ACTIVE; + else + { + VacuumCostInactive = VACUUM_COST_INACTIVE_AND_UNLOCKED; + VacuumCostBalance = 0; + } + } + + /* + * If we disabled cost-based delays after reloading the config file, + * return. + */ + if (VacuumCostInactive) return; /* @@ -2266,8 +2313,13 @@ vacuum_delay_point(void) VacuumCostBalance = 0; - /* update balance values for workers */ - AutoVacuumUpdateDelay(); + /* + * For autovacuum workers, someone may have called + * autovac_balance_cost() since they last updated their + * VacuumCostLimit above. Do so again now to ensure they have a + * current value. + */ + AutoVacuumOverrideCosts(); /* Might have gotten an interrupt while sleeping */ CHECK_FOR_INTERRUPTS(); diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index c0e2e00a7e..8ac14a44c8 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -1778,7 +1778,7 @@ FreeWorkerInfo(int code, Datum arg) * each a fraction of the total available I/O. */ void -AutoVacuumUpdateDelay(void) +AutoVacuumOverrideCosts(void) { if (MyWorkerInfo) { @@ -1787,6 +1787,29 @@ AutoVacuumUpdateDelay(void) } } +/* + * Caller must not already hold the AutovacuumLock + */ +void +AutoVacuumUpdateCosts(void) +{ + /* + * Even though this autovacuum worker may be vacuuming a table with a cost + * limit table option and not a cost delay table option, we still don't + * refresh the cost delay value. + */ + if (!MyWorkerInfo || !MyWorkerInfo->wi_dobalance) + return; + + LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE); + MyWorkerInfo->wi_cost_delay = autovacuum_vac_cost_delay >= 0 ? + autovacuum_vac_cost_delay : VacuumCostDelay; + MyWorkerInfo->wi_cost_limit_base = autovacuum_vac_cost_limit > 0 ? + autovacuum_vac_cost_limit : VacuumCostLimit; + autovac_balance_cost(); + LWLockRelease(AutovacuumLock); +} + /* * autovac_balance_cost * Recalculate the cost limit setting for each active worker. @@ -2320,6 +2343,9 @@ do_autovacuum(void) /* * Check for config changes before processing each collected table. + * Autovacuum workers must update VacuumCostDelay and VacuumCostLimit + * in case they were overridden by the reload. However, we will do + * this as soon as we check table options a bit later. */ if (ConfigReloadPending) { @@ -2437,7 +2463,7 @@ do_autovacuum(void) autovac_balance_cost(); /* set the active cost parameters from the result of that */ - AutoVacuumUpdateDelay(); + AutoVacuumOverrideCosts(); /* done */ LWLockRelease(AutovacuumLock); diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h index c140371b51..ee48e7123d 100644 --- a/src/include/postmaster/autovacuum.h +++ b/src/include/postmaster/autovacuum.h @@ -64,7 +64,8 @@ extern int StartAutoVacWorker(void); extern void AutoVacWorkerFailed(void); /* autovacuum cost-delay balancer */ -extern void AutoVacuumUpdateDelay(void); +extern void AutoVacuumOverrideCosts(void); +extern void AutoVacuumUpdateCosts(void); #ifdef EXEC_BACKEND extern void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn(); -- 2.37.2