Skip to content

Commit a7212be

Browse files
committed
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
1 parent db864c3 commit a7212be

File tree

5 files changed

+70
-36
lines changed

5 files changed

+70
-36
lines changed

src/backend/access/heap/vacuumlazy.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
471471
params->freeze_table_age,
472472
params->multixact_freeze_min_age,
473473
params->multixact_freeze_table_age,
474+
true, /* we must be a top-level command */
474475
&OldestXmin, &FreezeLimit, &xidFullScanLimit,
475476
&MultiXactCutoff, &mxactFullScanLimit);
476477

src/backend/commands/cluster.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,13 @@ typedef struct
6767
} RelToCluster;
6868

6969

70-
static void rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose);
70+
static void rebuild_relation(Relation OldHeap, Oid indexOid,
71+
bool isTopLevel, bool verbose);
7172
static void copy_table_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
72-
bool verbose, bool *pSwapToastByContent,
73-
TransactionId *pFreezeXid, MultiXactId *pCutoffMulti);
73+
bool isTopLevel, bool verbose,
74+
bool *pSwapToastByContent,
75+
TransactionId *pFreezeXid,
76+
MultiXactId *pCutoffMulti);
7477
static List *get_tables_to_cluster(MemoryContext cluster_context);
7578

7679

@@ -170,7 +173,7 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
170173
table_close(rel, NoLock);
171174

172175
/* Do the job. */
173-
cluster_rel(tableOid, indexOid, stmt->options);
176+
cluster_rel(tableOid, indexOid, stmt->options, isTopLevel);
174177
}
175178
else
176179
{
@@ -219,7 +222,8 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
219222
PushActiveSnapshot(GetTransactionSnapshot());
220223
/* Do the job. */
221224
cluster_rel(rvtc->tableOid, rvtc->indexOid,
222-
stmt->options | CLUOPT_RECHECK);
225+
stmt->options | CLUOPT_RECHECK,
226+
isTopLevel);
223227
PopActiveSnapshot();
224228
CommitTransactionCommand();
225229
}
@@ -250,7 +254,7 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
250254
* and error messages should refer to the operation as VACUUM not CLUSTER.
251255
*/
252256
void
253-
cluster_rel(Oid tableOid, Oid indexOid, int options)
257+
cluster_rel(Oid tableOid, Oid indexOid, int options, bool isTopLevel)
254258
{
255259
Relation OldHeap;
256260
bool verbose = ((options & CLUOPT_VERBOSE) != 0);
@@ -400,7 +404,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
400404
TransferPredicateLocksToHeapRelation(OldHeap);
401405

402406
/* rebuild_relation does all the dirty work */
403-
rebuild_relation(OldHeap, indexOid, verbose);
407+
rebuild_relation(OldHeap, indexOid, isTopLevel, verbose);
404408

405409
/* NB: rebuild_relation does table_close() on OldHeap */
406410

@@ -545,11 +549,12 @@ mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
545549
*
546550
* OldHeap: table to rebuild --- must be opened and exclusive-locked!
547551
* indexOid: index to cluster by, or InvalidOid to rewrite in physical order.
552+
* isTopLevel: should be passed down from ProcessUtility.
548553
*
549554
* NB: this routine closes OldHeap at the right time; caller should not.
550555
*/
551556
static void
552-
rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose)
557+
rebuild_relation(Relation OldHeap, Oid indexOid, bool isTopLevel, bool verbose)
553558
{
554559
Oid tableOid = RelationGetRelid(OldHeap);
555560
Oid tableSpace = OldHeap->rd_rel->reltablespace;
@@ -577,7 +582,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose)
577582
AccessExclusiveLock);
578583

