Separate vacuum cost variables from GUCs
authorDaniel Gustafsson <[email protected]>
Thu, 6 Apr 2023 22:54:53 +0000 (00:54 +0200)
committerDaniel Gustafsson <[email protected]>
Thu, 6 Apr 2023 22:54:53 +0000 (00:54 +0200)
Vacuum code run both by autovacuum workers and a backend doing
VACUUM/ANALYZE previously inspected VacuumCostLimit and VacuumCostDelay,
which are the global variables backing the GUCs vacuum_cost_limit and
vacuum_cost_delay.

Autovacuum workers needed to override these variables with their
own values, derived from autovacuum_vacuum_cost_limit and
autovacuum_vacuum_cost_delay and worker cost limit balancing logic.
This led to confusing code which, in some cases, both derived and
set a new value of VacuumCostLimit from VacuumCostLimit.

In preparation for refreshing these GUC values more often, introduce
new, independent global variables and add a function to update them
using the GUCs and existing logic.

Per suggestion by Kyotaro Horiguchi

Author: Melanie Plageman <[email protected]>
Reviewed-by: Masahiko Sawada <[email protected]>
Reviewed-by: Daniel Gustafsson <[email protected]>
Reviewed-by: Kyotaro Horiguchi <[email protected]>
Reviewed-by: Robert Haas <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/CAAKRu_ZngzqnEODc7LmS1NH04Kt6Y9huSjz5pp7%2BDXhrjDA0gw%40mail.gmail.com

src/backend/commands/vacuum.c
src/backend/commands/vacuumparallel.c
src/backend/postmaster/autovacuum.c
src/include/commands/vacuum.h
src/include/postmaster/autovacuum.h

index 7fc5c19e3797b94ab204926a7eb4d0b0364a167b..f2be74cdb5f64541286decb39d1cdf274e6fad26 100644 (file)
@@ -72,6 +72,15 @@ int                  vacuum_multixact_freeze_table_age;
 int                    vacuum_failsafe_age;
 int                    vacuum_multixact_failsafe_age;
 
+/*
+ * Variables for cost-based vacuum delay. The defaults differ between
+ * autovacuum and vacuum. They should be set with the appropriate GUC value in
+ * vacuum code. They are initialized here to the defaults for client backends
+ * executing VACUUM or ANALYZE.
+ */
+double         vacuum_cost_delay = 0;
+int                    vacuum_cost_limit = 200;
+
 /*
  * VacuumFailsafeActive is a defined as a global so that we can determine
  * whether or not to re-enable cost-based vacuum delay when vacuuming a table.
@@ -514,8 +523,9 @@ vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy,
        {
                ListCell   *cur;
 
+               VacuumUpdateCosts();
                in_vacuum = true;
-               VacuumCostActive = (VacuumCostDelay > 0);
+               VacuumCostActive = (vacuum_cost_delay > 0);
                VacuumCostBalance = 0;
                VacuumPageHit = 0;
                VacuumPageMiss = 0;
@@ -2244,14 +2254,14 @@ vacuum_delay_point(void)
         */
        if (VacuumSharedCostBalance != NULL)
                msec = compute_parallel_delay();
-       else if (VacuumCostBalance >= VacuumCostLimit)
-               msec = VacuumCostDelay * VacuumCostBalance / VacuumCostLimit;
+       else if (VacuumCostBalance >= vacuum_cost_limit)
+               msec = vacuum_cost_delay * VacuumCostBalance / vacuum_cost_limit;
 
        /* Nap if appropriate */
        if (msec > 0)
        {
-               if (msec > VacuumCostDelay * 4)
-                       msec = VacuumCostDelay * 4;
+               if (msec > vacuum_cost_delay * 4)
+                       msec = vacuum_cost_delay * 4;
 
                pgstat_report_wait_start(WAIT_EVENT_VACUUM_DELAY);
                pg_usleep(msec * 1000);
@@ -2268,8 +2278,7 @@ vacuum_delay_point(void)
 
                VacuumCostBalance = 0;
 
-               /* update balance values for workers */
-               AutoVacuumUpdateDelay();
+               VacuumUpdateCosts();
 
                /* Might have gotten an interrupt while sleeping */
                CHECK_FOR_INTERRUPTS();
@@ -2319,11 +2328,11 @@ compute_parallel_delay(void)
        /* Compute the total local balance for the current worker */
        VacuumCostBalanceLocal += VacuumCostBalance;
 
-       if ((shared_balance >= VacuumCostLimit) &&
-               (VacuumCostBalanceLocal > 0.5 * ((double) VacuumCostLimit / nworkers)))
+       if ((shared_balance >= vacuum_cost_limit) &&
+               (VacuumCostBalanceLocal > 0.5 * ((double) vacuum_cost_limit / nworkers)))
        {
                /* Compute sleep time based on the local cost balance */
-               msec = VacuumCostDelay * VacuumCostBalanceLocal / VacuumCostLimit;
+               msec = vacuum_cost_delay * VacuumCostBalanceLocal / vacuum_cost_limit;
                pg_atomic_sub_fetch_u32(VacuumSharedCostBalance, VacuumCostBalanceLocal);
                VacuumCostBalanceLocal = 0;
        }
index 563117a8f6eaf41127ae7e65bb6cb91fd50ef90b..cc0aff7904484eb47685a3fd9f40162ab30eed98 100644 (file)
@@ -995,7 +995,8 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
                                                                                                 false);
 
        /* Set cost-based vacuum delay */
