1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Rationalize handling of VacuumParams

This commit refactors the vacuum routines that rely on VacuumParams,
adding const markers where necessary to force a new policy in the code.
This structure should not use a pointer as it may be used across
multiple relations, and its contents should never be updated.
vacuum_rel() stands as an exception as it touches the "index_cleanup"
and "truncate" options.

VacuumParams has been introduced in 0d83138974, and 661643deda has
fixed a bug impacting VACUUM operating on multiple relations.  The
changes done in tableam.h break ABI compatibility, so this commit can
only happen on HEAD.

Author: Shihao Zhong <zhong950419@gmail.com>
Co-authored-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Junwang Zhao <zhjwpku@gmail.com>
Discussion: https://postgr.es/m/CAGRkXqTo+aK=GTy5pSc-9cy8H2F2TJvcrZ-zXEiNJj93np1UUw@mail.gmail.com
This commit is contained in:
Michael Paquier
2025-06-30 15:42:50 +09:00
parent 5ba00e175a
commit 2252fcd427
8 changed files with 98 additions and 110 deletions

View File

@ -423,7 +423,7 @@ typedef struct LVSavedErrInfo
/* non-export function prototypes */ /* non-export function prototypes */
static void lazy_scan_heap(LVRelState *vacrel); static void lazy_scan_heap(LVRelState *vacrel);
static void heap_vacuum_eager_scan_setup(LVRelState *vacrel, static void heap_vacuum_eager_scan_setup(LVRelState *vacrel,
VacuumParams *params); const VacuumParams params);
static BlockNumber heap_vac_scan_next_block(ReadStream *stream, static BlockNumber heap_vac_scan_next_block(ReadStream *stream,
void *callback_private_data, void *callback_private_data,
void *per_buffer_data); void *per_buffer_data);
@ -485,7 +485,7 @@ static void restore_vacuum_error_info(LVRelState *vacrel,
* vacuum options or for relfrozenxid/relminmxid advancement. * vacuum options or for relfrozenxid/relminmxid advancement.
*/ */
static void static void
heap_vacuum_eager_scan_setup(LVRelState *vacrel, VacuumParams *params) heap_vacuum_eager_scan_setup(LVRelState *vacrel, const VacuumParams params)
{ {
uint32 randseed; uint32 randseed;
BlockNumber allvisible; BlockNumber allvisible;
@ -504,7 +504,7 @@ heap_vacuum_eager_scan_setup(LVRelState *vacrel, VacuumParams *params)
vacrel->eager_scan_remaining_successes = 0; vacrel->eager_scan_remaining_successes = 0;
/* If eager scanning is explicitly disabled, just return. */ /* If eager scanning is explicitly disabled, just return. */
if (params->max_eager_freeze_failure_rate == 0) if (params.max_eager_freeze_failure_rate == 0)
return; return;
/* /*
@ -581,11 +581,11 @@ heap_vacuum_eager_scan_setup(LVRelState *vacrel, VacuumParams *params)
vacrel->next_eager_scan_region_start = randseed % EAGER_SCAN_REGION_SIZE; vacrel->next_eager_scan_region_start = randseed % EAGER_SCAN_REGION_SIZE;
Assert(params->max_eager_freeze_failure_rate > 0 && Assert(params.max_eager_freeze_failure_rate > 0 &&
params->max_eager_freeze_failure_rate <= 1); params.max_eager_freeze_failure_rate <= 1);
vacrel->eager_scan_max_fails_per_region = vacrel->eager_scan_max_fails_per_region =
params->max_eager_freeze_failure_rate * params.max_eager_freeze_failure_rate *
EAGER_SCAN_REGION_SIZE; EAGER_SCAN_REGION_SIZE;
/* /*
@ -612,7 +612,7 @@ heap_vacuum_eager_scan_setup(LVRelState *vacrel, VacuumParams *params)
* and locked the relation. * and locked the relation.
*/ */
void void
heap_vacuum_rel(Relation rel, VacuumParams *params, heap_vacuum_rel(Relation rel, const VacuumParams params,
BufferAccessStrategy bstrategy) BufferAccessStrategy bstrategy)
{ {
LVRelState *vacrel; LVRelState *vacrel;
@ -634,9 +634,9 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
ErrorContextCallback errcallback; ErrorContextCallback errcallback;
char **indnames = NULL; char **indnames = NULL;
verbose = (params->options & VACOPT_VERBOSE) != 0; verbose = (params.options & VACOPT_VERBOSE) != 0;
instrument = (verbose || (AmAutoVacuumWorkerProcess() && instrument = (verbose || (AmAutoVacuumWorkerProcess() &&
params->log_min_duration >= 0)); params.log_min_duration >= 0));
if (instrument) if (instrument)
{ {
pg_rusage_init(&ru0); pg_rusage_init(&ru0);
@ -699,9 +699,9 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
* The truncate param allows user to avoid attempting relation truncation, * The truncate param allows user to avoid attempting relation truncation,
* though it can't force truncation to happen. * though it can't force truncation to happen.
*/ */
Assert(params->index_cleanup != VACOPTVALUE_UNSPECIFIED); Assert(params.index_cleanup != VACOPTVALUE_UNSPECIFIED);
Assert(params->truncate != VACOPTVALUE_UNSPECIFIED && Assert(params.truncate != VACOPTVALUE_UNSPECIFIED &&
params->truncate != VACOPTVALUE_AUTO); params.truncate != VACOPTVALUE_AUTO);
/* /*
* While VacuumFailSafeActive is reset to false before calling this, we * While VacuumFailSafeActive is reset to false before calling this, we
@ -711,14 +711,14 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
vacrel->consider_bypass_optimization = true; vacrel->consider_bypass_optimization = true;
vacrel->do_index_vacuuming = true; vacrel->do_index_vacuuming = true;
vacrel->do_index_cleanup = true; vacrel->do_index_cleanup = true;
vacrel->do_rel_truncate = (params->truncate != VACOPTVALUE_DISABLED); vacrel->do_rel_truncate = (params.truncate != VACOPTVALUE_DISABLED);
if (params->index_cleanup == VACOPTVALUE_DISABLED) if (params.index_cleanup == VACOPTVALUE_DISABLED)
{ {
/* Force disable index vacuuming up-front */ /* Force disable index vacuuming up-front */
vacrel->do_index_vacuuming = false; vacrel->do_index_vacuuming = false;
vacrel->do_index_cleanup = false; vacrel->do_index_cleanup = false;
} }
else if (params->index_cleanup == VACOPTVALUE_ENABLED) else if (params.index_cleanup == VACOPTVALUE_ENABLED)
{ {
/* Force index vacuuming. Note that failsafe can still bypass. */ /* Force index vacuuming. Note that failsafe can still bypass. */
vacrel->consider_bypass_optimization = false; vacrel->consider_bypass_optimization = false;
@ -726,7 +726,7 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
else else
{ {
/* Default/auto, make all decisions dynamically */ /* Default/auto, make all decisions dynamically */
Assert(params->index_cleanup == VACOPTVALUE_AUTO); Assert(params.index_cleanup == VACOPTVALUE_AUTO);
} }
/* Initialize page counters explicitly (be tidy) */ /* Initialize page counters explicitly (be tidy) */
@ -789,7 +789,7 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
*/ */
vacrel->skippedallvis = false; vacrel->skippedallvis = false;
skipwithvm = true; skipwithvm = true;
if (params->options & VACOPT_DISABLE_PAGE_SKIPPING) if (params.options & VACOPT_DISABLE_PAGE_SKIPPING)
{ {
/* /*
* Force aggressive mode, and disable skipping blocks using the * Force aggressive mode, and disable skipping blocks using the
@ -830,7 +830,7 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
* is already dangerously old.) * is already dangerously old.)
*/ */
lazy_check_wraparound_failsafe(vacrel); lazy_check_wraparound_failsafe(vacrel);
dead_items_alloc(vacrel, params->nworkers); dead_items_alloc(vacrel, params.nworkers);
/* /*
* Call lazy_scan_heap to perform all required heap pruning, index * Call lazy_scan_heap to perform all required heap pruning, index
@ -947,9 +947,9 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
{ {
TimestampTz endtime = GetCurrentTimestamp(); TimestampTz endtime = GetCurrentTimestamp();
if (verbose || params->log_min_duration == 0 || if (verbose || params.log_min_duration == 0 ||
TimestampDifferenceExceeds(starttime, endtime, TimestampDifferenceExceeds(starttime, endtime,
params->log_min_duration)) params.log_min_duration))
{ {
long secs_dur; long secs_dur;
int usecs_dur; int usecs_dur;
@ -984,10 +984,10 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
* Aggressiveness already reported earlier, in dedicated * Aggressiveness already reported earlier, in dedicated
* VACUUM VERBOSE ereport * VACUUM VERBOSE ereport
*/ */
Assert(!params->is_wraparound); Assert(!params.is_wraparound);
msgfmt = _("finished vacuuming \"%s.%s.%s\": index scans: %d\n"); msgfmt = _("finished vacuuming \"%s.%s.%s\": index scans: %d\n");
} }
else if (params->is_wraparound) else if (params.is_wraparound)
{ {
/* /*
* While it's possible for a VACUUM to be both is_wraparound * While it's possible for a VACUUM to be both is_wraparound

View File

@ -76,7 +76,7 @@ static BufferAccessStrategy vac_strategy;
static void do_analyze_rel(Relation onerel, static void do_analyze_rel(Relation onerel,
VacuumParams *params, List *va_cols, const VacuumParams params, List *va_cols,
AcquireSampleRowsFunc acquirefunc, BlockNumber relpages, AcquireSampleRowsFunc acquirefunc, BlockNumber relpages,
bool inh, bool in_outer_xact, int elevel); bool inh, bool in_outer_xact, int elevel);
static void compute_index_stats(Relation onerel, double totalrows, static void compute_index_stats(Relation onerel, double totalrows,
@ -107,7 +107,7 @@ static Datum ind_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull);
*/ */
void void
analyze_rel(Oid relid, RangeVar *relation, analyze_rel(Oid relid, RangeVar *relation,
VacuumParams *params, List *va_cols, bool in_outer_xact, const VacuumParams params, List *va_cols, bool in_outer_xact,
BufferAccessStrategy bstrategy) BufferAccessStrategy bstrategy)
{ {
Relation onerel; Relation onerel;
@ -116,7 +116,7 @@ analyze_rel(Oid relid, RangeVar *relation,
BlockNumber relpages = 0; BlockNumber relpages = 0;
/* Select logging level */ /* Select logging level */
if (params->options & VACOPT_VERBOSE) if (params.options & VACOPT_VERBOSE)
elevel = INFO; elevel = INFO;
else else
elevel = DEBUG2; elevel = DEBUG2;
@ -138,8 +138,8 @@ analyze_rel(Oid relid, RangeVar *relation,
* *
* Make sure to generate only logs for ANALYZE in this case. * Make sure to generate only logs for ANALYZE in this case.
*/ */
onerel = vacuum_open_relation(relid, relation, params->options & ~(VACOPT_VACUUM), onerel = vacuum_open_relation(relid, relation, params.options & ~(VACOPT_VACUUM),
params->log_min_duration >= 0, params.log_min_duration >= 0,
ShareUpdateExclusiveLock); ShareUpdateExclusiveLock);
/* leave if relation could not be opened or locked */ /* leave if relation could not be opened or locked */
@ -155,7 +155,7 @@ analyze_rel(Oid relid, RangeVar *relation,
*/ */
if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel), if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
onerel->rd_rel, onerel->rd_rel,
params->options & ~VACOPT_VACUUM)) params.options & ~VACOPT_VACUUM))
{ {
relation_close(onerel, ShareUpdateExclusiveLock); relation_close(onerel, ShareUpdateExclusiveLock);
return; return;
@ -227,7 +227,7 @@ analyze_rel(Oid relid, RangeVar *relation,
else else
{ {
/* No need for a WARNING if we already complained during VACUUM */ /* No need for a WARNING if we already complained during VACUUM */
if (!(params->options & VACOPT_VACUUM)) if (!(params.options & VACOPT_VACUUM))
ereport(WARNING, ereport(WARNING,
(errmsg("skipping \"%s\" --- cannot analyze non-tables or special system tables", (errmsg("skipping \"%s\" --- cannot analyze non-tables or special system tables",
RelationGetRelationName(onerel)))); RelationGetRelationName(onerel))));
@ -275,7 +275,7 @@ analyze_rel(Oid relid, RangeVar *relation,
* appropriate acquirefunc for each child table. * appropriate acquirefunc for each child table.
*/ */
static void static void
do_analyze_rel(Relation onerel, VacuumParams *params, do_analyze_rel(Relation onerel, const VacuumParams params,
List *va_cols, AcquireSampleRowsFunc acquirefunc, List *va_cols, AcquireSampleRowsFunc acquirefunc,
BlockNumber relpages, bool inh, bool in_outer_xact, BlockNumber relpages, bool inh, bool in_outer_xact,
int elevel) int elevel)
@ -309,9 +309,9 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
PgStat_Counter startreadtime = 0; PgStat_Counter startreadtime = 0;
PgStat_Counter startwritetime = 0; PgStat_Counter startwritetime = 0;
verbose = (params->options & VACOPT_VERBOSE) != 0; verbose = (params.options & VACOPT_VERBOSE) != 0;
instrument = (verbose || (AmAutoVacuumWorkerProcess() && instrument = (verbose || (AmAutoVacuumWorkerProcess() &&
params->log_min_duration >= 0)); params.log_min_duration >= 0));
if (inh) if (inh)
ereport(elevel, ereport(elevel,
(errmsg("analyzing \"%s.%s\" inheritance tree", (errmsg("analyzing \"%s.%s\" inheritance tree",
@ -706,7 +706,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
* amvacuumcleanup() when called in ANALYZE-only mode. The only exception * amvacuumcleanup() when called in ANALYZE-only mode. The only exception
* among core index AMs is GIN/ginvacuumcleanup(). * among core index AMs is GIN/ginvacuumcleanup().
*/ */
if (!(params->options & VACOPT_VACUUM)) if (!(params.options & VACOPT_VACUUM))
{ {
for (ind = 0; ind < nindexes; ind++) for (ind = 0; ind < nindexes; ind++)
{ {
@ -736,9 +736,9 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
{ {
TimestampTz endtime = GetCurrentTimestamp(); TimestampTz endtime = GetCurrentTimestamp();
if (verbose || params->log_min_duration == 0 || if (verbose || params.log_min_duration == 0 ||
TimestampDifferenceExceeds(starttime, endtime, TimestampDifferenceExceeds(starttime, endtime,
params->log_min_duration)) params.log_min_duration))
{ {
long delay_in_ms; long delay_in_ms;
WalUsage walusage; WalUsage walusage;

View File

@ -917,7 +917,7 @@ copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex, bool verb
* not to be aggressive about this. * not to be aggressive about this.
*/ */
memset(&params, 0, sizeof(VacuumParams)); memset(&params, 0, sizeof(VacuumParams));
vacuum_get_cutoffs(OldHeap, &params, &cutoffs); vacuum_get_cutoffs(OldHeap, params, &cutoffs);
/* /*
* FreezeXid will become the table's new relfrozenxid, and that mustn't go * FreezeXid will become the table's new relfrozenxid, and that mustn't go

View File

@ -124,7 +124,7 @@ static void vac_truncate_clog(TransactionId frozenXID,
MultiXactId minMulti, MultiXactId minMulti,
TransactionId lastSaneFrozenXid, TransactionId lastSaneFrozenXid,
MultiXactId lastSaneMinMulti); MultiXactId lastSaneMinMulti);
static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params, static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
BufferAccessStrategy bstrategy); BufferAccessStrategy bstrategy);
static double compute_parallel_delay(void); static double compute_parallel_delay(void);
static VacOptValue get_vacoptval_from_boolean(DefElem *def); static VacOptValue get_vacoptval_from_boolean(DefElem *def);
@ -465,7 +465,7 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
} }
/* Now go through the common routine */ /* Now go through the common routine */
vacuum(vacstmt->rels, &params, bstrategy, vac_context, isTopLevel); vacuum(vacstmt->rels, params, bstrategy, vac_context, isTopLevel);
/* Finally, clean up the vacuum memory context */ /* Finally, clean up the vacuum memory context */
MemoryContextDelete(vac_context); MemoryContextDelete(vac_context);
@ -494,7 +494,7 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
* memory context that will not disappear at transaction commit. * memory context that will not disappear at transaction commit.
*/ */
void void
vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy, vacuum(List *relations, const VacuumParams params, BufferAccessStrategy bstrategy,
MemoryContext vac_context, bool isTopLevel) MemoryContext vac_context, bool isTopLevel)
{ {
static bool in_vacuum = false; static bool in_vacuum = false;
@ -503,9 +503,7 @@ vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy,
volatile bool in_outer_xact, volatile bool in_outer_xact,
use_own_xacts; use_own_xacts;
Assert(params != NULL); stmttype = (params.options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
stmttype = (params->options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
/* /*
* We cannot run VACUUM inside a user transaction block; if we were inside * We cannot run VACUUM inside a user transaction block; if we were inside
@ -515,7 +513,7 @@ vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy,
* *
* ANALYZE (without VACUUM) can run either way. * ANALYZE (without VACUUM) can run either way.
*/ */
if (params->options & VACOPT_VACUUM) if (params.options & VACOPT_VACUUM)
{ {
PreventInTransactionBlock(isTopLevel, stmttype); PreventInTransactionBlock(isTopLevel, stmttype);
in_outer_xact = false; in_outer_xact = false;
@ -538,7 +536,7 @@ vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy,
* Build list of relation(s) to process, putting any new data in * Build list of relation(s) to process, putting any new data in
* vac_context for safekeeping. * vac_context for safekeeping.
*/ */
if (params->options & VACOPT_ONLY_DATABASE_STATS) if (params.options & VACOPT_ONLY_DATABASE_STATS)
{ {
/* We don't process any tables in this case */ /* We don't process any tables in this case */
Assert(relations == NIL); Assert(relations == NIL);
@ -554,7 +552,7 @@ vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy,
List *sublist; List *sublist;
MemoryContext old_context; MemoryContext old_context;
sublist = expand_vacuum_rel(vrel, vac_context, params->options); sublist = expand_vacuum_rel(vrel, vac_context, params.options);
old_context = MemoryContextSwitchTo(vac_context); old_context = MemoryContextSwitchTo(vac_context);
newrels = list_concat(newrels, sublist); newrels = list_concat(newrels, sublist);
MemoryContextSwitchTo(old_context); MemoryContextSwitchTo(old_context);
@ -562,7 +560,7 @@ vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy,
relations = newrels; relations = newrels;
} }
else else
relations = get_all_vacuum_rels(vac_context, params->options); relations = get_all_vacuum_rels(vac_context, params.options);
/* /*
* Decide whether we need to start/commit our own transactions. * Decide whether we need to start/commit our own transactions.
@ -578,11 +576,11 @@ vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy,
* transaction block, and also in an autovacuum worker, use own * transaction block, and also in an autovacuum worker, use own
* transactions so we can release locks sooner. * transactions so we can release locks sooner.
*/ */
if (params->options & VACOPT_VACUUM) if (params.options & VACOPT_VACUUM)
use_own_xacts = true; use_own_xacts = true;
else else
{ {
Assert(params->options & VACOPT_ANALYZE); Assert(params.options & VACOPT_ANALYZE);
if (AmAutoVacuumWorkerProcess()) if (AmAutoVacuumWorkerProcess())
use_own_xacts = true; use_own_xacts = true;
else if (in_outer_xact) else if (in_outer_xact)
@ -633,21 +631,13 @@ vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy,
{ {
VacuumRelation *vrel = lfirst_node(VacuumRelation, cur); VacuumRelation *vrel = lfirst_node(VacuumRelation, cur);
if (params->options & VACOPT_VACUUM) if (params.options & VACOPT_VACUUM)
{ {
VacuumParams params_copy; if (!vacuum_rel(vrel->oid, vrel->relation, params, bstrategy))
/*
* vacuum_rel() scribbles on the parameters, so give it a copy
* to avoid affecting other relations.
*/
memcpy(&params_copy, params, sizeof(VacuumParams));
if (!vacuum_rel(vrel->oid, vrel->relation, &params_copy, bstrategy))
continue; continue;
} }
if (params->options & VACOPT_ANALYZE) if (params.options & VACOPT_ANALYZE)
{ {
/* /*
* If using separate xacts, start one for analyze. Otherwise, * If using separate xacts, start one for analyze. Otherwise,
@ -711,8 +701,8 @@ vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy,
StartTransactionCommand(); StartTransactionCommand();
} }
if ((params->options & VACOPT_VACUUM) && if ((params.options & VACOPT_VACUUM) &&
!(params->options & VACOPT_SKIP_DATABASE_STATS)) !(params.options & VACOPT_SKIP_DATABASE_STATS))
{ {
/* /*
* Update pg_database.datfrozenxid, and truncate pg_xact if possible. * Update pg_database.datfrozenxid, and truncate pg_xact if possible.
@ -1110,7 +1100,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
* minimum). * minimum).
*/ */
bool bool
vacuum_get_cutoffs(Relation rel, const VacuumParams *params, vacuum_get_cutoffs(Relation rel, const VacuumParams params,
struct VacuumCutoffs *cutoffs) struct VacuumCutoffs *cutoffs)
{ {
int freeze_min_age, int freeze_min_age,
@ -1126,10 +1116,10 @@ vacuum_get_cutoffs(Relation rel, const VacuumParams *params,
aggressiveMXIDCutoff; aggressiveMXIDCutoff;
/* Use mutable copies of freeze age parameters */ /* Use mutable copies of freeze age parameters */
freeze_min_age = params->freeze_min_age; freeze_min_age = params.freeze_min_age;
multixact_freeze_min_age = params->multixact_freeze_min_age; multixact_freeze_min_age = params.multixact_freeze_min_age;
freeze_table_age = params->freeze_table_age; freeze_table_age = params.freeze_table_age;
multixact_freeze_table_age = params->multixact_freeze_table_age; multixact_freeze_table_age = params.multixact_freeze_table_age;
/* Set pg_class fields in cutoffs */ /* Set pg_class fields in cutoffs */
cutoffs->relfrozenxid = rel->rd_rel->relfrozenxid; cutoffs->relfrozenxid = rel->rd_rel->relfrozenxid;
@ -2006,7 +1996,7 @@ vac_truncate_clog(TransactionId frozenXID,
* At entry and exit, we are not inside a transaction. * At entry and exit, we are not inside a transaction.
*/ */
static bool static bool
vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params, vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
BufferAccessStrategy bstrategy) BufferAccessStrategy bstrategy)
{ {
LOCKMODE lmode; LOCKMODE lmode;
@ -2019,18 +2009,16 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
int save_nestlevel; int save_nestlevel;
VacuumParams toast_vacuum_params; VacuumParams toast_vacuum_params;
Assert(params != NULL);
/* /*
* This function scribbles on the parameters, so make a copy early to * This function scribbles on the parameters, so make a copy early to
* avoid affecting the TOAST table (if we do end up recursing to it). * avoid affecting the TOAST table (if we do end up recursing to it).
*/ */
memcpy(&toast_vacuum_params, params, sizeof(VacuumParams)); memcpy(&toast_vacuum_params, &params, sizeof(VacuumParams));
/* Begin a transaction for vacuuming this relation */ /* Begin a transaction for vacuuming this relation */
StartTransactionCommand(); StartTransactionCommand();
if (!(params->options & VACOPT_FULL)) if (!(params.options & VACOPT_FULL))
{ {
/* /*
* In lazy vacuum, we can set the PROC_IN_VACUUM flag, which lets * In lazy vacuum, we can set the PROC_IN_VACUUM flag, which lets
@ -2056,7 +2044,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
*/ */
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
MyProc->statusFlags |= PROC_IN_VACUUM; MyProc->statusFlags |= PROC_IN_VACUUM;
if (params->is_wraparound) if (params.is_wraparound)
MyProc->statusFlags |= PROC_VACUUM_FOR_WRAPAROUND; MyProc->statusFlags |= PROC_VACUUM_FOR_WRAPAROUND;
ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags; ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags;
LWLockRelease(ProcArrayLock); LWLockRelease(ProcArrayLock);
@ -2080,12 +2068,12 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
* vacuum, but just ShareUpdateExclusiveLock for concurrent vacuum. Either * vacuum, but just ShareUpdateExclusiveLock for concurrent vacuum. Either
* way, we can be sure that no other backend is vacuuming the same table. * way, we can be sure that no other backend is vacuuming the same table.
*/ */
lmode = (params->options & VACOPT_FULL) ? lmode = (params.options & VACOPT_FULL) ?
AccessExclusiveLock : ShareUpdateExclusiveLock; AccessExclusiveLock : ShareUpdateExclusiveLock;
/* open the relation and get the appropriate lock on it */ /* open the relation and get the appropriate lock on it */
rel = vacuum_open_relation(relid, relation, params->options, rel = vacuum_open_relation(relid, relation, params.options,
params->log_min_duration >= 0, lmode); params.log_min_duration >= 0, lmode);
/* leave if relation could not be opened or locked */ /* leave if relation could not be opened or locked */
if (!rel) if (!rel)
@ -2100,8 +2088,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
* This is only safe to do because we hold a session lock on the main * This is only safe to do because we hold a session lock on the main
* relation that prevents concurrent deletion. * relation that prevents concurrent deletion.
*/ */
if (OidIsValid(params->toast_parent)) if (OidIsValid(params.toast_parent))
priv_relid = params->toast_parent; priv_relid = params.toast_parent;
else else
priv_relid = RelationGetRelid(rel); priv_relid = RelationGetRelid(rel);
@ -2114,7 +2102,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
*/ */
if (!vacuum_is_permitted_for_relation(priv_relid, if (!vacuum_is_permitted_for_relation(priv_relid,
rel->rd_rel, rel->rd_rel,
params->options & ~VACOPT_ANALYZE)) params.options & ~VACOPT_ANALYZE))
{ {
relation_close(rel, lmode); relation_close(rel, lmode);
PopActiveSnapshot(); PopActiveSnapshot();
@ -2185,7 +2173,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
* Set index_cleanup option based on index_cleanup reloption if it wasn't * Set index_cleanup option based on index_cleanup reloption if it wasn't
* specified in VACUUM command, or when running in an autovacuum worker * specified in VACUUM command, or when running in an autovacuum worker
*/ */
if (params->index_cleanup == VACOPTVALUE_UNSPECIFIED) if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED)
{ {
StdRdOptIndexCleanup vacuum_index_cleanup; StdRdOptIndexCleanup vacuum_index_cleanup;
@ -2196,23 +2184,23 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup;
if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO)
params->index_cleanup = VACOPTVALUE_AUTO; params.index_cleanup = VACOPTVALUE_AUTO;
else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON)
params->index_cleanup = VACOPTVALUE_ENABLED; params.index_cleanup = VACOPTVALUE_ENABLED;
else else
{ {
Assert(vacuum_index_cleanup == Assert(vacuum_index_cleanup ==
STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF);
params->index_cleanup = VACOPTVALUE_DISABLED; params.index_cleanup = VACOPTVALUE_DISABLED;
} }
} }
#ifdef USE_INJECTION_POINTS #ifdef USE_INJECTION_POINTS
if (params->index_cleanup == VACOPTVALUE_AUTO) if (params.index_cleanup == VACOPTVALUE_AUTO)
INJECTION_POINT("vacuum-index-cleanup-auto", NULL); INJECTION_POINT("vacuum-index-cleanup-auto", NULL);
else if (params->index_cleanup == VACOPTVALUE_DISABLED) else if (params.index_cleanup == VACOPTVALUE_DISABLED)
INJECTION_POINT("vacuum-index-cleanup-disabled", NULL); INJECTION_POINT("vacuum-index-cleanup-disabled", NULL);
else if (params->index_cleanup == VACOPTVALUE_ENABLED) else if (params.index_cleanup == VACOPTVALUE_ENABLED)
INJECTION_POINT("vacuum-index-cleanup-enabled", NULL); INJECTION_POINT("vacuum-index-cleanup-enabled", NULL);
#endif #endif
@ -2222,36 +2210,36 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
*/ */
if (rel->rd_options != NULL && if (rel->rd_options != NULL &&
((StdRdOptions *) rel->rd_options)->vacuum_max_eager_freeze_failure_rate >= 0) ((StdRdOptions *) rel->rd_options)->vacuum_max_eager_freeze_failure_rate >= 0)
params->max_eager_freeze_failure_rate = params.max_eager_freeze_failure_rate =
((StdRdOptions *) rel->rd_options)->vacuum_max_eager_freeze_failure_rate; ((StdRdOptions *) rel->rd_options)->vacuum_max_eager_freeze_failure_rate;
/* /*
* Set truncate option based on truncate reloption or GUC if it wasn't * Set truncate option based on truncate reloption or GUC if it wasn't
* specified in VACUUM command, or when running in an autovacuum worker * specified in VACUUM command, or when running in an autovacuum worker
*/ */
if (params->truncate == VACOPTVALUE_UNSPECIFIED) if (params.truncate == VACOPTVALUE_UNSPECIFIED)
{ {
StdRdOptions *opts = (StdRdOptions *) rel->rd_options; StdRdOptions *opts = (StdRdOptions *) rel->rd_options;
if (opts && opts->vacuum_truncate_set) if (opts && opts->vacuum_truncate_set)
{ {
if (opts->vacuum_truncate) if (opts->vacuum_truncate)
params->truncate = VACOPTVALUE_ENABLED; params.truncate = VACOPTVALUE_ENABLED;
else else
params->truncate = VACOPTVALUE_DISABLED; params.truncate = VACOPTVALUE_DISABLED;
} }
else if (vacuum_truncate) else if (vacuum_truncate)
params->truncate = VACOPTVALUE_ENABLED; params.truncate = VACOPTVALUE_ENABLED;
else else
params->truncate = VACOPTVALUE_DISABLED; params.truncate = VACOPTVALUE_DISABLED;
} }
#ifdef USE_INJECTION_POINTS #ifdef USE_INJECTION_POINTS
if (params->truncate == VACOPTVALUE_AUTO) if (params.truncate == VACOPTVALUE_AUTO)
INJECTION_POINT("vacuum-truncate-auto", NULL); INJECTION_POINT("vacuum-truncate-auto", NULL);
else if (params->truncate == VACOPTVALUE_DISABLED) else if (params.truncate == VACOPTVALUE_DISABLED)
INJECTION_POINT("vacuum-truncate-disabled", NULL); INJECTION_POINT("vacuum-truncate-disabled", NULL);
else if (params->truncate == VACOPTVALUE_ENABLED) else if (params.truncate == VACOPTVALUE_ENABLED)
INJECTION_POINT("vacuum-truncate-enabled", NULL); INJECTION_POINT("vacuum-truncate-enabled", NULL);
#endif #endif
@ -2261,9 +2249,9 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
* automatically rebuilt by cluster_rel so we shouldn't recurse to it, * automatically rebuilt by cluster_rel so we shouldn't recurse to it,
* unless PROCESS_MAIN is disabled. * unless PROCESS_MAIN is disabled.
*/ */
if ((params->options & VACOPT_PROCESS_TOAST) != 0 && if ((params.options & VACOPT_PROCESS_TOAST) != 0 &&
((params->options & VACOPT_FULL) == 0 || ((params.options & VACOPT_FULL) == 0 ||
(params->options & VACOPT_PROCESS_MAIN) == 0)) (params.options & VACOPT_PROCESS_MAIN) == 0))
toast_relid = rel->rd_rel->reltoastrelid; toast_relid = rel->rd_rel->reltoastrelid;
else else
toast_relid = InvalidOid; toast_relid = InvalidOid;
@ -2286,16 +2274,16 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
* table is required (e.g., PROCESS_TOAST is set), we force PROCESS_MAIN * table is required (e.g., PROCESS_TOAST is set), we force PROCESS_MAIN
* to be set when we recurse to the TOAST table. * to be set when we recurse to the TOAST table.
*/ */
if (params->options & VACOPT_PROCESS_MAIN) if (params.options & VACOPT_PROCESS_MAIN)
{ {
/* /*
* Do the actual work --- either FULL or "lazy" vacuum * Do the actual work --- either FULL or "lazy" vacuum
*/ */
if (params->options & VACOPT_FULL) if (params.options & VACOPT_FULL)
{ {
ClusterParams cluster_params = {0}; ClusterParams cluster_params = {0};
if ((params->options & VACOPT_VERBOSE) != 0) if ((params.options & VACOPT_VERBOSE) != 0)
cluster_params.options |= CLUOPT_VERBOSE; cluster_params.options |= CLUOPT_VERBOSE;
/* VACUUM FULL is now a variant of CLUSTER; see cluster.c */ /* VACUUM FULL is now a variant of CLUSTER; see cluster.c */
@ -2342,7 +2330,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
toast_vacuum_params.options |= VACOPT_PROCESS_MAIN; toast_vacuum_params.options |= VACOPT_PROCESS_MAIN;
toast_vacuum_params.toast_parent = relid; toast_vacuum_params.toast_parent = relid;
vacuum_rel(toast_relid, NULL, &toast_vacuum_params, bstrategy); vacuum_rel(toast_relid, NULL, toast_vacuum_params, bstrategy);
} }
/* /*

View File

@ -3190,7 +3190,7 @@ autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy)
rel_list = list_make1(rel); rel_list = list_make1(rel);
MemoryContextSwitchTo(old_context); MemoryContextSwitchTo(old_context);
vacuum(rel_list, &tab->at_params, bstrategy, vac_context, true); vacuum(rel_list, tab->at_params, bstrategy, vac_context, true);
MemoryContextDelete(vac_context); MemoryContextDelete(vac_context);
} }

View File

@ -21,6 +21,7 @@
#include "access/skey.h" #include "access/skey.h"
#include "access/table.h" /* for backward compatibility */ #include "access/table.h" /* for backward compatibility */
#include "access/tableam.h" #include "access/tableam.h"
#include "commands/vacuum.h"
#include "nodes/lockoptions.h" #include "nodes/lockoptions.h"
#include "nodes/primnodes.h" #include "nodes/primnodes.h"
#include "storage/bufpage.h" #include "storage/bufpage.h"
@ -396,9 +397,8 @@ extern void log_heap_prune_and_freeze(Relation relation, Buffer buffer,
OffsetNumber *unused, int nunused); OffsetNumber *unused, int nunused);
/* in heap/vacuumlazy.c */ /* in heap/vacuumlazy.c */
struct VacuumParams;
extern void heap_vacuum_rel(Relation rel, extern void heap_vacuum_rel(Relation rel,
struct VacuumParams *params, BufferAccessStrategy bstrategy); const VacuumParams params, BufferAccessStrategy bstrategy);
/* in heap/heapam_visibility.c */ /* in heap/heapam_visibility.c */
extern bool HeapTupleSatisfiesVisibility(HeapTuple htup, Snapshot snapshot, extern bool HeapTupleSatisfiesVisibility(HeapTuple htup, Snapshot snapshot,

View File

@ -20,6 +20,7 @@
#include "access/relscan.h" #include "access/relscan.h"
#include "access/sdir.h" #include "access/sdir.h"
#include "access/xact.h" #include "access/xact.h"
#include "commands/vacuum.h"
#include "executor/tuptable.h" #include "executor/tuptable.h"
#include "storage/read_stream.h" #include "storage/read_stream.h"
#include "utils/rel.h" #include "utils/rel.h"
@ -36,7 +37,6 @@ extern PGDLLIMPORT bool synchronize_seqscans;
struct BulkInsertStateData; struct BulkInsertStateData;
struct IndexInfo; struct IndexInfo;
struct SampleScanState; struct SampleScanState;
struct VacuumParams;
struct ValidateIndexState; struct ValidateIndexState;
/* /*
@ -645,7 +645,7 @@ typedef struct TableAmRoutine
* integrate with autovacuum's scheduling. * integrate with autovacuum's scheduling.
*/ */
void (*relation_vacuum) (Relation rel, void (*relation_vacuum) (Relation rel,
struct VacuumParams *params, const VacuumParams params,
BufferAccessStrategy bstrategy); BufferAccessStrategy bstrategy);
/* /*
@ -1664,7 +1664,7 @@ table_relation_copy_for_cluster(Relation OldTable, Relation NewTable,
* routine, even if (for ANALYZE) it is part of the same VACUUM command. * routine, even if (for ANALYZE) it is part of the same VACUUM command.
*/ */
static inline void static inline void
table_relation_vacuum(Relation rel, struct VacuumParams *params, table_relation_vacuum(Relation rel, const VacuumParams params,
BufferAccessStrategy bstrategy) BufferAccessStrategy bstrategy)
{ {
rel->rd_tableam->relation_vacuum(rel, params, bstrategy); rel->rd_tableam->relation_vacuum(rel, params, bstrategy);

View File

@ -336,7 +336,7 @@ extern PGDLLIMPORT int64 parallel_vacuum_worker_delay_ns;
/* in commands/vacuum.c */ /* in commands/vacuum.c */
extern void ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel); extern void ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel);
extern void vacuum(List *relations, VacuumParams *params, extern void vacuum(List *relations, const VacuumParams params,
BufferAccessStrategy bstrategy, MemoryContext vac_context, BufferAccessStrategy bstrategy, MemoryContext vac_context,
bool isTopLevel); bool isTopLevel);
extern void vac_open_indexes(Relation relation, LOCKMODE lockmode, extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
@ -357,7 +357,7 @@ extern void vac_update_relstats(Relation relation,
bool *frozenxid_updated, bool *frozenxid_updated,
bool *minmulti_updated, bool *minmulti_updated,
bool in_outer_xact); bool in_outer_xact);
extern bool vacuum_get_cutoffs(Relation rel, const VacuumParams *params, extern bool vacuum_get_cutoffs(Relation rel, const VacuumParams params,
struct VacuumCutoffs *cutoffs); struct VacuumCutoffs *cutoffs);
extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs); extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
extern void vac_update_datfrozenxid(void); extern void vac_update_datfrozenxid(void);
@ -398,7 +398,7 @@ extern void parallel_vacuum_main(dsm_segment *seg, shm_toc *toc);
/* in commands/analyze.c */ /* in commands/analyze.c */
extern void analyze_rel(Oid relid, RangeVar *relation, extern void analyze_rel(Oid relid, RangeVar *relation,
VacuumParams *params, List *va_cols, bool in_outer_xact, const VacuumParams params, List *va_cols, bool in_outer_xact,
BufferAccessStrategy bstrategy); BufferAccessStrategy bstrategy);
extern bool std_typanalyze(VacAttrStats *stats); extern bool std_typanalyze(VacAttrStats *stats);