Applies on top of v2 and nocfbot-0001. Not for the CF bot. Replaces nocfbot-0002 from 2026-10-22: the clog is only a filter, the proc array still confirms the abort before the hint is set. diff --git a/src/backend/access/heap/heapam_visibility.c b/src/backend/access/heap/heapam_visibility.c --- a/src/backend/access/heap/heapam_visibility.c +++ b/src/backend/access/heap/heapam_visibility.c @@ -1197,10 +1197,18 @@ HeapTupleSatisfiesVacuumHorizon(HeapTupl { TransactionId xmax = HeapTupleHeaderGetUpdateXid(tuple); - /* xmax == xmin: xmax is in progress too, nothing to do */ + /* + * xmax == xmin: xmax is in progress too, nothing to do. + * The clog is only a cheap filter here: a running xmax is not + * aborted there. An abort reaches the clog before the xid + * leaves the proc array, and the new version of the tuple, + * whose xmin is this xmax, is in progress until then. So the + * proc array must confirm it, as the note at the top of this + * file asks. + */ if (!TransactionIdEquals(xmax, HeapTupleHeaderGetRawXmin(tuple)) && - !TransactionIdIsInProgress(xmax) && - !TransactionIdDidCommit(xmax)) + TransactionIdDidAbort(xmax) && + !TransactionIdIsInProgress(xmax)) SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); }