On Mon, Dec 14, 2020 at 06:14:17PM -0600, Justin Pryzby wrote: > On Sat, Dec 12, 2020 at 01:45:26PM -0600, Justin Pryzby wrote: > > On Sat, Dec 12, 2020 at 09:20:35AM +0100, Peter Eisentraut wrote: > > > On 2020-12-11 21:27, Alvaro Herrera wrote: > > > > By the way-- What did you think of the idea of explictly marking the > > > > types used for bitmasks using types bits32 and friends, instead of plain > > > > int, which is harder to spot? > > > > > > If we want to make it clearer, why not turn the thing into a struct, as in > > > the attached patch, and avoid the bit fiddling altogether. > > > > I like this. > > It's a lot like what I wrote as [PATCH v31 1/5] ExecReindex and > > ReindexParams > > In my v31 patch, I moved ReindexOptions to a private structure in > > indexcmds.c, > > with an "int options" bitmask which is passed to reindex_index() et al. > > Your > > patch keeps/puts ReindexOptions index.h, so it also applies to > > reindex_index, > > which I think is good. > > > > So I've rebased this branch on your patch. > > > > Some thoughts: > > > > - what about removing the REINDEXOPT_* prefix ? > > - You created local vars with initialization like "={}". But I thought it's > > needed to include at least one struct member like "={false}", or else > > they're not guaranteed to be zerod ? > > - You passed the structure across function calls. The usual convention is > > to > > pass a pointer. > > I think maybe Michael missed this message (?) > I had applied some changes on top of Peter's patch. > > I squished those commits now, and also handled ClusterOption and VacuumOption > in the same style. > > Some more thoughts: > - should the structures be named in plural ? "ReindexOptions" etc. Since > they > define *all* the options, not just a single bit. > - For vacuum, do we even need a separate structure, or should the members be > directly within VacuumParams ? It's a bit odd to write > params.options.verbose. Especially since there's also ternary options > which > are directly within params. > - Then, for cluster, I think it should be called ClusterParams, and > eventually > include the tablespaceOid, like what we're doing for Reindex. > > I am awaiting feedback on these before going further since I've done too much > rebasing with these ideas going back and forth and back.
With Alexey's agreement, I propose something like this. I've merged some commits and kept separate the ones which are more likely to be disputed/amended. But it may be best to read the series as a single commit, like "git diff origin.." -- Justin
>From ee702a6f49392e84bb51ec4324444d0974c7369b Mon Sep 17 00:00:00 2001 From: Justin Pryzby <pryz...@telsasoft.com> Date: Tue, 15 Dec 2020 17:55:21 -0600 Subject: [PATCH 1/4] Convert options to struct: Reindex/Cluster/Vacuum Remove prefixes and lowercase structure member variables; Rename to plural: Vacuum/ClusterOptions; --- src/backend/access/heap/vacuumlazy.c | 8 +- src/backend/catalog/index.c | 26 +++--- src/backend/commands/analyze.c | 15 ++-- src/backend/commands/cluster.c | 29 +++--- src/backend/commands/indexcmds.c | 100 ++++++++++----------- src/backend/commands/tablecmds.c | 4 +- src/backend/commands/vacuum.c | 128 +++++++++++++-------------- src/backend/postmaster/autovacuum.c | 14 +-- src/backend/tcop/utility.c | 10 +-- src/include/catalog/index.h | 16 ++-- src/include/commands/cluster.h | 10 +-- src/include/commands/defrem.h | 9 +- src/include/commands/vacuum.h | 29 +++--- 13 files changed, 198 insertions(+), 200 deletions(-) diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index 25f2d5df1b..6bfed2b2da 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -456,7 +456,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params, starttime = GetCurrentTimestamp(); } - if (params->options & VACOPT_VERBOSE) + if (params->options.verbose) elevel = INFO; else elevel = DEBUG2; @@ -484,7 +484,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params, xidFullScanLimit); aggressive |= MultiXactIdPrecedesOrEquals(onerel->rd_rel->relminmxid, mxactFullScanLimit); - if (params->options & VACOPT_DISABLE_PAGE_SKIPPING) + if (params->options.disable_page_skipping) aggressive = true; vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats)); @@ -902,7 +902,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats, * be replayed on any hot standby, where it can be disruptive. */ next_unskippable_block = 0; - if ((params->options & VACOPT_DISABLE_PAGE_SKIPPING) == 0) + if (!params->options.disable_page_skipping) { while (next_unskippable_block < nblocks) { @@ -960,7 +960,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats, { /* Time to advance next_unskippable_block */ next_unskippable_block++; - if ((params->options & VACOPT_DISABLE_PAGE_SKIPPING) == 0) + if (!params->options.disable_page_skipping) { while (next_unskippable_block < nblocks) { diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 731610c701..ecd66ff3df 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -3594,7 +3594,7 @@ IndexGetRelation(Oid indexId, bool missing_ok) */ void reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, - int options) + ReindexOptions *options) { Relation iRel, heapRelation; @@ -3602,7 +3602,6 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, IndexInfo *indexInfo; volatile bool skipped_constraint = false; PGRUsage ru0; - bool progress = (options & REINDEXOPT_REPORT_PROGRESS) != 0; pg_rusage_init(&ru0); @@ -3611,12 +3610,12 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, * we only need to be sure no schema or data changes are going on. */ heapId = IndexGetRelation(indexId, - (options & REINDEXOPT_MISSING_OK) != 0); + options->missing_ok); /* if relation is missing, leave */ if (!OidIsValid(heapId)) return; - if ((options & REINDEXOPT_MISSING_OK) != 0) + if (options->missing_ok) heapRelation = try_table_open(heapId, ShareLock); else heapRelation = table_open(heapId, ShareLock); @@ -3625,7 +3624,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, if (!heapRelation) return; - if (progress) + if (options->report_progress) { pgstat_progress_start_command(PROGRESS_COMMAND_CREATE_INDEX, heapId); @@ -3641,7 +3640,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, */ iRel = index_open(indexId, AccessExclusiveLock); - if (progress) + if (options->report_progress) pgstat_progress_update_param(PROGRESS_CREATEIDX_ACCESS_METHOD_OID, iRel->rd_rel->relam); @@ -3792,14 +3791,14 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, } /* Log what we did */ - if (options & REINDEXOPT_VERBOSE) + if (options->verbose) ereport(INFO, (errmsg("index \"%s\" was reindexed", get_rel_name(indexId)), errdetail_internal("%s", pg_rusage_show(&ru0)))); - if (progress) + if (options->report_progress) pgstat_progress_end_command(); /* Close rels, but keep locks */ @@ -3846,7 +3845,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, * index rebuild. */ bool -reindex_relation(Oid relid, int flags, int options) +reindex_relation(Oid relid, int flags, ReindexOptions *options) { Relation rel; Oid toast_relid; @@ -3861,7 +3860,7 @@ reindex_relation(Oid relid, int flags, int options) * to prevent schema and data changes in it. The lock level used here * should match ReindexTable(). */ - if ((options & REINDEXOPT_MISSING_OK) != 0) + if (options->missing_ok) rel = try_table_open(relid, ShareLock); else rel = table_open(relid, ShareLock); @@ -3963,10 +3962,11 @@ reindex_relation(Oid relid, int flags, int options) { /* * Note that this should fail if the toast relation is missing, so - * reset REINDEXOPT_MISSING_OK. + * reset missing_ok. */ - result |= reindex_relation(toast_relid, flags, - options & ~(REINDEXOPT_MISSING_OK)); + ReindexOptions newoptions = *options; + newoptions.missing_ok = false; + result |= reindex_relation(toast_relid, flags, &newoptions); } return result; diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 8af12b5c6b..884bfeee21 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -124,9 +124,10 @@ analyze_rel(Oid relid, RangeVar *relation, int elevel; AcquireSampleRowsFunc acquirefunc = NULL; BlockNumber relpages = 0; + VacuumOptions newoptions; /* Select logging level */ - if (params->options & VACOPT_VERBOSE) + if (params->options.verbose) elevel = INFO; else elevel = DEBUG2; @@ -148,7 +149,9 @@ analyze_rel(Oid relid, RangeVar *relation, * * Make sure to generate only logs for ANALYZE in this case. */ - onerel = vacuum_open_relation(relid, relation, params->options & ~(VACOPT_VACUUM), + newoptions = params->options; + newoptions.vacuum = false; + onerel = vacuum_open_relation(relid, relation, &newoptions, params->log_min_duration >= 0, ShareUpdateExclusiveLock); @@ -166,7 +169,7 @@ analyze_rel(Oid relid, RangeVar *relation, */ if (!vacuum_is_relation_owner(RelationGetRelid(onerel), onerel->rd_rel, - params->options & VACOPT_ANALYZE)) + &newoptions)) { relation_close(onerel, ShareUpdateExclusiveLock); return; @@ -238,7 +241,7 @@ analyze_rel(Oid relid, RangeVar *relation, else { /* No need for a WARNING if we already complained during VACUUM */ - if (!(params->options & VACOPT_VACUUM)) + if (!params->options.vacuum) ereport(WARNING, (errmsg("skipping \"%s\" --- cannot analyze non-tables or special system tables", RelationGetRelationName(onerel)))); @@ -624,7 +627,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params, * VACUUM ANALYZE, don't overwrite the accurate count already inserted by * VACUUM. */ - if (!inh && !(params->options & VACOPT_VACUUM)) + if (!inh && !params->options.vacuum) { for (ind = 0; ind < nindexes; ind++) { @@ -655,7 +658,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params, (va_cols == NIL)); /* If this isn't part of VACUUM ANALYZE, let index AMs do cleanup */ - if (!(params->options & VACOPT_VACUUM)) + if (!params->options.vacuum) { for (ind = 0; ind < nindexes; ind++) { diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index fd5a6eec86..e57bef42aa 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -103,8 +103,7 @@ void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) { ListCell *lc; - int options = 0; - bool verbose = false; + ClusterOptions options = {false}; /* Parse option list */ foreach(lc, stmt->params) @@ -112,7 +111,7 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) DefElem *opt = (DefElem *) lfirst(lc); if (strcmp(opt->defname, "verbose") == 0) - verbose = defGetBoolean(opt); + options.verbose = defGetBoolean(opt); else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -121,8 +120,6 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) parser_errposition(pstate, opt->location))); } - options = (verbose ? CLUOPT_VERBOSE : 0); - if (stmt->relation != NULL) { /* This is the single-relation case. */ @@ -192,7 +189,7 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) table_close(rel, NoLock); /* Do the job. */ - cluster_rel(tableOid, indexOid, options); + cluster_rel(tableOid, indexOid, &options); } else { @@ -234,14 +231,15 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) foreach(rv, rvs) { RelToCluster *rvtc = (RelToCluster *) lfirst(rv); + ClusterOptions newoptions = options; + newoptions.recheck = true; /* Start a new transaction for each relation. */ StartTransactionCommand(); /* functions in indexes may want a snapshot set */ PushActiveSnapshot(GetTransactionSnapshot()); /* Do the job. */ - cluster_rel(rvtc->tableOid, rvtc->indexOid, - options | CLUOPT_RECHECK); + cluster_rel(rvtc->tableOid, rvtc->indexOid, &newoptions); PopActiveSnapshot(); CommitTransactionCommand(); } @@ -272,11 +270,9 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) * and error messages should refer to the operation as VACUUM not CLUSTER. */ void -cluster_rel(Oid tableOid, Oid indexOid, int options) +cluster_rel(Oid tableOid, Oid indexOid, ClusterOptions *options) { Relation OldHeap; - bool verbose = ((options & CLUOPT_VERBOSE) != 0); - bool recheck = ((options & CLUOPT_RECHECK) != 0); /* Check for user-requested abort. */ CHECK_FOR_INTERRUPTS(); @@ -312,7 +308,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options) * *must* skip the one on indisclustered since it would reject an attempt * to cluster a not-previously-clustered index. */ - if (recheck) + if (options->recheck) { /* Check that the user still owns the relation */ if (!pg_class_ownercheck(tableOid, GetUserId())) @@ -396,7 +392,9 @@ cluster_rel(Oid tableOid, Oid indexOid, int options) /* Check heap and index are valid to cluster on */ if (OidIsValid(indexOid)) - check_index_is_clusterable(OldHeap, indexOid, recheck, AccessExclusiveLock); + check_index_is_clusterable(OldHeap, indexOid, options->recheck, + AccessExclusiveLock); + /* * Quietly ignore the request if this is a materialized view which has not @@ -422,7 +420,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options) TransferPredicateLocksToHeapRelation(OldHeap); /* rebuild_relation does all the dirty work */ - rebuild_relation(OldHeap, indexOid, verbose); + rebuild_relation(OldHeap, indexOid, options->verbose); /* NB: rebuild_relation does table_close() on OldHeap */ @@ -1353,6 +1351,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, char newrelpersistence) { ObjectAddress object; + ReindexOptions reindexopts = {false}; /* Default options are all false */ Oid mapped_tables[4]; int reindex_flags; int i; @@ -1412,7 +1411,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE, PROGRESS_CLUSTER_PHASE_REBUILD_INDEX); - reindex_relation(OIDOldHeap, reindex_flags, 0); + reindex_relation(OIDOldHeap, reindex_flags, &reindexopts); /* Report that we are now doing clean up */ pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE, diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 14d24b3cc4..13e463da90 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -89,9 +89,9 @@ static List *ChooseIndexColumnNames(List *indexElems); static void RangeVarCallbackForReindexIndex(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg); static void reindex_error_callback(void *args); -static void ReindexPartitions(Oid relid, int options, bool isTopLevel); -static void ReindexMultipleInternal(List *relids, int options); -static bool ReindexRelationConcurrently(Oid relationOid, int options); +static void ReindexPartitions(Oid relid, ReindexOptions *options, bool isTopLevel); +static void ReindexMultipleInternal(List *relids, ReindexOptions *options); +static bool ReindexRelationConcurrently(Oid relationOid, ReindexOptions *options); static void update_relispartition(Oid relationId, bool newval); static inline void set_indexsafe_procflags(void); @@ -100,7 +100,7 @@ static inline void set_indexsafe_procflags(void); */ struct ReindexIndexCallbackState { - int options; /* options from statement */ + ReindexOptions options; /* options from statement */ Oid locked_table_oid; /* tracks previously locked table */ }; @@ -2455,13 +2455,11 @@ ChooseIndexColumnNames(List *indexElems) * ReindexParseOptions * Parse list of REINDEX options, returning a bitmask of ReindexOption. */ -int +ReindexOptions ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt) { ListCell *lc; - int options = 0; - bool concurrently = false; - bool verbose = false; + ReindexOptions options = {false}; /* Parse option list */ foreach(lc, stmt->params) @@ -2469,9 +2467,9 @@ ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt) DefElem *opt = (DefElem *) lfirst(lc); if (strcmp(opt->defname, "verbose") == 0) - verbose = defGetBoolean(opt); + options.verbose = defGetBoolean(opt); else if (strcmp(opt->defname, "concurrently") == 0) - concurrently = defGetBoolean(opt); + options.concurrently = defGetBoolean(opt); else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -2480,10 +2478,6 @@ ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt) parser_errposition(pstate, opt->location))); } - options = - (verbose ? REINDEXOPT_VERBOSE : 0) | - (concurrently ? REINDEXOPT_CONCURRENTLY : 0); - return options; } @@ -2492,7 +2486,7 @@ ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt) * Recreate a specific index. */ void -ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel) +ReindexIndex(RangeVar *indexRelation, ReindexOptions *options, bool isTopLevel) { struct ReindexIndexCallbackState state; Oid indOid; @@ -2509,10 +2503,10 @@ ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel) * upgrade the lock, but that's OK, because other sessions can't hold * locks on our temporary table. */ - state.options = options; + state.options = *options; state.locked_table_oid = InvalidOid; indOid = RangeVarGetRelidExtended(indexRelation, - (options & REINDEXOPT_CONCURRENTLY) != 0 ? + options->concurrently ? ShareUpdateExclusiveLock : AccessExclusiveLock, 0, RangeVarCallbackForReindexIndex, @@ -2527,12 +2521,15 @@ ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel) if (relkind == RELKIND_PARTITIONED_INDEX) ReindexPartitions(indOid, options, isTopLevel); - else if ((options & REINDEXOPT_CONCURRENTLY) != 0 && + else if (options->concurrently && persistence != RELPERSISTENCE_TEMP) ReindexRelationConcurrently(indOid, options); else - reindex_index(indOid, false, persistence, - options | REINDEXOPT_REPORT_PROGRESS); + { + ReindexOptions newoptions = *options; + newoptions.report_progress = true; + reindex_index(indOid, false, persistence, &newoptions); + } } /* @@ -2553,7 +2550,7 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation, * non-concurrent case and table locks used by index_concurrently_*() for * concurrent case. */ - table_lockmode = ((state->options & REINDEXOPT_CONCURRENTLY) != 0) ? + table_lockmode = state->options.concurrently ? ShareUpdateExclusiveLock : ShareLock; /* @@ -2611,7 +2608,7 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation, * Recreate all indexes of a table (and of its toast table, if any) */ Oid -ReindexTable(RangeVar *relation, int options, bool isTopLevel) +ReindexTable(RangeVar *relation, ReindexOptions *options, bool isTopLevel) { Oid heapOid; bool result; @@ -2625,14 +2622,14 @@ ReindexTable(RangeVar *relation, int options, bool isTopLevel) * locks on our temporary table. */ heapOid = RangeVarGetRelidExtended(relation, - (options & REINDEXOPT_CONCURRENTLY) != 0 ? + options->concurrently ? ShareUpdateExclusiveLock : ShareLock, 0, RangeVarCallbackOwnsTable, NULL); if (get_rel_relkind(heapOid) == RELKIND_PARTITIONED_TABLE) ReindexPartitions(heapOid, options, isTopLevel); - else if ((options & REINDEXOPT_CONCURRENTLY) != 0 && + else if (options->concurrently && get_rel_persistence(heapOid) != RELPERSISTENCE_TEMP) { result = ReindexRelationConcurrently(heapOid, options); @@ -2644,10 +2641,12 @@ ReindexTable(RangeVar *relation, int options, bool isTopLevel) } else { + ReindexOptions newoptions = *options; + newoptions.report_progress = true; result = reindex_relation(heapOid, REINDEX_REL_PROCESS_TOAST | REINDEX_REL_CHECK_CONSTRAINTS, - options | REINDEXOPT_REPORT_PROGRESS); + &newoptions); if (!result) ereport(NOTICE, (errmsg("table \"%s\" has no indexes to reindex", @@ -2667,7 +2666,7 @@ ReindexTable(RangeVar *relation, int options, bool isTopLevel) */ void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, - int options) + ReindexOptions *options) { Oid objectOid; Relation relationRelation; @@ -2686,7 +2685,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, objectKind == REINDEX_OBJECT_DATABASE); if (objectKind == REINDEX_OBJECT_SYSTEM && - (options & REINDEXOPT_CONCURRENTLY) != 0) + options->concurrently) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot reindex system catalogs concurrently"))); @@ -2794,7 +2793,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, * Skip system tables, since index_create() would reject indexing them * concurrently (and it would likely fail if we tried). */ - if ((options & REINDEXOPT_CONCURRENTLY) != 0 && + if (options->concurrently && IsCatalogRelationOid(relid)) { if (!concurrent_warning) @@ -2860,7 +2859,7 @@ reindex_error_callback(void *arg) * by the caller. */ static void -ReindexPartitions(Oid relid, int options, bool isTopLevel) +ReindexPartitions(Oid relid, ReindexOptions *options, bool isTopLevel) { List *partitions = NIL; char relkind = get_rel_relkind(relid); @@ -2955,7 +2954,7 @@ ReindexPartitions(Oid relid, int options, bool isTopLevel) * and starts a new transaction when finished. */ static void -ReindexMultipleInternal(List *relids, int options) +ReindexMultipleInternal(List *relids, ReindexOptions *options) { ListCell *l; @@ -2991,35 +2990,36 @@ ReindexMultipleInternal(List *relids, int options) Assert(relkind != RELKIND_PARTITIONED_INDEX && relkind != RELKIND_PARTITIONED_TABLE); - if ((options & REINDEXOPT_CONCURRENTLY) != 0 && + if (options->concurrently && relpersistence != RELPERSISTENCE_TEMP) { - (void) ReindexRelationConcurrently(relid, - options | - REINDEXOPT_MISSING_OK); + ReindexOptions newoptions = *options; + newoptions.missing_ok = true; + (void) ReindexRelationConcurrently(relid, &newoptions); /* ReindexRelationConcurrently() does the verbose output */ } else if (relkind == RELKIND_INDEX) { - reindex_index(relid, false, relpersistence, - options | - REINDEXOPT_REPORT_PROGRESS | - REINDEXOPT_MISSING_OK); + ReindexOptions newoptions = *options; + newoptions.report_progress = true; + newoptions.missing_ok = true; + reindex_index(relid, false, relpersistence, &newoptions); PopActiveSnapshot(); /* reindex_index() does the verbose output */ } else { bool result; + ReindexOptions newoptions = *options; + newoptions.report_progress = true; + newoptions.missing_ok = true; result = reindex_relation(relid, REINDEX_REL_PROCESS_TOAST | REINDEX_REL_CHECK_CONSTRAINTS, - options | - REINDEXOPT_REPORT_PROGRESS | - REINDEXOPT_MISSING_OK); + &newoptions); - if (result && (options & REINDEXOPT_VERBOSE)) + if (result && options->verbose) ereport(INFO, (errmsg("table \"%s.%s\" was reindexed", get_namespace_name(get_rel_namespace(relid)), @@ -3059,7 +3059,7 @@ ReindexMultipleInternal(List *relids, int options) * anyway, and a non-concurrent reindex is more efficient. */ static bool -ReindexRelationConcurrently(Oid relationOid, int options) +ReindexRelationConcurrently(Oid relationOid, ReindexOptions *options) { List *heapRelationIds = NIL; List *indexIds = NIL; @@ -3092,7 +3092,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) "ReindexConcurrent", ALLOCSET_SMALL_SIZES); - if (options & REINDEXOPT_VERBOSE) + if (options->verbose) { /* Save data needed by REINDEX VERBOSE in private context */ oldcontext = MemoryContextSwitchTo(private_context); @@ -3137,7 +3137,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) errmsg("cannot reindex system catalogs concurrently"))); /* Open relation to get its indexes */ - if ((options & REINDEXOPT_MISSING_OK) != 0) + if (options->missing_ok) { heapRelation = try_table_open(relationOid, ShareUpdateExclusiveLock); @@ -3233,7 +3233,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) case RELKIND_INDEX: { Oid heapId = IndexGetRelation(relationOid, - (options & REINDEXOPT_MISSING_OK) != 0); + options->missing_ok); Relation heapRelation; /* if relation is missing, leave */ @@ -3259,10 +3259,10 @@ ReindexRelationConcurrently(Oid relationOid, int options) /* * Check if parent relation can be locked and if it exists, * this needs to be done at this stage as the list of indexes - * to rebuild is not complete yet, and REINDEXOPT_MISSING_OK + * to rebuild is not complete yet, and missing_ok * should not be used once all the session locks are taken. */ - if ((options & REINDEXOPT_MISSING_OK) != 0) + if (options->missing_ok) { heapRelation = try_table_open(heapId, ShareUpdateExclusiveLock); @@ -3303,7 +3303,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) /* * Definitely no indexes, so leave. Any checks based on - * REINDEXOPT_MISSING_OK should be done only while the list of indexes to + * missing_ok should be done only while the list of indexes to * work on is built as the session locks taken before this transaction * commits will make sure that they cannot be dropped by a concurrent * session until this operation completes. @@ -3754,7 +3754,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) StartTransactionCommand(); /* Log what we did */ - if (options & REINDEXOPT_VERBOSE) + if (options->verbose) { if (relkind == RELKIND_INDEX) ereport(INFO, diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 1fa9f19f08..e0f62d3c77 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -1854,6 +1854,7 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, { Oid heap_relid; Oid toast_relid; + ReindexOptions reindexopts = {false}; /* Default options are all false */ /* * This effectively deletes all rows in the table, and may be done @@ -1891,7 +1892,8 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, /* * Reconstruct the indexes to match, and we're done. */ - reindex_relation(heap_relid, REINDEX_REL_PROCESS_TOAST, 0); + reindex_relation(heap_relid, REINDEX_REL_PROCESS_TOAST, + &reindexopts); } pgstat_count_truncate(rel); diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 98270a1049..99b0345338 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -78,8 +78,8 @@ pg_atomic_uint32 *VacuumActiveNWorkers = NULL; int VacuumCostBalanceLocal = 0; /* non-export function prototypes */ -static List *expand_vacuum_rel(VacuumRelation *vrel, int options); -static List *get_all_vacuum_rels(int options); +static List *expand_vacuum_rel(VacuumRelation *vrel, VacuumOptions *options); +static List *get_all_vacuum_rels(VacuumOptions *options); static void vac_truncate_clog(TransactionId frozenXID, MultiXactId minMulti, TransactionId lastSaneFrozenXid, @@ -97,13 +97,7 @@ static VacOptTernaryValue get_vacopt_ternary_value(DefElem *def); void ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) { - VacuumParams params; - bool verbose = false; - bool skip_locked = false; - bool analyze = false; - bool freeze = false; - bool full = false; - bool disable_page_skipping = false; + VacuumParams params = {.options={false} }; ListCell *lc; /* Set default value */ @@ -120,9 +114,9 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) /* Parse common options for VACUUM and ANALYZE */ if (strcmp(opt->defname, "verbose") == 0) - verbose = defGetBoolean(opt); + params.options.verbose = defGetBoolean(opt); else if (strcmp(opt->defname, "skip_locked") == 0) - skip_locked = defGetBoolean(opt); + params.options.skip_locked = defGetBoolean(opt); else if (!vacstmt->is_vacuumcmd) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -131,13 +125,13 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) /* Parse options available on VACUUM */ else if (strcmp(opt->defname, "analyze") == 0) - analyze = defGetBoolean(opt); + params.options.analyze = defGetBoolean(opt); else if (strcmp(opt->defname, "freeze") == 0) - freeze = defGetBoolean(opt); + params.options.freeze = defGetBoolean(opt); else if (strcmp(opt->defname, "full") == 0) - full = defGetBoolean(opt); + params.options.full = defGetBoolean(opt); else if (strcmp(opt->defname, "disable_page_skipping") == 0) - disable_page_skipping = defGetBoolean(opt); + params.options.disable_page_skipping = defGetBoolean(opt); else if (strcmp(opt->defname, "index_cleanup") == 0) params.index_cleanup = get_vacopt_ternary_value(opt); else if (strcmp(opt->defname, "truncate") == 0) @@ -181,31 +175,26 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) parser_errposition(pstate, opt->location))); } - /* Set vacuum options */ - params.options = - (vacstmt->is_vacuumcmd ? VACOPT_VACUUM : VACOPT_ANALYZE) | - (verbose ? VACOPT_VERBOSE : 0) | - (skip_locked ? VACOPT_SKIP_LOCKED : 0) | - (analyze ? VACOPT_ANALYZE : 0) | - (freeze ? VACOPT_FREEZE : 0) | - (full ? VACOPT_FULL : 0) | - (disable_page_skipping ? VACOPT_DISABLE_PAGE_SKIPPING : 0); + if (vacstmt->is_vacuumcmd) + params.options.vacuum = true; + else + params.options.analyze = true; /* sanity checks on options */ - Assert(params.options & (VACOPT_VACUUM | VACOPT_ANALYZE)); - Assert((params.options & VACOPT_VACUUM) || - !(params.options & (VACOPT_FULL | VACOPT_FREEZE))); - Assert(!(params.options & VACOPT_SKIPTOAST)); + Assert(params.options.vacuum || params.options.analyze); + Assert(params.options.vacuum || + !(params.options.full || params.options.freeze)); + Assert(!params.options.skiptoast); - if ((params.options & VACOPT_FULL) && params.nworkers > 0) + if (params.options.full && params.nworkers > 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("VACUUM FULL cannot be performed in parallel"))); /* - * Make sure VACOPT_ANALYZE is specified if any column lists are present. + * Make sure analyze is specified if any column lists are present. */ - if (!(params.options & VACOPT_ANALYZE)) + if (!params.options.analyze) { ListCell *lc; @@ -224,7 +213,7 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) * All freeze ages are zero if the FREEZE option is given; otherwise pass * them as -1 which means to use the default values. */ - if (params.options & VACOPT_FREEZE) + if (params.options.freeze) { params.freeze_min_age = 0; params.freeze_table_age = 0; @@ -280,7 +269,7 @@ vacuum(List *relations, VacuumParams *params, Assert(params != NULL); - stmttype = (params->options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE"; + stmttype = params->options.vacuum ? "VACUUM" : "ANALYZE"; /* * We cannot run VACUUM inside a user transaction block; if we were inside @@ -290,7 +279,7 @@ vacuum(List *relations, VacuumParams *params, * * ANALYZE (without VACUUM) can run either way. */ - if (params->options & VACOPT_VACUUM) + if (params->options.vacuum) { PreventInTransactionBlock(isTopLevel, stmttype); in_outer_xact = false; @@ -312,8 +301,8 @@ vacuum(List *relations, VacuumParams *params, /* * Sanity check DISABLE_PAGE_SKIPPING option. */ - if ((params->options & VACOPT_FULL) != 0 && - (params->options & VACOPT_DISABLE_PAGE_SKIPPING) != 0) + if (params->options.full && + params->options.disable_page_skipping) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("VACUUM option DISABLE_PAGE_SKIPPING cannot be used with FULL"))); @@ -322,7 +311,7 @@ vacuum(List *relations, VacuumParams *params, * Send info about dead objects to the statistics collector, unless we are * in autovacuum --- autovacuum.c does this for itself. */ - if ((params->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess()) + if (params->options.vacuum && !IsAutoVacuumWorkerProcess()) pgstat_vacuum_stat(); /* @@ -363,7 +352,7 @@ vacuum(List *relations, VacuumParams *params, List *sublist; MemoryContext old_context; - sublist = expand_vacuum_rel(vrel, params->options); + sublist = expand_vacuum_rel(vrel, ¶ms->options); old_context = MemoryContextSwitchTo(vac_context); newrels = list_concat(newrels, sublist); MemoryContextSwitchTo(old_context); @@ -371,7 +360,7 @@ vacuum(List *relations, VacuumParams *params, relations = newrels; } else - relations = get_all_vacuum_rels(params->options); + relations = get_all_vacuum_rels(¶ms->options); /* * Decide whether we need to start/commit our own transactions. @@ -387,11 +376,11 @@ vacuum(List *relations, VacuumParams *params, * transaction block, and also in an autovacuum worker, use own * transactions so we can release locks sooner. */ - if (params->options & VACOPT_VACUUM) + if (params->options.vacuum) use_own_xacts = true; else { - Assert(params->options & VACOPT_ANALYZE); + Assert(params->options.analyze); if (IsAutoVacuumWorkerProcess()) use_own_xacts = true; else if (in_outer_xact) @@ -444,13 +433,13 @@ vacuum(List *relations, VacuumParams *params, { VacuumRelation *vrel = lfirst_node(VacuumRelation, cur); - if (params->options & VACOPT_VACUUM) + if (params->options.vacuum) { if (!vacuum_rel(vrel->oid, vrel->relation, params)) continue; } - if (params->options & VACOPT_ANALYZE) + if (params->options.analyze) { /* * If using separate xacts, start one for analyze. Otherwise, @@ -504,7 +493,7 @@ vacuum(List *relations, VacuumParams *params, StartTransactionCommand(); } - if ((params->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess()) + if (params->options.vacuum && !IsAutoVacuumWorkerProcess()) { /* * Update pg_database.datfrozenxid, and truncate pg_xact if possible. @@ -530,11 +519,11 @@ vacuum(List *relations, VacuumParams *params, * ANALYZE. */ bool -vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int options) +vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, VacuumOptions *options) { char *relname; - Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0); + Assert(options->vacuum || options->analyze); /* * Check permissions. @@ -553,7 +542,7 @@ vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int options) relname = NameStr(reltuple->relname); - if ((options & VACOPT_VACUUM) != 0) + if (options->vacuum) { if (reltuple->relisshared) ereport(WARNING, @@ -576,7 +565,7 @@ vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int options) return false; } - if ((options & VACOPT_ANALYZE) != 0) + if (options->analyze) { if (reltuple->relisshared) ereport(WARNING, @@ -604,14 +593,14 @@ vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int options) * or locked, a log is emitted if possible. */ Relation -vacuum_open_relation(Oid relid, RangeVar *relation, int options, +vacuum_open_relation(Oid relid, RangeVar *relation, VacuumOptions *options, bool verbose, LOCKMODE lmode) { Relation onerel; bool rel_lock = true; int elevel; - Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0); + Assert(options->vacuum || options->analyze); /* * Open the relation and get the appropriate lock on it. @@ -622,7 +611,7 @@ vacuum_open_relation(Oid relid, RangeVar *relation, int options, * If we've been asked not to wait for the relation lock, acquire it first * in non-blocking mode, before calling try_relation_open(). */ - if (!(options & VACOPT_SKIP_LOCKED)) + if (!options->skip_locked) onerel = try_relation_open(relid, lmode); else if (ConditionalLockRelationOid(relid, lmode)) onerel = try_relation_open(relid, NoLock); @@ -662,7 +651,7 @@ vacuum_open_relation(Oid relid, RangeVar *relation, int options, else return NULL; - if ((options & VACOPT_VACUUM) != 0) + if (options->vacuum) { if (!rel_lock) ereport(elevel, @@ -683,7 +672,7 @@ vacuum_open_relation(Oid relid, RangeVar *relation, int options, return NULL; } - if ((options & VACOPT_ANALYZE) != 0) + if (options->analyze) { if (!rel_lock) ereport(elevel, @@ -716,7 +705,7 @@ vacuum_open_relation(Oid relid, RangeVar *relation, int options, * are made in vac_context. */ static List * -expand_vacuum_rel(VacuumRelation *vrel, int options) +expand_vacuum_rel(VacuumRelation *vrel, VacuumOptions *options) { List *vacrels = NIL; MemoryContext oldcontext; @@ -748,7 +737,7 @@ expand_vacuum_rel(VacuumRelation *vrel, int options) * below, as well as find_all_inheritors's expectation that the caller * holds some lock on the starting relation. */ - rvr_opts = (options & VACOPT_SKIP_LOCKED) ? RVR_SKIP_LOCKED : 0; + rvr_opts = (options->skip_locked) ? RVR_SKIP_LOCKED : 0; relid = RangeVarGetRelidExtended(vrel->relation, AccessShareLock, rvr_opts, @@ -760,7 +749,7 @@ expand_vacuum_rel(VacuumRelation *vrel, int options) */ if (!OidIsValid(relid)) { - if (options & VACOPT_VACUUM) + if (options->vacuum) ereport(WARNING, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("skipping vacuum of \"%s\" --- lock not available", @@ -855,7 +844,7 @@ expand_vacuum_rel(VacuumRelation *vrel, int options) * the current database. The list is built in vac_context. */ static List * -get_all_vacuum_rels(int options) +get_all_vacuum_rels(VacuumOptions *options) { List *vacrels = NIL; Relation pgclass; @@ -1722,13 +1711,14 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) Oid save_userid; int save_sec_context; int save_nestlevel; + VacuumOptions newoptions; Assert(params != NULL); /* Begin a transaction for vacuuming this relation */ StartTransactionCommand(); - if (!(params->options & VACOPT_FULL)) + if (!params->options.full) { /* * In lazy vacuum, we can set the PROC_IN_VACUUM flag, which lets @@ -1778,11 +1768,11 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) * vacuum, but just ShareUpdateExclusiveLock for concurrent vacuum. Either * way, we can be sure that no other backend is vacuuming the same table. */ - lmode = (params->options & VACOPT_FULL) ? + lmode = (params->options.full) ? AccessExclusiveLock : ShareUpdateExclusiveLock; /* open the relation and get the appropriate lock on it */ - onerel = vacuum_open_relation(relid, relation, params->options, + onerel = vacuum_open_relation(relid, relation, ¶ms->options, params->log_min_duration >= 0, lmode); /* leave if relation could not be opened or locked */ @@ -1801,9 +1791,11 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) * changed in-between. Make sure to only generate logs for VACUUM in this * case. */ + newoptions = params->options; + newoptions.analyze = false; if (!vacuum_is_relation_owner(RelationGetRelid(onerel), onerel->rd_rel, - params->options & VACOPT_VACUUM)) + &newoptions)) { relation_close(onerel, lmode); PopActiveSnapshot(); @@ -1895,7 +1887,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) * us to process it. In VACUUM FULL, though, the toast table is * automatically rebuilt by cluster_rel so we shouldn't recurse to it. */ - if (!(params->options & VACOPT_SKIPTOAST) && !(params->options & VACOPT_FULL)) + if (!params->options.skiptoast && !params->options.full) toast_relid = onerel->rd_rel->reltoastrelid; else toast_relid = InvalidOid; @@ -1914,19 +1906,19 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) /* * Do the actual work --- either FULL or "lazy" vacuum */ - if (params->options & VACOPT_FULL) + if (params->options.full) { - int cluster_options = 0; + ClusterOptions cluster_options = { + .verbose = params->options.verbose, + /* Other members initialized to false/0/NULL */ + }; /* close relation before vacuuming, but hold lock until commit */ relation_close(onerel, NoLock); onerel = NULL; - if ((params->options & VACOPT_VERBOSE) != 0) - cluster_options |= CLUOPT_VERBOSE; - /* VACUUM FULL is now a variant of CLUSTER; see cluster.c */ - cluster_rel(relid, InvalidOid, cluster_options); + cluster_rel(relid, InvalidOid, &cluster_options); } else table_relation_vacuum(onerel, params, vac_strategy); diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index ed127a1032..8b151bd994 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -2504,7 +2504,7 @@ do_autovacuum(void) * next table in our list. */ HOLD_INTERRUPTS(); - if (tab->at_params.options & VACOPT_VACUUM) + if (tab->at_params.options.vacuum) errcontext("automatic vacuum of table \"%s.%s.%s\"", tab->at_datname, tab->at_nspname, tab->at_relname); else @@ -2918,10 +2918,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, tab = palloc(sizeof(autovac_table)); tab->at_relid = relid; tab->at_sharedrel = classForm->relisshared; - tab->at_params.options = VACOPT_SKIPTOAST | - (dovacuum ? VACOPT_VACUUM : 0) | - (doanalyze ? VACOPT_ANALYZE : 0) | - (!wraparound ? VACOPT_SKIP_LOCKED : 0); + tab->at_params.options.skiptoast = true; + tab->at_params.options.vacuum = dovacuum; + tab->at_params.options.analyze = doanalyze; + tab->at_params.options.skip_locked = !wraparound; tab->at_params.index_cleanup = VACOPT_TERNARY_DEFAULT; tab->at_params.truncate = VACOPT_TERNARY_DEFAULT; /* As of now, we don't support parallel vacuum for autovacuum */ @@ -3249,10 +3249,10 @@ autovac_report_activity(autovac_table *tab) int len; /* Report the command and possible options */ - if (tab->at_params.options & VACOPT_VACUUM) + if (tab->at_params.options.vacuum) snprintf(activity, MAX_AUTOVAC_ACTIV_LEN, "autovacuum: VACUUM%s", - tab->at_params.options & VACOPT_ANALYZE ? " ANALYZE" : ""); + tab->at_params.options.analyze ? " ANALYZE" : ""); else snprintf(activity, MAX_AUTOVAC_ACTIV_LEN, "autovacuum: ANALYZE"); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index a42ead7d69..a6c42ee599 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -919,20 +919,20 @@ standard_ProcessUtility(PlannedStmt *pstmt, case T_ReindexStmt: { ReindexStmt *stmt = (ReindexStmt *) parsetree; - int options; + ReindexOptions options; options = ReindexParseOptions(pstate, stmt); - if ((options & REINDEXOPT_CONCURRENTLY) != 0) + if (options.concurrently) PreventInTransactionBlock(isTopLevel, "REINDEX CONCURRENTLY"); switch (stmt->kind) { case REINDEX_OBJECT_INDEX: - ReindexIndex(stmt->relation, options, isTopLevel); + ReindexIndex(stmt->relation, &options, isTopLevel); break; case REINDEX_OBJECT_TABLE: - ReindexTable(stmt->relation, options, isTopLevel); + ReindexTable(stmt->relation, &options, isTopLevel); break; case REINDEX_OBJECT_SCHEMA: case REINDEX_OBJECT_SYSTEM: @@ -948,7 +948,7 @@ standard_ProcessUtility(PlannedStmt *pstmt, (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" : (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" : "REINDEX DATABASE"); - ReindexMultipleTables(stmt->name, stmt->kind, options); + ReindexMultipleTables(stmt->name, stmt->kind, &options); break; default: elog(ERROR, "unrecognized object type: %d", diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index c041628049..d7e7e0dd24 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -30,13 +30,13 @@ typedef enum } IndexStateFlagsAction; /* options for REINDEX */ -typedef enum ReindexOption +typedef struct ReindexOptions { - REINDEXOPT_VERBOSE = 1 << 0, /* print progress info */ - REINDEXOPT_REPORT_PROGRESS = 1 << 1, /* report pgstat progress */ - REINDEXOPT_MISSING_OK = 1 << 2, /* skip missing relations */ - REINDEXOPT_CONCURRENTLY = 1 << 3 /* concurrent mode */ -} ReindexOption; + bool verbose; /* print progress info */ + bool report_progress; /* report pgstat progress */ + bool missing_ok; /* skip missing relations */ + bool concurrently; /* concurrent mode */ +} ReindexOptions; /* state info for validate_index bulkdelete callback */ typedef struct ValidateIndexState @@ -146,7 +146,7 @@ extern void index_set_state_flags(Oid indexId, IndexStateFlagsAction action); extern Oid IndexGetRelation(Oid indexId, bool missing_ok); extern void reindex_index(Oid indexId, bool skip_constraint_checks, - char relpersistence, int options); + char relpersistence, ReindexOptions *options); /* Flag bits for reindex_relation(): */ #define REINDEX_REL_PROCESS_TOAST 0x01 @@ -155,7 +155,7 @@ extern void reindex_index(Oid indexId, bool skip_constraint_checks, #define REINDEX_REL_FORCE_INDEXES_UNLOGGED 0x08 #define REINDEX_REL_FORCE_INDEXES_PERMANENT 0x10 -extern bool reindex_relation(Oid relid, int flags, int options); +extern bool reindex_relation(Oid relid, int flags, ReindexOptions *options); extern bool ReindexIsProcessingHeap(Oid heapOid); extern bool ReindexIsProcessingIndex(Oid indexOid); diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h index 7cfb37c9b2..0e661f6ce9 100644 --- a/src/include/commands/cluster.h +++ b/src/include/commands/cluster.h @@ -20,14 +20,14 @@ /* options for CLUSTER */ -typedef enum ClusterOption +typedef struct ClusterOptions { - CLUOPT_RECHECK = 1 << 0, /* recheck relation state */ - CLUOPT_VERBOSE = 1 << 1 /* print progress info */ -} ClusterOption; + bool recheck; /* recheck relation state */ + bool verbose; /* print progress info */ +} ClusterOptions; extern void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel); -extern void cluster_rel(Oid tableOid, Oid indexOid, int options); +extern void cluster_rel(Oid tableOid, Oid indexOid, ClusterOptions *options); extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck, LOCKMODE lockmode); extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal); diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 1133ae1143..33df5d5780 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -14,6 +14,7 @@ #ifndef DEFREM_H #define DEFREM_H +#include "catalog/index.h" #include "catalog/objectaddress.h" #include "nodes/params.h" #include "parser/parse_node.h" @@ -34,11 +35,11 @@ extern ObjectAddress DefineIndex(Oid relationId, bool check_not_in_use, bool skip_build, bool quiet); -extern int ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt); -extern void ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel); -extern Oid ReindexTable(RangeVar *relation, int options, bool isTopLevel); +extern ReindexOptions ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt); +extern void ReindexIndex(RangeVar *indexRelation, ReindexOptions *options, bool isTopLevel); +extern Oid ReindexTable(RangeVar *relation, ReindexOptions *options, bool isTopLevel); extern void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, - int options); + ReindexOptions *options); extern char *makeObjectName(const char *name1, const char *name2, const char *label); extern char *ChooseRelationName(const char *name1, const char *name2, diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index a4cd721400..d9e5485a1e 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -174,17 +174,17 @@ typedef struct VacAttrStats int rowstride; } VacAttrStats; -typedef enum VacuumOption +typedef struct VacuumOptions { - VACOPT_VACUUM = 1 << 0, /* do VACUUM */ - VACOPT_ANALYZE = 1 << 1, /* do ANALYZE */ - VACOPT_VERBOSE = 1 << 2, /* print progress info */ - VACOPT_FREEZE = 1 << 3, /* FREEZE option */ - VACOPT_FULL = 1 << 4, /* FULL (non-concurrent) vacuum */ - VACOPT_SKIP_LOCKED = 1 << 5, /* skip if cannot get lock */ - VACOPT_SKIPTOAST = 1 << 6, /* don't process the TOAST table, if any */ - VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7 /* don't skip any pages */ -} VacuumOption; + bool vacuum; /* do VACUUM */ + bool analyze; /* do ANALYZE */ + bool verbose; /* print progress info */ + bool freeze; /* FREEZE option */ + bool full; /* FULL (non-concurrent) vacuum */ + bool skip_locked; /* skip if cannot get lock */ + bool skiptoast; /* don't process the TOAST table, if any */ + bool disable_page_skipping; /* don't skip any pages */ +} VacuumOptions; /* * A ternary value used by vacuum parameters. @@ -202,12 +202,12 @@ typedef enum VacOptTernaryValue /* * Parameters customizing behavior of VACUUM and ANALYZE. * - * Note that at least one of VACOPT_VACUUM and VACOPT_ANALYZE must be set + * Note that at least one of VACUUM and ANALYZE must be set * in options. */ typedef struct VacuumParams { - int options; /* bitmask of VacuumOption */ + VacuumOptions options; /* struct of boolean options */ int freeze_min_age; /* min freeze age, -1 to use default */ int freeze_table_age; /* age at which to scan whole table */ int multixact_freeze_min_age; /* min multixact freeze age, -1 to @@ -275,9 +275,10 @@ extern void vacuum_set_xid_limits(Relation rel, extern void vac_update_datfrozenxid(void); extern void vacuum_delay_point(void); extern bool vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, - int options); + VacuumOptions *options); extern Relation vacuum_open_relation(Oid relid, RangeVar *relation, - int options, bool verbose, LOCKMODE lmode); + VacuumOptions *options, bool verbose, + LOCKMODE lmode); /* in commands/analyze.c */ extern void analyze_rel(Oid relid, RangeVar *relation, -- 2.17.0
>From b0228c88490a8dc7824252b3f2f15eeb1640f8fe Mon Sep 17 00:00:00 2001 From: Justin Pryzby <pryz...@telsasoft.com> Date: Tue, 15 Dec 2020 11:43:57 -0600 Subject: [PATCH 2/4] Change vacuum_open_relation/vacuum_is_relation_owner to accept booleans rather than VacuumOptions --- src/backend/commands/analyze.c | 9 ++++---- src/backend/commands/vacuum.c | 39 +++++++++++++++++----------------- src/include/commands/vacuum.h | 5 +++-- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 884bfeee21..14c436b8c0 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -124,7 +124,6 @@ analyze_rel(Oid relid, RangeVar *relation, int elevel; AcquireSampleRowsFunc acquirefunc = NULL; BlockNumber relpages = 0; - VacuumOptions newoptions; /* Select logging level */ if (params->options.verbose) @@ -149,10 +148,10 @@ analyze_rel(Oid relid, RangeVar *relation, * * Make sure to generate only logs for ANALYZE in this case. */ - newoptions = params->options; - newoptions.vacuum = false; - onerel = vacuum_open_relation(relid, relation, &newoptions, + Assert(params->options.analyze); + onerel = vacuum_open_relation(relid, relation, false, true, params->log_min_duration >= 0, + params->options.skip_locked, ShareUpdateExclusiveLock); /* leave if relation could not be opened or locked */ @@ -169,7 +168,7 @@ analyze_rel(Oid relid, RangeVar *relation, */ if (!vacuum_is_relation_owner(RelationGetRelid(onerel), onerel->rd_rel, - &newoptions)) + false, true)) { relation_close(onerel, ShareUpdateExclusiveLock); return; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 99b0345338..2652880474 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -519,11 +519,12 @@ vacuum(List *relations, VacuumParams *params, * ANALYZE. */ bool -vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, VacuumOptions *options) +vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, bool do_vacuum, + bool do_analyze) { char *relname; - Assert(options->vacuum || options->analyze); + Assert(do_vacuum || do_analyze); /* * Check permissions. @@ -542,7 +543,7 @@ vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, VacuumOptions *optio relname = NameStr(reltuple->relname); - if (options->vacuum) + if (do_vacuum) { if (reltuple->relisshared) ereport(WARNING, @@ -565,7 +566,7 @@ vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, VacuumOptions *optio return false; } - if (options->analyze) + if (do_analyze) { if (reltuple->relisshared) ereport(WARNING, @@ -593,14 +594,15 @@ vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, VacuumOptions *optio * or locked, a log is emitted if possible. */ Relation -vacuum_open_relation(Oid relid, RangeVar *relation, VacuumOptions *options, - bool verbose, LOCKMODE lmode) +vacuum_open_relation(Oid relid, RangeVar *relation, bool do_vacuum, + bool do_analyze, bool verbose, bool skip_locked, + LOCKMODE lmode) { Relation onerel; bool rel_lock = true; int elevel; - Assert(options->vacuum || options->analyze); + Assert(do_vacuum || do_analyze); /* * Open the relation and get the appropriate lock on it. @@ -611,7 +613,7 @@ vacuum_open_relation(Oid relid, RangeVar *relation, VacuumOptions *options, * If we've been asked not to wait for the relation lock, acquire it first * in non-blocking mode, before calling try_relation_open(). */ - if (!options->skip_locked) + if (!skip_locked) onerel = try_relation_open(relid, lmode); else if (ConditionalLockRelationOid(relid, lmode)) onerel = try_relation_open(relid, NoLock); @@ -651,7 +653,7 @@ vacuum_open_relation(Oid relid, RangeVar *relation, VacuumOptions *options, else return NULL; - if (options->vacuum) + if (do_vacuum) { if (!rel_lock) ereport(elevel, @@ -672,7 +674,7 @@ vacuum_open_relation(Oid relid, RangeVar *relation, VacuumOptions *options, return NULL; } - if (options->analyze) + if (do_analyze) { if (!rel_lock) ereport(elevel, @@ -775,7 +777,8 @@ expand_vacuum_rel(VacuumRelation *vrel, VacuumOptions *options) * Make a returnable VacuumRelation for this rel if user is a proper * owner. */ - if (vacuum_is_relation_owner(relid, classForm, options)) + if (vacuum_is_relation_owner(relid, classForm, options->vacuum, + options->analyze)) { oldcontext = MemoryContextSwitchTo(vac_context); vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation, @@ -862,7 +865,8 @@ get_all_vacuum_rels(VacuumOptions *options) Oid relid = classForm->oid; /* check permissions of relation */ - if (!vacuum_is_relation_owner(relid, classForm, options)) + if (!vacuum_is_relation_owner(relid, classForm, options->vacuum, + options->analyze)) continue; /* @@ -1711,7 +1715,6 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) Oid save_userid; int save_sec_context; int save_nestlevel; - VacuumOptions newoptions; Assert(params != NULL); @@ -1772,8 +1775,9 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) AccessExclusiveLock : ShareUpdateExclusiveLock; /* open the relation and get the appropriate lock on it */ - onerel = vacuum_open_relation(relid, relation, ¶ms->options, - params->log_min_duration >= 0, lmode); + Assert(params->options.vacuum); + onerel = vacuum_open_relation(relid, relation, true, false, + params->log_min_duration >= 0, params->options.skip_locked, lmode); /* leave if relation could not be opened or locked */ if (!onerel) @@ -1791,11 +1795,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) * changed in-between. Make sure to only generate logs for VACUUM in this * case. */ - newoptions = params->options; - newoptions.analyze = false; if (!vacuum_is_relation_owner(RelationGetRelid(onerel), - onerel->rd_rel, - &newoptions)) + onerel->rd_rel, true, false)) { relation_close(onerel, lmode); PopActiveSnapshot(); diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index d9e5485a1e..740fa7aaa1 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -275,9 +275,10 @@ extern void vacuum_set_xid_limits(Relation rel, extern void vac_update_datfrozenxid(void); extern void vacuum_delay_point(void); extern bool vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, - VacuumOptions *options); + bool do_vacuum, bool do_analyze); extern Relation vacuum_open_relation(Oid relid, RangeVar *relation, - VacuumOptions *options, bool verbose, + bool do_vacuum, bool do_analyze, + bool verbose, bool skip_locked, LOCKMODE lmode); /* in commands/analyze.c */ -- 2.17.0
>From cc8ed3c40ef36dc19fb30f38d445983baac40d1e Mon Sep 17 00:00:00 2001 From: Justin Pryzby <pryz...@telsasoft.com> Date: Mon, 14 Dec 2020 21:18:36 -0600 Subject: [PATCH 3/4] Move booleans directly into VacuumParams --- src/backend/access/heap/vacuumlazy.c | 8 +-- src/backend/commands/analyze.c | 12 ++-- src/backend/commands/vacuum.c | 90 ++++++++++++++-------------- src/backend/postmaster/autovacuum.c | 14 ++--- src/include/commands/vacuum.h | 26 ++++---- 5 files changed, 73 insertions(+), 77 deletions(-) diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index 6bfed2b2da..f7995b33a8 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -456,7 +456,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params, starttime = GetCurrentTimestamp(); } - if (params->options.verbose) + if (params->verbose) elevel = INFO; else elevel = DEBUG2; @@ -484,7 +484,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params, xidFullScanLimit); aggressive |= MultiXactIdPrecedesOrEquals(onerel->rd_rel->relminmxid, mxactFullScanLimit); - if (params->options.disable_page_skipping) + if (params->disable_page_skipping) aggressive = true; vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats)); @@ -902,7 +902,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats, * be replayed on any hot standby, where it can be disruptive. */ next_unskippable_block = 0; - if (!params->options.disable_page_skipping) + if (!params->disable_page_skipping) { while (next_unskippable_block < nblocks) { @@ -960,7 +960,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats, { /* Time to advance next_unskippable_block */ next_unskippable_block++; - if (!params->options.disable_page_skipping) + if (!params->disable_page_skipping) { while (next_unskippable_block < nblocks) { diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 14c436b8c0..175309a834 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -126,7 +126,7 @@ analyze_rel(Oid relid, RangeVar *relation, BlockNumber relpages = 0; /* Select logging level */ - if (params->options.verbose) + if (params->verbose) elevel = INFO; else elevel = DEBUG2; @@ -148,10 +148,10 @@ analyze_rel(Oid relid, RangeVar *relation, * * Make sure to generate only logs for ANALYZE in this case. */ - Assert(params->options.analyze); + Assert(params->do_analyze); onerel = vacuum_open_relation(relid, relation, false, true, params->log_min_duration >= 0, - params->options.skip_locked, + params->skip_locked, ShareUpdateExclusiveLock); /* leave if relation could not be opened or locked */ @@ -240,7 +240,7 @@ analyze_rel(Oid relid, RangeVar *relation, else { /* No need for a WARNING if we already complained during VACUUM */ - if (!params->options.vacuum) + if (!params->do_vacuum) ereport(WARNING, (errmsg("skipping \"%s\" --- cannot analyze non-tables or special system tables", RelationGetRelationName(onerel)))); @@ -626,7 +626,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params, * VACUUM ANALYZE, don't overwrite the accurate count already inserted by * VACUUM. */ - if (!inh && !params->options.vacuum) + if (!inh && !params->do_vacuum) { for (ind = 0; ind < nindexes; ind++) { @@ -657,7 +657,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params, (va_cols == NIL)); /* If this isn't part of VACUUM ANALYZE, let index AMs do cleanup */ - if (!params->options.vacuum) + if (!params->do_vacuum) { for (ind = 0; ind < nindexes; ind++) { diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 2652880474..5fa88de650 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -78,8 +78,8 @@ pg_atomic_uint32 *VacuumActiveNWorkers = NULL; int VacuumCostBalanceLocal = 0; /* non-export function prototypes */ -static List *expand_vacuum_rel(VacuumRelation *vrel, VacuumOptions *options); -static List *get_all_vacuum_rels(VacuumOptions *options); +static List *expand_vacuum_rel(VacuumRelation *vrel, VacuumParams *params); +static List *get_all_vacuum_rels(VacuumParams *params); static void vac_truncate_clog(TransactionId frozenXID, MultiXactId minMulti, TransactionId lastSaneFrozenXid, @@ -97,7 +97,7 @@ static VacOptTernaryValue get_vacopt_ternary_value(DefElem *def); void ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) { - VacuumParams params = {.options={false} }; + VacuumParams params = {false}; ListCell *lc; /* Set default value */ @@ -114,9 +114,9 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) /* Parse common options for VACUUM and ANALYZE */ if (strcmp(opt->defname, "verbose") == 0) - params.options.verbose = defGetBoolean(opt); + params.verbose = defGetBoolean(opt); else if (strcmp(opt->defname, "skip_locked") == 0) - params.options.skip_locked = defGetBoolean(opt); + params.skip_locked = defGetBoolean(opt); else if (!vacstmt->is_vacuumcmd) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -125,13 +125,13 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) /* Parse options available on VACUUM */ else if (strcmp(opt->defname, "analyze") == 0) - params.options.analyze = defGetBoolean(opt); + params.do_analyze = defGetBoolean(opt); else if (strcmp(opt->defname, "freeze") == 0) - params.options.freeze = defGetBoolean(opt); + params.freeze = defGetBoolean(opt); else if (strcmp(opt->defname, "full") == 0) - params.options.full = defGetBoolean(opt); + params.full = defGetBoolean(opt); else if (strcmp(opt->defname, "disable_page_skipping") == 0) - params.options.disable_page_skipping = defGetBoolean(opt); + params.disable_page_skipping = defGetBoolean(opt); else if (strcmp(opt->defname, "index_cleanup") == 0) params.index_cleanup = get_vacopt_ternary_value(opt); else if (strcmp(opt->defname, "truncate") == 0) @@ -176,17 +176,17 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) } if (vacstmt->is_vacuumcmd) - params.options.vacuum = true; + params.do_vacuum = true; else - params.options.analyze = true; + params.do_analyze = true; /* sanity checks on options */ - Assert(params.options.vacuum || params.options.analyze); - Assert(params.options.vacuum || - !(params.options.full || params.options.freeze)); - Assert(!params.options.skiptoast); + Assert(params.do_vacuum || params.do_analyze); + Assert(params.do_vacuum || + !(params.full || params.freeze)); + Assert(!params.skiptoast); - if (params.options.full && params.nworkers > 0) + if (params.full && params.nworkers > 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("VACUUM FULL cannot be performed in parallel"))); @@ -194,7 +194,7 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) /* * Make sure analyze is specified if any column lists are present. */ - if (!params.options.analyze) + if (!params.do_analyze) { ListCell *lc; @@ -213,7 +213,7 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) * All freeze ages are zero if the FREEZE option is given; otherwise pass * them as -1 which means to use the default values. */ - if (params.options.freeze) + if (params.freeze) { params.freeze_min_age = 0; params.freeze_table_age = 0; @@ -269,7 +269,7 @@ vacuum(List *relations, VacuumParams *params, Assert(params != NULL); - stmttype = params->options.vacuum ? "VACUUM" : "ANALYZE"; + stmttype = params->do_vacuum ? "VACUUM" : "ANALYZE"; /* * We cannot run VACUUM inside a user transaction block; if we were inside @@ -279,7 +279,7 @@ vacuum(List *relations, VacuumParams *params, * * ANALYZE (without VACUUM) can run either way. */ - if (params->options.vacuum) + if (params->do_vacuum) { PreventInTransactionBlock(isTopLevel, stmttype); in_outer_xact = false; @@ -301,8 +301,8 @@ vacuum(List *relations, VacuumParams *params, /* * Sanity check DISABLE_PAGE_SKIPPING option. */ - if (params->options.full && - params->options.disable_page_skipping) + if (params->full && + params->disable_page_skipping) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("VACUUM option DISABLE_PAGE_SKIPPING cannot be used with FULL"))); @@ -311,7 +311,7 @@ vacuum(List *relations, VacuumParams *params, * Send info about dead objects to the statistics collector, unless we are * in autovacuum --- autovacuum.c does this for itself. */ - if (params->options.vacuum && !IsAutoVacuumWorkerProcess()) + if (params->do_vacuum && !IsAutoVacuumWorkerProcess()) pgstat_vacuum_stat(); /* @@ -352,7 +352,7 @@ vacuum(List *relations, VacuumParams *params, List *sublist; MemoryContext old_context; - sublist = expand_vacuum_rel(vrel, ¶ms->options); + sublist = expand_vacuum_rel(vrel, params); old_context = MemoryContextSwitchTo(vac_context); newrels = list_concat(newrels, sublist); MemoryContextSwitchTo(old_context); @@ -360,7 +360,7 @@ vacuum(List *relations, VacuumParams *params, relations = newrels; } else - relations = get_all_vacuum_rels(¶ms->options); + relations = get_all_vacuum_rels(params); /* * Decide whether we need to start/commit our own transactions. @@ -376,11 +376,11 @@ vacuum(List *relations, VacuumParams *params, * transaction block, and also in an autovacuum worker, use own * transactions so we can release locks sooner. */ - if (params->options.vacuum) + if (params->do_vacuum) use_own_xacts = true; else { - Assert(params->options.analyze); + Assert(params->do_analyze); if (IsAutoVacuumWorkerProcess()) use_own_xacts = true; else if (in_outer_xact) @@ -433,13 +433,13 @@ vacuum(List *relations, VacuumParams *params, { VacuumRelation *vrel = lfirst_node(VacuumRelation, cur); - if (params->options.vacuum) + if (params->do_vacuum) { if (!vacuum_rel(vrel->oid, vrel->relation, params)) continue; } - if (params->options.analyze) + if (params->do_analyze) { /* * If using separate xacts, start one for analyze. Otherwise, @@ -493,7 +493,7 @@ vacuum(List *relations, VacuumParams *params, StartTransactionCommand(); } - if (params->options.vacuum && !IsAutoVacuumWorkerProcess()) + if (params->do_vacuum && !IsAutoVacuumWorkerProcess()) { /* * Update pg_database.datfrozenxid, and truncate pg_xact if possible. @@ -707,7 +707,7 @@ vacuum_open_relation(Oid relid, RangeVar *relation, bool do_vacuum, * are made in vac_context. */ static List * -expand_vacuum_rel(VacuumRelation *vrel, VacuumOptions *options) +expand_vacuum_rel(VacuumRelation *vrel, VacuumParams *params) { List *vacrels = NIL; MemoryContext oldcontext; @@ -739,7 +739,7 @@ expand_vacuum_rel(VacuumRelation *vrel, VacuumOptions *options) * below, as well as find_all_inheritors's expectation that the caller * holds some lock on the starting relation. */ - rvr_opts = (options->skip_locked) ? RVR_SKIP_LOCKED : 0; + rvr_opts = (params->skip_locked) ? RVR_SKIP_LOCKED : 0; relid = RangeVarGetRelidExtended(vrel->relation, AccessShareLock, rvr_opts, @@ -751,7 +751,7 @@ expand_vacuum_rel(VacuumRelation *vrel, VacuumOptions *options) */ if (!OidIsValid(relid)) { - if (options->vacuum) + if (params->do_vacuum) ereport(WARNING, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("skipping vacuum of \"%s\" --- lock not available", @@ -777,8 +777,8 @@ expand_vacuum_rel(VacuumRelation *vrel, VacuumOptions *options) * Make a returnable VacuumRelation for this rel if user is a proper * owner. */ - if (vacuum_is_relation_owner(relid, classForm, options->vacuum, - options->analyze)) + if (vacuum_is_relation_owner(relid, classForm, params->do_vacuum, + params->do_analyze)) { oldcontext = MemoryContextSwitchTo(vac_context); vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation, @@ -847,7 +847,7 @@ expand_vacuum_rel(VacuumRelation *vrel, VacuumOptions *options) * the current database. The list is built in vac_context. */ static List * -get_all_vacuum_rels(VacuumOptions *options) +get_all_vacuum_rels(VacuumParams *params) { List *vacrels = NIL; Relation pgclass; @@ -865,8 +865,8 @@ get_all_vacuum_rels(VacuumOptions *options) Oid relid = classForm->oid; /* check permissions of relation */ - if (!vacuum_is_relation_owner(relid, classForm, options->vacuum, - options->analyze)) + if (!vacuum_is_relation_owner(relid, classForm, params->do_vacuum, + params->do_analyze)) continue; /* @@ -1721,7 +1721,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) /* Begin a transaction for vacuuming this relation */ StartTransactionCommand(); - if (!params->options.full) + if (!params->full) { /* * In lazy vacuum, we can set the PROC_IN_VACUUM flag, which lets @@ -1771,13 +1771,13 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) * vacuum, but just ShareUpdateExclusiveLock for concurrent vacuum. Either * way, we can be sure that no other backend is vacuuming the same table. */ - lmode = (params->options.full) ? + lmode = (params->full) ? AccessExclusiveLock : ShareUpdateExclusiveLock; /* open the relation and get the appropriate lock on it */ - Assert(params->options.vacuum); + Assert(params->do_vacuum); onerel = vacuum_open_relation(relid, relation, true, false, - params->log_min_duration >= 0, params->options.skip_locked, lmode); + params->log_min_duration >= 0, params->skip_locked, lmode); /* leave if relation could not be opened or locked */ if (!onerel) @@ -1888,7 +1888,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) * us to process it. In VACUUM FULL, though, the toast table is * automatically rebuilt by cluster_rel so we shouldn't recurse to it. */ - if (!params->options.skiptoast && !params->options.full) + if (!params->skiptoast && !params->full) toast_relid = onerel->rd_rel->reltoastrelid; else toast_relid = InvalidOid; @@ -1907,10 +1907,10 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) /* * Do the actual work --- either FULL or "lazy" vacuum */ - if (params->options.full) + if (params->full) { ClusterOptions cluster_options = { - .verbose = params->options.verbose, + .verbose = params->verbose, /* Other members initialized to false/0/NULL */ }; diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 8b151bd994..1f8d0d1b88 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -2504,7 +2504,7 @@ do_autovacuum(void) * next table in our list. */ HOLD_INTERRUPTS(); - if (tab->at_params.options.vacuum) + if (tab->at_params.do_vacuum) errcontext("automatic vacuum of table \"%s.%s.%s\"", tab->at_datname, tab->at_nspname, tab->at_relname); else @@ -2918,10 +2918,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, tab = palloc(sizeof(autovac_table)); tab->at_relid = relid; tab->at_sharedrel = classForm->relisshared; - tab->at_params.options.skiptoast = true; - tab->at_params.options.vacuum = dovacuum; - tab->at_params.options.analyze = doanalyze; - tab->at_params.options.skip_locked = !wraparound; + tab->at_params.skiptoast = true; + tab->at_params.do_vacuum = dovacuum; + tab->at_params.do_analyze = doanalyze; + tab->at_params.skip_locked = !wraparound; tab->at_params.index_cleanup = VACOPT_TERNARY_DEFAULT; tab->at_params.truncate = VACOPT_TERNARY_DEFAULT; /* As of now, we don't support parallel vacuum for autovacuum */ @@ -3249,10 +3249,10 @@ autovac_report_activity(autovac_table *tab) int len; /* Report the command and possible options */ - if (tab->at_params.options.vacuum) + if (tab->at_params.do_vacuum) snprintf(activity, MAX_AUTOVAC_ACTIV_LEN, "autovacuum: VACUUM%s", - tab->at_params.options.analyze ? " ANALYZE" : ""); + tab->at_params.do_analyze ? " ANALYZE" : ""); else snprintf(activity, MAX_AUTOVAC_ACTIV_LEN, "autovacuum: ANALYZE"); diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 740fa7aaa1..e51f2adcd5 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -174,18 +174,6 @@ typedef struct VacAttrStats int rowstride; } VacAttrStats; -typedef struct VacuumOptions -{ - bool vacuum; /* do VACUUM */ - bool analyze; /* do ANALYZE */ - bool verbose; /* print progress info */ - bool freeze; /* FREEZE option */ - bool full; /* FULL (non-concurrent) vacuum */ - bool skip_locked; /* skip if cannot get lock */ - bool skiptoast; /* don't process the TOAST table, if any */ - bool disable_page_skipping; /* don't skip any pages */ -} VacuumOptions; - /* * A ternary value used by vacuum parameters. * @@ -202,12 +190,20 @@ typedef enum VacOptTernaryValue /* * Parameters customizing behavior of VACUUM and ANALYZE. * - * Note that at least one of VACUUM and ANALYZE must be set - * in options. + * Note that at least one of VACUUM and ANALYZE must be set. */ typedef struct VacuumParams { - VacuumOptions options; /* struct of boolean options */ + /* boolean options */ + bool do_vacuum; /* do VACUUM */ + bool do_analyze; /* do ANALYZE */ + bool verbose; /* print progress info */ + bool freeze; /* FREEZE option */ + bool full; /* FULL (non-concurrent) vacuum */ + bool skip_locked; /* skip if cannot get lock */ + bool skiptoast; /* don't process the TOAST table, if any */ + bool disable_page_skipping; /* don't skip any pages */ + int freeze_min_age; /* min freeze age, -1 to use default */ int freeze_table_age; /* age at which to scan whole table */ int multixact_freeze_min_age; /* min multixact freeze age, -1 to -- 2.17.0
>From ae50745e9339b286bf355d1af3095461f324185a Mon Sep 17 00:00:00 2001 From: Justin Pryzby <pryz...@telsasoft.com> Date: Sat, 12 Dec 2020 11:42:14 -0600 Subject: [PATCH 4/4] ExecReindex and ReindexParams --- src/backend/commands/indexcmds.c | 56 +++++++++++++++++++++++++++----- src/backend/tcop/utility.c | 40 +---------------------- src/include/commands/defrem.h | 6 +--- 3 files changed, 50 insertions(+), 52 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 13e463da90..8b688a5a65 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -86,6 +86,11 @@ static char *ChooseIndexName(const char *tabname, Oid namespaceId, bool primary, bool isconstraint); static char *ChooseIndexNameAddition(List *colnames); static List *ChooseIndexColumnNames(List *indexElems); +static void ReindexIndex(RangeVar *indexRelation, ReindexOptions *options, + bool isTopLevel); +static Oid ReindexTable(RangeVar *relation, ReindexOptions *options, bool isTopLevel); +static void ReindexMultipleTables(const char *objectName, + ReindexObjectType objectKind, ReindexOptions *options); static void RangeVarCallbackForReindexIndex(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg); static void reindex_error_callback(void *args); @@ -2452,11 +2457,14 @@ ChooseIndexColumnNames(List *indexElems) } /* - * ReindexParseOptions - * Parse list of REINDEX options, returning a bitmask of ReindexOption. + * Reindex accordinging to stmt. + * This calls the intermediate routines: ReindexIndex, ReindexTable, ReindexMultipleTables, + * which ultimately call reindex_index, reindex_relation, ReindexRelationConcurrently. + * Note that partitioned relations are handled by ReindexPartitions, except that + * ReindexRelationConcurrently handles concurrently reindexing a table. */ -ReindexOptions -ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt) +void +ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel) { ListCell *lc; ReindexOptions options = {false}; @@ -2478,14 +2486,46 @@ ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt) parser_errposition(pstate, opt->location))); } - return options; + if (options.concurrently) + PreventInTransactionBlock(isTopLevel, + "REINDEX CONCURRENTLY"); + + switch (stmt->kind) + { + case REINDEX_OBJECT_INDEX: + ReindexIndex(stmt->relation, &options, isTopLevel); + break; + case REINDEX_OBJECT_TABLE: + ReindexTable(stmt->relation, &options, isTopLevel); + break; + case REINDEX_OBJECT_SCHEMA: + case REINDEX_OBJECT_SYSTEM: + case REINDEX_OBJECT_DATABASE: + + /* + * This cannot run inside a user transaction block; if + * we were inside a transaction, then its commit- and + * start-transaction-command calls would not have the + * intended effect! + */ + PreventInTransactionBlock(isTopLevel, + (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" : + (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" : + "REINDEX DATABASE"); + ReindexMultipleTables(stmt->name, stmt->kind, &options); + break; + default: + elog(ERROR, "unrecognized object type: %d", + (int) stmt->kind); + break; + } } /* * ReindexIndex * Recreate a specific index. */ -void +static void ReindexIndex(RangeVar *indexRelation, ReindexOptions *options, bool isTopLevel) { struct ReindexIndexCallbackState state; @@ -2607,7 +2647,7 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation, * ReindexTable * Recreate all indexes of a table (and of its toast table, if any) */ -Oid +static Oid ReindexTable(RangeVar *relation, ReindexOptions *options, bool isTopLevel) { Oid heapOid; @@ -2664,7 +2704,7 @@ ReindexTable(RangeVar *relation, ReindexOptions *options, bool isTopLevel) * separate transaction, so we can release the lock on it right away. * That means this must not be called within a user transaction block! */ -void +static void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, ReindexOptions *options) { diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index a6c42ee599..3991a834b4 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -917,45 +917,7 @@ standard_ProcessUtility(PlannedStmt *pstmt, break; case T_ReindexStmt: - { - ReindexStmt *stmt = (ReindexStmt *) parsetree; - ReindexOptions options; - - options = ReindexParseOptions(pstate, stmt); - if (options.concurrently) - PreventInTransactionBlock(isTopLevel, - "REINDEX CONCURRENTLY"); - - switch (stmt->kind) - { - case REINDEX_OBJECT_INDEX: - ReindexIndex(stmt->relation, &options, isTopLevel); - break; - case REINDEX_OBJECT_TABLE: - ReindexTable(stmt->relation, &options, isTopLevel); - break; - case REINDEX_OBJECT_SCHEMA: - case REINDEX_OBJECT_SYSTEM: - case REINDEX_OBJECT_DATABASE: - - /* - * This cannot run inside a user transaction block; if - * we were inside a transaction, then its commit- and - * start-transaction-command calls would not have the - * intended effect! - */ - PreventInTransactionBlock(isTopLevel, - (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" : - (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" : - "REINDEX DATABASE"); - ReindexMultipleTables(stmt->name, stmt->kind, &options); - break; - default: - elog(ERROR, "unrecognized object type: %d", - (int) stmt->kind); - break; - } - } + ExecReindex(pstate, (ReindexStmt *)parsetree, isTopLevel); break; /* diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 33df5d5780..d4ea57e757 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -35,11 +35,7 @@ extern ObjectAddress DefineIndex(Oid relationId, bool check_not_in_use, bool skip_build, bool quiet); -extern ReindexOptions ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt); -extern void ReindexIndex(RangeVar *indexRelation, ReindexOptions *options, bool isTopLevel); -extern Oid ReindexTable(RangeVar *relation, ReindexOptions *options, bool isTopLevel); -extern void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, - ReindexOptions *options); +extern void ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel); extern char *makeObjectName(const char *name1, const char *name2, const char *label); extern char *ChooseRelationName(const char *name1, const char *name2, -- 2.17.0