From 54823d82fcbb2c8bf3eb2a122c461b41b66eb5b6 Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Wed, 26 May 2021 17:17:05 -0700 Subject: [PATCH] Generalize VACUUM's INDEX_CLEANUP option. Generalize the reloption INDEX_CLEANUP to enable users to disable the index vacuum bypassing optimization added by commit 5100010e, as well as any similar optimizations that may be added in the future. The reloption is now a trinary boolean style enum whose default is 'auto', which preserves the current VACUUM behavior. Explicitly setting INDEX_CLEANUP to 'on' now avoids any optimizations that skip index vacuuming, though it doesn't have any effect on the failsafe mechanism. The INDEX_CLEANUP reloption was originally added by commit a96c41fe as an emergency option to allow DBAs to opt out of index vacuuming in extreme cases -- cases where the likely alternative is an anti-wraparoud failure. The reloption can still be used for that, but it seems like a much less useful option now that VACUUM has the failsafe mechanism added by commit 1e55e7d1. --- src/include/commands/vacuum.h | 14 +---------- src/include/utils/rel.h | 15 +++++++++++- src/backend/access/common/reloptions.c | 33 +++++++++++++++++++------- src/backend/access/heap/vacuumlazy.c | 33 ++++++++++++++------------ src/backend/commands/vacuum.c | 11 +++------ 5 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index cb27257bb6..d45891ca31 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -21,6 +21,7 @@ #include "parser/parse_node.h" #include "storage/buf.h" #include "storage/lock.h" +#include "utils/rel.h" #include "utils/relcache.h" /* @@ -184,19 +185,6 @@ typedef struct VacAttrStats #define VACOPT_PROCESS_TOAST 0x40 /* process the TOAST table, if any */ #define VACOPT_DISABLE_PAGE_SKIPPING 0x80 /* don't skip any pages */ -/* - * A ternary value used by vacuum parameters. - * - * DEFAULT value is used to determine the value based on other - * configurations, e.g. reloptions. - */ -typedef enum VacOptTernaryValue -{ - VACOPT_TERNARY_DEFAULT = 0, - VACOPT_TERNARY_DISABLED, - VACOPT_TERNARY_ENABLED, -} VacOptTernaryValue; - /* * Parameters customizing behavior of VACUUM and ANALYZE. * diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 774ac5b2b1..740e22942e 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -307,6 +307,19 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; +/* + * A ternary value used by vacuum parameters. + * + * DEFAULT value is used to determine the value based on other + * configurations, e.g. reloptions. + */ +typedef enum VacOptTernaryValue +{ + VACOPT_TERNARY_DEFAULT = 0, + VACOPT_TERNARY_DISABLED, + VACOPT_TERNARY_ENABLED, +} VacOptTernaryValue; + typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -316,7 +329,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - bool vacuum_index_cleanup; /* enables index vacuuming and cleanup */ + VacOptTernaryValue vacuum_index_cleanup; /* enables index vacuuming and cleanup */ bool vacuum_truncate; /* enables vacuum to truncate a relation */ } StdRdOptions; diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 5554275e64..60df707f36 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -140,15 +140,6 @@ static relopt_bool boolRelOpts[] = }, false }, - { - { - "vacuum_index_cleanup", - "Enables index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - true - }, { { "vacuum_truncate", @@ -474,6 +465,19 @@ static relopt_real realRelOpts[] = {{NULL}} }; +/* values from HeapOptIndexCleanupMode */ +relopt_enum_elt_def HeapOptIndexCleanupOptValues[] = +{ + {"auto", VACOPT_TERNARY_DEFAULT}, + {"on", VACOPT_TERNARY_ENABLED}, + {"off", VACOPT_TERNARY_DISABLED}, + {"true", VACOPT_TERNARY_ENABLED}, + {"false", VACOPT_TERNARY_DISABLED}, + {"1", VACOPT_TERNARY_ENABLED}, + {"0", VACOPT_TERNARY_DISABLED}, + {(const char *) NULL} /* list terminator */ +}; + /* values from GistOptBufferingMode */ relopt_enum_elt_def gistBufferingOptValues[] = { @@ -494,6 +498,17 @@ relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { + { + { + "vacuum_index_cleanup", + "Enables index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + HeapOptIndexCleanupOptValues, + VACOPT_TERNARY_DEFAULT, + gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") + }, { { "buffering", diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index ad3feb88b3..db22ca1ee1 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -313,6 +313,8 @@ typedef struct LVRelState bool do_index_cleanup; /* Wraparound failsafe in effect? (implies !do_index_vacuuming) */ bool do_failsafe; + /* Consider bypass optimization? */ + bool do_bypass_optimization; /* Buffer access strategy and parallel state */ BufferAccessStrategy bstrategy; @@ -406,7 +408,7 @@ static void lazy_scan_prune(LVRelState *vacrel, Buffer buf, BlockNumber blkno, Page page, GlobalVisState *vistest, LVPagePruneState *prunestate); -static void lazy_vacuum(LVRelState *vacrel, bool onecall); +static void lazy_vacuum(LVRelState *vacrel); static bool lazy_vacuum_all_indexes(LVRelState *vacrel); static void lazy_vacuum_heap_rel(LVRelState *vacrel); static int lazy_vacuum_heap_page(LVRelState *vacrel, BlockNumber blkno, @@ -507,7 +509,6 @@ heap_vacuum_rel(Relation rel, VacuumParams *params, MultiXactId MultiXactCutoff; Assert(params != NULL); - Assert(params->index_cleanup != VACOPT_TERNARY_DEFAULT); Assert(params->truncate != VACOPT_TERNARY_DEFAULT); /* measure elapsed time iff autovacuum logging requires it */ @@ -560,11 +561,15 @@ heap_vacuum_rel(Relation rel, VacuumParams *params, vacrel->do_index_vacuuming = true; vacrel->do_index_cleanup = true; vacrel->do_failsafe = false; + vacrel->do_bypass_optimization = true; if (params->index_cleanup == VACOPT_TERNARY_DISABLED) { vacrel->do_index_vacuuming = false; vacrel->do_index_cleanup = false; } + else if (params->index_cleanup == VACOPT_TERNARY_ENABLED) + vacrel->do_bypass_optimization = false; + vacrel->bstrategy = bstrategy; vacrel->old_rel_pages = rel->rd_rel->relpages; vacrel->old_live_tuples = rel->rd_rel->reltuples; @@ -893,8 +898,7 @@ lazy_scan_heap(LVRelState *vacrel, VacuumParams *params, bool aggressive) next_fsm_block_to_vacuum; PGRUsage ru0; Buffer vmbuffer = InvalidBuffer; - bool skipping_blocks, - have_vacuumed_indexes = false; + bool skipping_blocks; StringInfoData buf; const int initprog_index[] = { PROGRESS_VACUUM_PHASE, @@ -1167,8 +1171,8 @@ lazy_scan_heap(LVRelState *vacrel, VacuumParams *params, bool aggressive) } /* Remove the collected garbage tuples from table and indexes */ - lazy_vacuum(vacrel, false); - have_vacuumed_indexes = true; + vacrel->do_bypass_optimization = false; + lazy_vacuum(vacrel); /* * Vacuum the Free Space Map to make newly-freed space visible on @@ -1580,7 +1584,7 @@ lazy_scan_heap(LVRelState *vacrel, VacuumParams *params, bool aggressive) /* If any tuples need to be deleted, perform final vacuum cycle */ if (dead_tuples->num_tuples > 0) - lazy_vacuum(vacrel, !have_vacuumed_indexes); + lazy_vacuum(vacrel); /* * Vacuum the remainder of the Free Space Map. We must do this whether or @@ -2065,9 +2069,9 @@ retry: * wraparound. */ static void -lazy_vacuum(LVRelState *vacrel, bool onecall) +lazy_vacuum(LVRelState *vacrel) { - bool do_bypass_optimization; + bool bypass; /* Should not end up here with no indexes */ Assert(vacrel->nindexes > 0); @@ -2100,8 +2104,8 @@ lazy_vacuum(LVRelState *vacrel, bool onecall) * It's far easier to ensure that 99%+ of all UPDATEs against a table use * HOT through careful tuning. */ - do_bypass_optimization = false; - if (onecall && vacrel->rel_pages > 0) + bypass = false; + if (vacrel->do_bypass_optimization && vacrel->rel_pages > 0) { BlockNumber threshold; @@ -2133,12 +2137,11 @@ lazy_vacuum(LVRelState *vacrel, bool onecall) * expanded to cover more cases then this may need to be reconsidered. */ threshold = (double) vacrel->rel_pages * BYPASS_THRESHOLD_PAGES; - do_bypass_optimization = - (vacrel->lpdead_item_pages < threshold && - vacrel->lpdead_items < MAXDEADTUPLES(32L * 1024L * 1024L)); + bypass = (vacrel->lpdead_item_pages < threshold && + vacrel->lpdead_items < MAXDEADTUPLES(32L * 1024L * 1024L)); } - if (do_bypass_optimization) + if (bypass) { /* * There are almost zero TIDs. Behave as if there were precisely diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7421d7cfbd..3b17d028af 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -1939,14 +1939,9 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) LockRelationIdForSession(&lockrelid, lmode); /* Set index cleanup option based on reloptions if not yet */ - if (params->index_cleanup == VACOPT_TERNARY_DEFAULT) - { - if (rel->rd_options == NULL || - ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup) - params->index_cleanup = VACOPT_TERNARY_ENABLED; - else - params->index_cleanup = VACOPT_TERNARY_DISABLED; - } + if (params->index_cleanup == VACOPT_TERNARY_DEFAULT && rel->rd_options != NULL) + params->index_cleanup = + ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; /* Set truncate option based on reloptions if not yet */ if (params->truncate == VACOPT_TERNARY_DEFAULT) -- 2.27.0