mirror of
https://github.com/postgres/postgres.git
synced 2025-08-28 18:48:04 +03:00
Set cutoff xmin more aggressively when vacuuming a temporary table.
Since other sessions aren't allowed to look into a temporary table of our own session, we do not need to worry about the global xmin horizon when setting the vacuum XID cutoff. Indeed, if we're not inside a transaction block, we may set oldestXmin to be the next XID, because there cannot be any in-doubt tuples in a temp table, nor any tuples that are dead but still visible to some snapshot of our transaction. (VACUUM, of course, is never inside a transaction block; but we need to test that because CLUSTER shares the same code.) This approach allows us to always clean out a temp table completely during VACUUM, independently of concurrent activity. Aside from being useful in its own right, that simplifies building reproducible test cases. Discussion: https://postgr.es/m/3490536.1598629609@sss.pgh.pa.us
This commit is contained in:
@@ -907,6 +907,9 @@ get_all_vacuum_rels(int options)
|
||||
/*
|
||||
* vacuum_set_xid_limits() -- compute oldestXmin and freeze cutoff points
|
||||
*
|
||||
* Input parameters are the target relation, applicable freeze age settings,
|
||||
* and isTopLevel which should be passed down from ProcessUtility.
|
||||
*
|
||||
* The output parameters are:
|
||||
* - oldestXmin is the cutoff value used to distinguish whether tuples are
|
||||
* DEAD or RECENTLY_DEAD (see HeapTupleSatisfiesVacuum).
|
||||
@@ -931,6 +934,7 @@ vacuum_set_xid_limits(Relation rel,
|
||||
int freeze_table_age,
|
||||
int multixact_freeze_min_age,
|
||||
int multixact_freeze_table_age,
|
||||
bool isTopLevel,
|
||||
TransactionId *oldestXmin,
|
||||
TransactionId *freezeLimit,
|
||||
TransactionId *xidFullScanLimit,
|
||||
@@ -946,32 +950,53 @@ vacuum_set_xid_limits(Relation rel,
|
||||
MultiXactId mxactLimit;
|
||||
MultiXactId safeMxactLimit;
|
||||
|
||||
/*
|
||||
* We can always ignore processes running lazy vacuum. This is because we
|
||||
* use these values only for deciding which tuples we must keep in the
|
||||
* tables. Since lazy vacuum doesn't write its XID anywhere (usually no
|
||||
* XID assigned), it's safe to ignore it. In theory it could be
|
||||
* problematic to ignore lazy vacuums in a full vacuum, but keep in mind
|
||||
* that only one vacuum process can be working on a particular table at
|
||||
* any time, and that each vacuum is always an independent transaction.
|
||||
*/
|
||||
*oldestXmin = GetOldestNonRemovableTransactionId(rel);
|
||||
|
||||
if (OldSnapshotThresholdActive())
|
||||
if (RELATION_IS_LOCAL(rel) && !IsInTransactionBlock(isTopLevel))
|
||||
{
|
||||
TransactionId limit_xmin;
|
||||
TimestampTz limit_ts;
|
||||
/*
|
||||
* If we are processing a temp relation (which by prior checks must be
|
||||
* one belonging to our session), and we are not inside any
|
||||
* transaction block, then there can be no tuples in the rel that are
|
||||
* still in-doubt, nor can there be any that are dead but possibly
|
||||
* still interesting to some snapshot our session holds. We don't
|
||||
* need to care whether other sessions could see such tuples, either.
|
||||
* So we can aggressively set the cutoff xmin to be the nextXid.
|
||||
*/
|
||||
*oldestXmin = ReadNewTransactionId();
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Otherwise, calculate the cutoff xmin normally.
|
||||
*
|
||||
* We can always ignore processes running lazy vacuum. This is
|
||||
* because we use these values only for deciding which tuples we must
|
||||
* keep in the tables. Since lazy vacuum doesn't write its XID
|
||||
* anywhere (usually no XID assigned), it's safe to ignore it. In
|
||||
* theory it could be problematic to ignore lazy vacuums in a full
|
||||
* vacuum, but keep in mind that only one vacuum process can be
|
||||
* working on a particular table at any time, and that each vacuum is
|
||||
* always an independent transaction.
|
||||
*/
|
||||
*oldestXmin = GetOldestNonRemovableTransactionId(rel);
|
||||
|
||||
if (TransactionIdLimitedForOldSnapshots(*oldestXmin, rel, &limit_xmin, &limit_ts))
|
||||
if (OldSnapshotThresholdActive())
|
||||
{
|
||||
/*
|
||||
* TODO: We should only set the threshold if we are pruning on the
|
||||
* basis of the increased limits. Not as crucial here as it is for
|
||||
* opportunistic pruning (which often happens at a much higher
|
||||
* frequency), but would still be a significant improvement.
|
||||
*/
|
||||
SetOldSnapshotThresholdTimestamp(limit_ts, limit_xmin);
|
||||
*oldestXmin = limit_xmin;
|
||||
TransactionId limit_xmin;
|
||||
TimestampTz limit_ts;
|
||||
|
||||
if (TransactionIdLimitedForOldSnapshots(*oldestXmin, rel,
|
||||
&limit_xmin, &limit_ts))
|
||||
{
|
||||
/*
|
||||
* TODO: We should only set the threshold if we are pruning on
|
||||
* the basis of the increased limits. Not as crucial here as
|
||||
* it is for opportunistic pruning (which often happens at a
|
||||
* much higher frequency), but would still be a significant
|
||||
* improvement.
|
||||
*/
|
||||
SetOldSnapshotThresholdTimestamp(limit_ts, limit_xmin);
|
||||
*oldestXmin = limit_xmin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1905,7 +1930,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
|
||||
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, true);
|
||||
}
|
||||
else
|
||||
table_relation_vacuum(onerel, params, vac_strategy);
|
||||
|
Reference in New Issue
Block a user