summaryrefslogtreecommitdiff
path: root/src/backend/commands/vacuum.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2020-09-01 18:37:12 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2020-09-01 18:40:43 -0400
commita7212be8b9e0885ee769e8c55f99ef742cda487b (patch)
treea0cb039b58cd2557725f63a2e60daf5392df3ffe /src/backend/commands/vacuum.c
parentdb864c3c36035e4620afd114c783af7d777d78b0 (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.c73
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);