aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndres Freund <andres@anarazel.de>2020-04-05 17:47:30 -0700
committerAndres Freund <andres@anarazel.de>2020-04-05 17:48:43 -0700
commita850063ee0bc6c2c703117395a51eb3154e907db (patch)
tree3411bd7e131a5610522523d8a404a7fbf4dee320
parent72b2b9c52e3a86ae414fc07acf6db3de0776fc13 (diff)
downloadpostgresql-a850063ee0bc6c2c703117395a51eb3154e907db.tar.gz
postgresql-a850063ee0bc6c2c703117395a51eb3154e907db.zip
Use TransactionXmin instead of RecentGlobalXmin in heap_abort_speculative().
There's a very low risk that RecentGlobalXmin could be far enough in the past to be older than relfrozenxid, or even wrapped around. Luckily the consequences of that having happened wouldn't be too bad - the page wouldn't be pruned for a while. Avoid that risk by using TransactionXmin instead. As that's announced via MyPgXact->xmin, it is protected against wrapping around (see code comments for details around relfrozenxid). Author: Andres Freund Discussion: https://postgr.es/m/20200328213023.s4eyijhdosuc4vcj@alap3.anarazel.de Backpatch: 9.5-
-rw-r--r--src/backend/access/heap/heapam.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 9554704456c..5dc7e30168a 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -5782,6 +5782,7 @@ heap_abort_speculative(Relation relation, HeapTuple tuple)
Page page;
BlockNumber block;
Buffer buffer;
+ TransactionId prune_xid;
Assert(ItemPointerIsValid(tid));
@@ -5824,13 +5825,21 @@ heap_abort_speculative(Relation relation, HeapTuple tuple)
START_CRIT_SECTION();
/*
- * The tuple will become DEAD immediately. Flag that this page
- * immediately is a candidate for pruning by setting xmin to
- * RecentGlobalXmin. That's not pretty, but it doesn't seem worth
- * inventing a nicer API for this.
+ * The tuple will become DEAD immediately. Flag that this page is a
+ * candidate for pruning by setting xmin to TransactionXmin. While not
+ * immediately prunable, it is the oldest xid we can cheaply determine
+ * that's safe against wraparound / being older than the table's
+ * relfrozenxid. To defend against the unlikely case of a new relation
+ * having a newer relfrozenxid than our TransactionXmin, use relfrozenxid
+ * if so (vacuum can't subsequently move relfrozenxid to beyond
+ * TransactionXmin, so there's no race here).
*/
- Assert(TransactionIdIsValid(RecentGlobalXmin));
- PageSetPrunable(page, RecentGlobalXmin);
+ Assert(TransactionIdIsValid(TransactionXmin));
+ if (TransactionIdPrecedes(TransactionXmin, relation->rd_rel->relfrozenxid))
+ prune_xid = relation->rd_rel->relfrozenxid;
+ else
+ prune_xid = TransactionXmin;
+ PageSetPrunable(page, prune_xid);
/* store transaction information of xact deleting the tuple */
tp.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);