-       VacuumCostActive = (VacuumCostDelay > 0);
+       VacuumCostActive = (vacuum_cost_delay > 0);
+       VacuumUpdateCosts();
        VacuumCostBalance = 0;
        VacuumPageHit = 0;
        VacuumPageMiss = 0;
index c1e911b1b3804e801ec2da958fd81096849d767a..0e7933c34d9550e9c267dc48c6930aa00aa9b8e0 100644 (file)
@@ -1773,16 +1773,24 @@ FreeWorkerInfo(int code, Datum arg)
 }
 
 /*
- * Update the cost-based delay parameters, so that multiple workers consume
- * each a fraction of the total available I/O.
+ * Update vacuum cost-based delay-related parameters for autovacuum workers and
+ * backends executing VACUUM or ANALYZE using the value of relevant GUCs and
+ * global state. This must be called during setup for vacuum and after every
+ * config reload to ensure up-to-date values.
  */
 void
-AutoVacuumUpdateDelay(void)
+VacuumUpdateCosts(void)
 {
        if (MyWorkerInfo)
        {
-               VacuumCostDelay = MyWorkerInfo->wi_cost_delay;
-               VacuumCostLimit = MyWorkerInfo->wi_cost_limit;
+               vacuum_cost_delay = MyWorkerInfo->wi_cost_delay;
+               vacuum_cost_limit = MyWorkerInfo->wi_cost_limit;
+       }
+       else
+       {
+               /* Must be explicit VACUUM or ANALYZE */
+               vacuum_cost_delay = VacuumCostDelay;
+               vacuum_cost_limit = VacuumCostLimit;
        }
 }
 
@@ -2311,8 +2319,6 @@ do_autovacuum(void)
                autovac_table *tab;
                bool            isshared;
                bool            skipit;
-               double          stdVacuumCostDelay;
-               int                     stdVacuumCostLimit;
                dlist_iter      iter;
 
                CHECK_FOR_INTERRUPTS();
@@ -2415,14 +2421,6 @@ do_autovacuum(void)
                        continue;
                }
 
-               /*
-                * Remember the prevailing values of the vacuum cost GUCs.  We have to
-                * restore these at the bottom of the loop, else we'll compute wrong
-                * values in the next iteration of autovac_balance_cost().
-                */
-               stdVacuumCostDelay = VacuumCostDelay;
-               stdVacuumCostLimit = VacuumCostLimit;
-
                /* Must hold AutovacuumLock while mucking with cost balance info */
                LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
 
@@ -2436,7 +2434,7 @@ do_autovacuum(void)
                autovac_balance_cost();
 
                /* set the active cost parameters from the result of that */
-               AutoVacuumUpdateDelay();
+               VacuumUpdateCosts();
 
                /* done */
                LWLockRelease(AutovacuumLock);
@@ -2533,10 +2531,6 @@ deleted:
                MyWorkerInfo->wi_tableoid = InvalidOid;
                MyWorkerInfo->wi_sharedrel = false;
                LWLockRelease(AutovacuumScheduleLock);
-
-               /* restore vacuum cost GUCs for the next iteration */
-               VacuumCostDelay = stdVacuumCostDelay;
-               VacuumCostLimit = stdVacuumCostLimit;
        }
 
        /*
index 1223d15e0db86a5b84319ddead7bf5b922f3658d..50caf1315dd7c5f45fa8e6c071502e06640804ef 100644 (file)
@@ -307,6 +307,8 @@ extern PGDLLIMPORT pg_atomic_uint32 *VacuumActiveNWorkers;
 extern PGDLLIMPORT int VacuumCostBalanceLocal;
 
 extern PGDLLIMPORT bool VacuumFailsafeActive;
+extern PGDLLIMPORT double vacuum_cost_delay;
+extern PGDLLIMPORT int vacuum_cost_limit;
 
 /* in commands/vacuum.c */
 extern void ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel);
@@ -347,6 +349,9 @@ extern IndexBulkDeleteResult *vac_cleanup_one_index(IndexVacuumInfo *ivinfo,
                                                                                                        IndexBulkDeleteResult *istat);
 extern Size vac_max_items_to_alloc_size(int max_items);
 
+/* In postmaster/autovacuum.c */
+extern void VacuumUpdateCosts(void);
+
 /* in commands/vacuumparallel.c */
 extern ParallelVacuumState *parallel_vacuum_init(Relation rel, Relation *indrels,
                                                                                                 int nindexes, int nrequested_workers,
index c140371b51879824103278f556695787484182ca..65afd1ea1e8f4232ad80f5ba6b7684e7f4faab02 100644 (file)
@@ -63,9 +63,6 @@ extern int    StartAutoVacWorker(void);
 /* called from postmaster when a worker could not be forked */
 extern void AutoVacWorkerFailed(void);
 
-/* autovacuum cost-delay balancer */
-extern void AutoVacuumUpdateDelay(void);
-
 #ifdef EXEC_BACKEND
 extern void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn();
 extern void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn();