Skip to content

Commit 2193461

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 e4514aa commit 2193461

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

27742774
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
27752775

2776+
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
2777+
Assert(ItemIdIsNormal(lp));
2778+
2779+
tp.t_tableOid = RelationGetRelid(relation);
2780+
tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
2781+
tp.t_len = ItemIdGetLength(lp);
2782+
tp.t_self = *tid;
2783+
2784+
l1:
27762785
/*
27772786
* If we didn't pin the visibility map page and the page has become all
27782787
* visible while we were busy locking the buffer, we'll have to unlock and
@@ -2786,15 +2795,6 @@ heap_delete(Relation relation, ItemPointer tid,
27862795
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
27872796
}
27882797

2789-
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
2790-
Assert(ItemIdIsNormal(lp));
2791-
2792-
tp.t_tableOid = RelationGetRelid(relation);
2793-
tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
2794-
tp.t_len = ItemIdGetLength(lp);
2795-
tp.t_self = *tid;
2796-
2797-
l1:
27982798
result = HeapTupleSatisfiesUpdate(&tp, cid, buffer);
27992799

28002800
if (result == TM_Invisible)
@@ -2853,8 +2853,12 @@ heap_delete(Relation relation, ItemPointer tid,
28532853
* If xwait had just locked the tuple then some other xact
28542854
* could update this tuple before we get to this point. Check
28552855
* for xmax change, and start over if so.
2856+
*
2857+
* We also must start over if we didn't pin the VM page, and
2858+
* the page has become all visible.
28562859
*/
2857-
if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
2860+
if ((vmbuffer == InvalidBuffer && PageIsAllVisible(page)) ||
2861+
xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
28582862
!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
28592863
xwait))
28602864
goto l1;
@@ -2886,8 +2890,12 @@ heap_delete(Relation relation, ItemPointer tid,
28862890
* xwait is done, but if xwait had just locked the tuple then some
28872891
* other xact could update this tuple before we get to this point.
28882892
* Check for xmax change, and start over if so.
2893+
*
2894+
* We also must start over if we didn't pin the VM page, and the
2895+
* page has become all visible.
28892896
*/
2890-
if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
2897+
if ((vmbuffer == InvalidBuffer && PageIsAllVisible(page)) ||
2898+
xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
28912899
!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
28922900
xwait))
28932901
goto l1;

0 commit comments

Comments
 (0)