Skip to content

Commit cab72f0

Browse files
committed
Fix race condition where heap_delete() fails to pin VM page.
Similar to 5f12bc9, the code must re-check PageIsAllVisible() after buffer lock is re-acquired. Backpatching to the same version, 12. Discussion: https://postgr.es/m/CAEP4nAw9jYQDKd_5Y+-s2E4YiUJq1vqiikFjYGpLShtp-K3gag@mail.gmail.com Reported-by: Robins Tharakan Reviewed-by: Robins Tharakan Backpatch-through: 12
1 parent 6359e4b commit cab72f0

File tree

1 file changed

+19
-11
lines changed

1 file changed

+19
-11
lines changed

src/backend/access/heap/heapam.c

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2531,6 +2531,15 @@ heap_delete(Relation relation, ItemPointer tid,
25312531

25322532
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
25332533

2534+
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
2535+
Assert(ItemIdIsNormal(lp));
2536+
2537+
tp.t_tableOid = RelationGetRelid(relation);
2538+
tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
2539+
tp.t_len = ItemIdGetLength(lp);
2540+
tp.t_self = *tid;
2541+
2542+
l1:
25342543
/*
25352544
* If we didn't pin the visibility map page and the page has become all
25362545
* visible while we were busy locking the buffer, we'll have to unlock and
@@ -2544,15 +2553,6 @@ heap_delete(Relation relation, ItemPointer tid,
25442553
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
25452554
}
25462555

2547-
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
2548-
Assert(ItemIdIsNormal(lp));
2549-
2550-
tp.t_tableOid = RelationGetRelid(relation);
2551-
tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
2552-
tp.t_len = ItemIdGetLength(lp);
2553-
tp.t_self = *tid;
2554-
2555-
l1:
25562556
result = HeapTupleSatisfiesUpdate(&tp, cid, buffer);
25572557

25582558
if (result == TM_Invisible)
@@ -2611,8 +2611,12 @@ heap_delete(Relation relation, ItemPointer tid,
26112611
* If xwait had just locked the tuple then some other xact
26122612
* could update this tuple before we get to this point. Check
26132613
* for xmax change, and start over if so.
2614+
*
2615+
* We also must start over if we didn't pin the VM page, and
2616+
* the page has become all visible.
26142617
*/
2615-
if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
2618+
if ((vmbuffer == InvalidBuffer && PageIsAllVisible(page)) ||
2619+
xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
26162620
!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
26172621
xwait))
26182622
goto l1;
@@ -2644,8 +2648,12 @@ heap_delete(Relation relation, ItemPointer tid,
26442648
* xwait is done, but if xwait had just locked the tuple then some
26452649
* other xact could update this tuple before we get to this point.
26462650
* Check for xmax change, and start over if so.
2651+
*
2652+
* We also must start over if we didn't pin the VM page, and the
2653+
* page has become all visible.
26472654
*/
2648-
if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
2655+
if ((vmbuffer == InvalidBuffer && PageIsAllVisible(page)) ||
2656+
xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
26492657
!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
26502658
xwait))
26512659
goto l1;

0 commit comments

Comments
 (0)