Skip to content

Commit 163b099

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 790bf61 commit 163b099

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
@@ -2711,6 +2711,15 @@ heap_delete(Relation relation, ItemPointer tid,
27112711

27122712
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
27132713

2714+
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
2715+
Assert(ItemIdIsNormal(lp));
2716+
2717+
tp.t_tableOid = RelationGetRelid(relation);
2718+
tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
2719+
tp.t_len = ItemIdGetLength(lp);
2720+
tp.t_self = *tid;
2721+
2722+
l1:
27142723
/*
27152724
* If we didn't pin the visibility map page and the page has become all
27162725
* visible while we were busy locking the buffer, we'll have to unlock and
@@ -2724,15 +2733,6 @@ heap_delete(Relation relation, ItemPointer tid,
27242733
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
27252734
}
27262735

2727-
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
2728-
Assert(ItemIdIsNormal(lp));
2729-
2730-
tp.t_tableOid = RelationGetRelid(relation);
2731-
tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
2732-
tp.t_len = ItemIdGetLength(lp);
2733-
tp.t_self = *tid;
2734-
2735-
l1:
27362736
result = HeapTupleSatisfiesUpdate(&tp, cid, buffer);
27372737

27382738
if (result == TM_Invisible)
@@ -2791,8 +2791,12 @@ heap_delete(Relation relation, ItemPointer tid,
27912791
* If xwait had just locked the tuple then some other xact
27922792
* could update this tuple before we get to this point. Check
27932793
* for xmax change, and start over if so.
2794+
*
2795+
* We also must start over if we didn't pin the VM page, and
2796+
* the page has become all visible.
27942797
*/
2795-
if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
2798+
if ((vmbuffer == InvalidBuffer && PageIsAllVisible(page)) ||
2799+
xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
27962800
!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
27972801
xwait))
27982802
goto l1;
@@ -2824,8 +2828,12 @@ heap_delete(Relation relation, ItemPointer tid,
28242828
* xwait is done, but if xwait had just locked the tuple then some
28252829
* other xact could update this tuple before we get to this point.
28262830
* Check for xmax change, and start over if so.
2831+
*
2832+
* We also must start over if we didn't pin the VM page, and the
2833+
* page has become all visible.
28272834
*/
2828-
if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
2835+
if ((vmbuffer == InvalidBuffer && PageIsAllVisible(page)) ||
2836+
xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
28292837
!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
28302838
xwait))
28312839
goto l1;

0 commit comments

Comments
 (0)