diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index a25d539ec47..c4a5aa616a3 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -5581,6 +5581,7 @@ heap_abort_speculative(Relation relation, ItemPointer tid) Page page; BlockNumber block; Buffer buffer; + TransactionId prune_xid; Assert(ItemPointerIsValid(tid)); @@ -5623,13 +5624,21 @@ heap_abort_speculative(Relation relation, ItemPointer tid) 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);