diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2020-09-01 18:37:12 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2020-09-01 18:40:43 -0400 |
commit | a7212be8b9e0885ee769e8c55f99ef742cda487b (patch) | |
tree | a0cb039b58cd2557725f63a2e60daf5392df3ffe /src/backend/commands/vacuum.c | |
parent | db864c3c36035e4620afd114c783af7d777d78b0 (diff) |
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
Diffstat (limited to 'src/backend/commands/vacuum.c')
-rw-r--r-- | src/backend/commands/vacuum.c | 73 |
1 files changed, 49 insertions, 24 deletions
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 308a51d95d7..ddeec870d81 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -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)) + { + /* + * 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 { - TransactionId limit_xmin; - TimestampTz limit_ts; + /* + * 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); |