Consolidate VACUUM xid cutoff logic.

Push the logic for determining whether or not a VACUUM operation will be
aggressive down into vacuum_set_xid_limits().  This makes the function's
signature significantly simpler, and seems clearer overall.

Author: Peter Geoghegan <pg@bowt.ie>
Discussion: https://postgr.es/m/CAH2-WzkymFbz6D_vL+jmqSn_5q1wsFvFrE+37yLgL_Rkfd6Gzg@mail.gmail.com
This commit is contained in:
Peter Geoghegan 2022-02-11 18:26:15 -08:00
parent 872770fd6c
commit efa4a9462a
4 changed files with 79 additions and 95 deletions

View File

@ -323,8 +323,6 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
minmulti_updated; minmulti_updated;
BlockNumber orig_rel_pages; BlockNumber orig_rel_pages;
char **indnames = NULL; char **indnames = NULL;
TransactionId xidFullScanLimit;
MultiXactId mxactFullScanLimit;
BlockNumber new_rel_pages; BlockNumber new_rel_pages;
BlockNumber new_rel_allvisible; BlockNumber new_rel_allvisible;
double new_live_tuples; double new_live_tuples;
@ -352,24 +350,24 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM, pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM,
RelationGetRelid(rel)); RelationGetRelid(rel));
vacuum_set_xid_limits(rel,
params->freeze_min_age,
params->freeze_table_age,
params->multixact_freeze_min_age,
params->multixact_freeze_table_age,
&OldestXmin, &FreezeLimit, &xidFullScanLimit,
&MultiXactCutoff, &mxactFullScanLimit);
/* /*
* We request an aggressive scan if the table's frozen Xid is now older * Get OldestXmin cutoff, which is used to determine which deleted tuples
* than or equal to the requested Xid full-table scan limit; or if the * are considered DEAD, not just RECENTLY_DEAD. Also get related cutoffs
* table's minimum MultiXactId is older than or equal to the requested * used to determine which XIDs/MultiXactIds will be frozen.
* mxid full-table scan limit; or if DISABLE_PAGE_SKIPPING was specified. *
* If this is an aggressive VACUUM, then we're strictly required to freeze
* any and all XIDs from before FreezeLimit, so that we will be able to
* safely advance relfrozenxid up to FreezeLimit below (we must be able to
* advance relminmxid up to MultiXactCutoff, too).
*/ */
aggressive = TransactionIdPrecedesOrEquals(rel->rd_rel->relfrozenxid, aggressive = vacuum_set_xid_limits(rel,
xidFullScanLimit); params->freeze_min_age,
aggressive |= MultiXactIdPrecedesOrEquals(rel->rd_rel->relminmxid, params->freeze_table_age,
mxactFullScanLimit); params->multixact_freeze_min_age,
params->multixact_freeze_table_age,
&OldestXmin, &FreezeLimit,
&MultiXactCutoff);
skipwithvm = true; skipwithvm = true;
if (params->options & VACOPT_DISABLE_PAGE_SKIPPING) if (params->options & VACOPT_DISABLE_PAGE_SKIPPING)
{ {

View File

@ -857,8 +857,7 @@ copy_table_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
* not to be aggressive about this. * not to be aggressive about this.
*/ */
vacuum_set_xid_limits(OldHeap, 0, 0, 0, 0, vacuum_set_xid_limits(OldHeap, 0, 0, 0, 0,
&OldestXmin, &FreezeXid, NULL, &MultiXactCutoff, &OldestXmin, &FreezeXid, &MultiXactCutoff);
NULL);
/* /*
* 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

@ -943,24 +943,18 @@ get_all_vacuum_rels(int options)
* Input parameters are the target relation, applicable freeze age settings. * Input parameters are the target relation, applicable freeze age settings.
* *
* The output parameters are: * The output parameters are:
* - oldestXmin is the cutoff value used to distinguish whether tuples are * - oldestXmin is the Xid below which tuples deleted by any xact (that
* DEAD or RECENTLY_DEAD (see HeapTupleSatisfiesVacuum). * committed) should be considered DEAD, not just RECENTLY_DEAD.
* - freezeLimit is the Xid below which all Xids are replaced by * - freezeLimit is the Xid below which all Xids are replaced by
* FrozenTransactionId during vacuum. * FrozenTransactionId during vacuum.
* - xidFullScanLimit (computed from freeze_table_age parameter) * - multiXactCutoff is the value below which all MultiXactIds are removed
* represents a minimum Xid value; a table whose relfrozenxid is older than * from Xmax.
* this will have a full-table vacuum applied to it, to freeze tuples across
* the whole table. Vacuuming a table younger than this value can use a
* partial scan.
* - multiXactCutoff is the value below which all MultiXactIds are removed from
* Xmax.
* - mxactFullScanLimit is a value against which a table's relminmxid value is
* compared to produce a full-table vacuum, as with xidFullScanLimit.
* *
* xidFullScanLimit and mxactFullScanLimit can be passed as NULL if caller is * Return value indicates if vacuumlazy.c caller should make its VACUUM
* not interested. * operation aggressive. An aggressive VACUUM must advance relfrozenxid up to
* FreezeLimit, and relminmxid up to multiXactCutoff.
*/ */
void bool
vacuum_set_xid_limits(Relation rel, vacuum_set_xid_limits(Relation rel,
int freeze_min_age, int freeze_min_age,
int freeze_table_age, int freeze_table_age,
@ -968,9 +962,7 @@ vacuum_set_xid_limits(Relation rel,
int multixact_freeze_table_age, int multixact_freeze_table_age,
TransactionId *oldestXmin, TransactionId *oldestXmin,
TransactionId *freezeLimit, TransactionId *freezeLimit,
TransactionId *xidFullScanLimit, MultiXactId *multiXactCutoff)
MultiXactId *multiXactCutoff,
MultiXactId *mxactFullScanLimit)
{ {
int freezemin; int freezemin;
int mxid_freezemin; int mxid_freezemin;
@ -980,6 +972,7 @@ vacuum_set_xid_limits(Relation rel,
MultiXactId oldestMxact; MultiXactId oldestMxact;
MultiXactId mxactLimit; MultiXactId mxactLimit;
MultiXactId safeMxactLimit; MultiXactId safeMxactLimit;
int freezetable;
/* /*
* We can always ignore processes running lazy vacuum. This is because we * We can always ignore processes running lazy vacuum. This is because we
@ -1097,64 +1090,60 @@ vacuum_set_xid_limits(Relation rel,
*multiXactCutoff = mxactLimit; *multiXactCutoff = mxactLimit;
if (xidFullScanLimit != NULL) /*
{ * Done setting output parameters; just need to figure out if caller needs
int freezetable; * to do an aggressive VACUUM or not.
*
* Determine the table freeze age to use: as specified by the caller, or
* vacuum_freeze_table_age, but in any case not more than
* autovacuum_freeze_max_age * 0.95, so that if you have e.g nightly
* VACUUM schedule, the nightly VACUUM gets a chance to freeze tuples
* before anti-wraparound autovacuum is launched.
*/
freezetable = freeze_table_age;
if (freezetable < 0)
freezetable = vacuum_freeze_table_age;
freezetable = Min(freezetable, autovacuum_freeze_max_age * 0.95);
Assert(freezetable >= 0);
Assert(mxactFullScanLimit != NULL); /*
* Compute XID limit causing an aggressive vacuum, being careful not to
* generate a "permanent" XID
*/
limit = ReadNextTransactionId() - freezetable;
if (!TransactionIdIsNormal(limit))
limit = FirstNormalTransactionId;
if (TransactionIdPrecedesOrEquals(rel->rd_rel->relfrozenxid,
limit))
return true;
/* /*
* Determine the table freeze age to use: as specified by the caller, * Similar to the above, determine the table freeze age to use for
* or vacuum_freeze_table_age, but in any case not more than * multixacts: as specified by the caller, or
* autovacuum_freeze_max_age * 0.95, so that if you have e.g nightly * vacuum_multixact_freeze_table_age, but in any case not more than
* VACUUM schedule, the nightly VACUUM gets a chance to freeze tuples * autovacuum_multixact_freeze_table_age * 0.95, so that if you have e.g.
* before anti-wraparound autovacuum is launched. * nightly VACUUM schedule, the nightly VACUUM gets a chance to freeze
*/ * multixacts before anti-wraparound autovacuum is launched.
freezetable = freeze_table_age; */
if (freezetable < 0) freezetable = multixact_freeze_table_age;
freezetable = vacuum_freeze_table_age; if (freezetable < 0)
freezetable = Min(freezetable, autovacuum_freeze_max_age * 0.95); freezetable = vacuum_multixact_freeze_table_age;
Assert(freezetable >= 0); freezetable = Min(freezetable,
effective_multixact_freeze_max_age * 0.95);
Assert(freezetable >= 0);
/* /*
* Compute XID limit causing a full-table vacuum, being careful not to * Compute MultiXact limit causing an aggressive vacuum, being careful to
* generate a "permanent" XID. * generate a valid MultiXact value
*/ */
limit = ReadNextTransactionId() - freezetable; mxactLimit = ReadNextMultiXactId() - freezetable;
if (!TransactionIdIsNormal(limit)) if (mxactLimit < FirstMultiXactId)
limit = FirstNormalTransactionId; mxactLimit = FirstMultiXactId;
if (MultiXactIdPrecedesOrEquals(rel->rd_rel->relminmxid,
mxactLimit))
return true;
*xidFullScanLimit = limit; return false;
/*
* Similar to the above, determine the table freeze age to use for
* multixacts: as specified by the caller, or
* vacuum_multixact_freeze_table_age, but in any case not more than
* autovacuum_multixact_freeze_table_age * 0.95, so that if you have
* e.g. nightly VACUUM schedule, the nightly VACUUM gets a chance to
* freeze multixacts before anti-wraparound autovacuum is launched.
*/
freezetable = multixact_freeze_table_age;
if (freezetable < 0)
freezetable = vacuum_multixact_freeze_table_age;
freezetable = Min(freezetable,
effective_multixact_freeze_max_age * 0.95);
Assert(freezetable >= 0);
/*
* Compute MultiXact limit causing a full-table vacuum, being careful
* to generate a valid MultiXact value.
*/
mxactLimit = ReadNextMultiXactId() - freezetable;
if (mxactLimit < FirstMultiXactId)
mxactLimit = FirstMultiXactId;
*mxactFullScanLimit = mxactLimit;
}
else
{
Assert(mxactFullScanLimit == NULL);
}
} }
/* /*

View File

@ -286,15 +286,13 @@ 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 void vacuum_set_xid_limits(Relation rel, extern bool vacuum_set_xid_limits(Relation rel,
int freeze_min_age, int freeze_table_age, int freeze_min_age, int freeze_table_age,
int multixact_freeze_min_age, int multixact_freeze_min_age,
int multixact_freeze_table_age, int multixact_freeze_table_age,
TransactionId *oldestXmin, TransactionId *oldestXmin,
TransactionId *freezeLimit, TransactionId *freezeLimit,
TransactionId *xidFullScanLimit, MultiXactId *multiXactCutoff);
MultiXactId *multiXactCutoff,
MultiXactId *mxactFullScanLimit);
extern bool vacuum_xid_failsafe_check(TransactionId relfrozenxid, extern bool vacuum_xid_failsafe_check(TransactionId relfrozenxid,
MultiXactId relminmxid); MultiXactId relminmxid);
extern void vac_update_datfrozenxid(void); extern void vac_update_datfrozenxid(void);