diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index fed25f4929..d57055674e 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -323,8 +323,6 @@ heap_vacuum_rel(Relation rel, VacuumParams *params, minmulti_updated; BlockNumber orig_rel_pages; char **indnames = NULL; - TransactionId xidFullScanLimit; - MultiXactId mxactFullScanLimit; BlockNumber new_rel_pages; BlockNumber new_rel_allvisible; double new_live_tuples; @@ -352,24 +350,24 @@ heap_vacuum_rel(Relation rel, VacuumParams *params, pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM, 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 - * than or equal to the requested Xid full-table scan limit; or if the - * table's minimum MultiXactId is older than or equal to the requested - * mxid full-table scan limit; or if DISABLE_PAGE_SKIPPING was specified. + * Get OldestXmin cutoff, which is used to determine which deleted tuples + * are considered DEAD, not just RECENTLY_DEAD. Also get related cutoffs + * used to determine which XIDs/MultiXactIds will be frozen. + * + * 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, - xidFullScanLimit); - aggressive |= MultiXactIdPrecedesOrEquals(rel->rd_rel->relminmxid, - mxactFullScanLimit); + aggressive = 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, + &MultiXactCutoff); + skipwithvm = true; if (params->options & VACOPT_DISABLE_PAGE_SKIPPING) { diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 2e8efe4f8f..02a7e94bf9 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -857,8 +857,7 @@ copy_table_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose, * not to be aggressive about this. */ vacuum_set_xid_limits(OldHeap, 0, 0, 0, 0, - &OldestXmin, &FreezeXid, NULL, &MultiXactCutoff, - NULL); + &OldestXmin, &FreezeXid, &MultiXactCutoff); /* * FreezeXid will become the table's new relfrozenxid, and that mustn't go diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 37413dd43e..b6767a5ff8 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -943,24 +943,18 @@ get_all_vacuum_rels(int options) * Input parameters are the target relation, applicable freeze age settings. * * The output parameters are: - * - oldestXmin is the cutoff value used to distinguish whether tuples are - * DEAD or RECENTLY_DEAD (see HeapTupleSatisfiesVacuum). + * - oldestXmin is the Xid below which tuples deleted by any xact (that + * committed) should be considered DEAD, not just RECENTLY_DEAD. * - freezeLimit is the Xid below which all Xids are replaced by * FrozenTransactionId during vacuum. - * - xidFullScanLimit (computed from freeze_table_age parameter) - * represents a minimum Xid value; a table whose relfrozenxid is older than - * 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. + * - multiXactCutoff is the value below which all MultiXactIds are removed + * from Xmax. * - * xidFullScanLimit and mxactFullScanLimit can be passed as NULL if caller is - * not interested. + * Return value indicates if vacuumlazy.c caller should make its VACUUM + * operation aggressive. An aggressive VACUUM must advance relfrozenxid up to + * FreezeLimit, and relminmxid up to multiXactCutoff. */ -void +bool vacuum_set_xid_limits(Relation rel, int freeze_min_age, int freeze_table_age, @@ -968,9 +962,7 @@ vacuum_set_xid_limits(Relation rel, int multixact_freeze_table_age, TransactionId *oldestXmin, TransactionId *freezeLimit, - TransactionId *xidFullScanLimit, - MultiXactId *multiXactCutoff, - MultiXactId *mxactFullScanLimit) + MultiXactId *multiXactCutoff) { int freezemin; int mxid_freezemin; @@ -980,6 +972,7 @@ vacuum_set_xid_limits(Relation rel, MultiXactId oldestMxact; MultiXactId mxactLimit; MultiXactId safeMxactLimit; + int freezetable; /* * We can always ignore processes running lazy vacuum. This is because we @@ -1097,64 +1090,60 @@ vacuum_set_xid_limits(Relation rel, *multiXactCutoff = mxactLimit; - if (xidFullScanLimit != NULL) - { - int freezetable; + /* + * Done setting output parameters; just need to figure out if caller needs + * 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, - * 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); + /* + * 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 XID limit causing a full-table vacuum, being careful not to - * generate a "permanent" XID. - */ - limit = ReadNextTransactionId() - freezetable; - if (!TransactionIdIsNormal(limit)) - limit = FirstNormalTransactionId; + /* + * Compute MultiXact limit causing an aggressive vacuum, being careful to + * generate a valid MultiXact value + */ + mxactLimit = ReadNextMultiXactId() - freezetable; + if (mxactLimit < FirstMultiXactId) + mxactLimit = FirstMultiXactId; + if (MultiXactIdPrecedesOrEquals(rel->rd_rel->relminmxid, + mxactLimit)) + return true; - *xidFullScanLimit = limit; - - /* - * 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); - } + return false; } /* diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index e5e548d6b9..d64f6268f2 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -286,15 +286,13 @@ extern void vac_update_relstats(Relation relation, bool *frozenxid_updated, bool *minmulti_updated, 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 multixact_freeze_min_age, int multixact_freeze_table_age, TransactionId *oldestXmin, TransactionId *freezeLimit, - TransactionId *xidFullScanLimit, - MultiXactId *multiXactCutoff, - MultiXactId *mxactFullScanLimit); + MultiXactId *multiXactCutoff); extern bool vacuum_xid_failsafe_check(TransactionId relfrozenxid, MultiXactId relminmxid); extern void vac_update_datfrozenxid(void);