579584
/* Copy the heap data into the new table in the desired order */
580-
copy_table_data(OIDNewHeap, tableOid, indexOid, verbose,
585+
copy_table_data(OIDNewHeap, tableOid, indexOid, isTopLevel, verbose,
581586
&swap_toast_by_content, &frozenXid, &cutoffMulti);
582587

583588
/*
@@ -728,7 +733,8 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, char relpersistence,
728733
* *pCutoffMulti receives the MultiXactId used as a cutoff point.
729734
*/
730735
static void
731-
copy_table_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
736+
copy_table_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
737+
bool isTopLevel, bool verbose,
732738
bool *pSwapToastByContent, TransactionId *pFreezeXid,
733739
MultiXactId *pCutoffMulti)
734740
{
@@ -826,7 +832,7 @@ copy_table_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
826832
* Since we're going to rewrite the whole table anyway, there's no reason
827833
* not to be aggressive about this.
828834
*/
829-
vacuum_set_xid_limits(OldHeap, 0, 0, 0, 0,
835+
vacuum_set_xid_limits(OldHeap, 0, 0, 0, 0, isTopLevel,
830836
&OldestXmin, &FreezeXid, NULL, &MultiXactCutoff,
831837
NULL);
832838

src/backend/commands/vacuum.c

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,9 @@ get_all_vacuum_rels(int options)
907907
/*
908908
* vacuum_set_xid_limits() -- compute oldestXmin and freeze cutoff points
909909
*
910+
* Input parameters are the target relation, applicable freeze age settings,
911+
* and isTopLevel which should be passed down from ProcessUtility.
912+
*
910913
* The output parameters are:
911914
* - oldestXmin is the cutoff value used to distinguish whether tuples are
912915
* DEAD or RECENTLY_DEAD (see HeapTupleSatisfiesVacuum).
@@ -931,6 +934,7 @@ vacuum_set_xid_limits(Relation rel,
931934
int freeze_table_age,
932935
int multixact_freeze_min_age,
933936
int multixact_freeze_table_age,
937+
bool isTopLevel,
934938
TransactionId *oldestXmin,
935939
TransactionId *freezeLimit,
936940
TransactionId *xidFullScanLimit,
@@ -946,32 +950,53 @@ vacuum_set_xid_limits(Relation rel,
946950
MultiXactId mxactLimit;
947951
MultiXactId safeMxactLimit;
948952

949-
/*
950-
* We can always ignore processes running lazy vacuum. This is because we
951-
* use these values only for deciding which tuples we must keep in the
952-
* tables. Since lazy vacuum doesn't write its XID anywhere (usually no
953-
* XID assigned), it's safe to ignore it. In theory it could be
954-
* problematic to ignore lazy vacuums in a full vacuum, but keep in mind
955-
* that only one vacuum process can be working on a particular table at
956-
* any time, and that each vacuum is always an independent transaction.
957-
*/
958-
*oldestXmin = GetOldestNonRemovableTransactionId(rel);
959-
960-
if (OldSnapshotThresholdActive())
953+
if (RELATION_IS_LOCAL(rel) && !IsInTransactionBlock(isTopLevel))
954+
{
955+
/*
956+
* If we are processing a temp relation (which by prior checks must be
957+
* one belonging to our session), and we are not inside any
958+
* transaction block, then there can be no tuples in the rel that are
959+
* still in-doubt, nor can there be any that are dead but possibly
960+
* still interesting to some snapshot our session holds. We don't
961+
* need to care whether other sessions could see such tuples, either.
962+
* So we can aggressively set the cutoff xmin to be the nextXid.
963+
*/
964+
*oldestXmin = ReadNewTransactionId();
965+
}
966+
else
961967
{
962-
TransactionId limit_xmin;
963-
TimestampTz limit_ts;
968+
/*
969+
* Otherwise, calculate the cutoff xmin normally.
970+
*
971+
* We can always ignore processes running lazy vacuum. This is
972+
* because we use these values only for deciding which tuples we must
973+
* keep in the tables. Since lazy vacuum doesn't write its XID
974+
* anywhere (usually no XID assigned), it's safe to ignore it. In
975+
* theory it could be problematic to ignore lazy vacuums in a full
976+
* vacuum, but keep in mind that only one vacuum process can be
977+
* working on a particular table at any time, and that each vacuum is
978+
* always an independent transaction.
979+
*/
980+
*oldestXmin = GetOldestNonRemovableTransactionId(rel);
964981

965-
if (TransactionIdLimitedForOldSnapshots(*oldestXmin, rel, &limit_xmin, &limit_ts))
982+
if (OldSnapshotThresholdActive())
966983
{
967-
/*
968-
* TODO: We should only set the threshold if we are pruning on the
969-
* basis of the increased limits. Not as crucial here as it is for
970-
* opportunistic pruning (which often happens at a much higher
971-
* frequency), but would still be a significant improvement.
972-
*/
973-
SetOldSnapshotThresholdTimestamp(limit_ts, limit_xmin);
974-
*oldestXmin = limit_xmin;
984+
TransactionId limit_xmin;
985+
TimestampTz limit_ts;
986+
987+
if (TransactionIdLimitedForOldSnapshots(*oldestXmin, rel,
988+
&limit_xmin, &limit_ts))
989+
{
990+
/*
991+
* TODO: We should only set the threshold if we are pruning on
992+
* the basis of the increased limits. Not as crucial here as
993+
* it is for opportunistic pruning (which often happens at a
994+
* much higher frequency), but would still be a significant
995+
* improvement.
996+
*/
997+
SetOldSnapshotThresholdTimestamp(limit_ts, limit_xmin);
998+
*oldestXmin = limit_xmin;
999+
}
9751000
}
9761001
}
9771002

@@ -1905,7 +1930,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
19051930
cluster_options |= CLUOPT_VERBOSE;
19061931

19071932
/* VACUUM FULL is now a variant of CLUSTER; see cluster.c */
1908-
cluster_rel(relid, InvalidOid, cluster_options);
1933+
cluster_rel(relid, InvalidOid, cluster_options, true);
19091934
}
19101935
else
19111936
table_relation_vacuum(onerel, params, vac_strategy);

src/include/commands/cluster.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919

2020

2121
extern void cluster(ClusterStmt *stmt, bool isTopLevel);
22-
extern void cluster_rel(Oid tableOid, Oid indexOid, int options);
22+
extern void cluster_rel(Oid tableOid, Oid indexOid, int options,
23+
bool isTopLevel);
2324
extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
2425
bool recheck, LOCKMODE lockmode);
2526
extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);

src/include/commands/vacuum.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ extern void vacuum_set_xid_limits(Relation rel,
267267
int freeze_min_age, int freeze_table_age,
268268
int multixact_freeze_min_age,
269269
int multixact_freeze_table_age,
270+
bool isTopLevel,
270271
TransactionId *oldestXmin,
271272
TransactionId *freezeLimit,
272273
TransactionId *xidFullScanLimit,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy