10000 Fix VM buffer pin management in heap_lock_updated_tuple_rec(). · postgres/postgres@96d2df8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 96d2df8

Browse files
committed
Fix VM buffer pin management in heap_lock_updated_tuple_rec().
Sloppy coding in this function could lead to leaking a VM buffer pin, or to attempting to free the same pin twice. Repair. While at it, reduce the code's tendency to free and reacquire the same page pin. Back-patch to 9.6; before that, this routine did not concern itself with VM pages. Amit Kapila and Tom Lane Discussion: https://postgr.es/m/CAA4eK1KJKwhc=isgTQHjM76CAdVswzNeAuZkh_cx-6QgGkSEgA@mail.gmail.com
1 parent 529137c commit 96d2df8

File tree

1 file changed

+16
-8
lines changed

1 file changed

+16
-8
lines changed

src/backend/access/heap/heapam.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5661,6 +5661,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
56615661
new_xmax;
56625662
TransactionId priorXmax = InvalidTransactionId;
56635663
bool cleared_all_frozen = false;
5664+
bool pinned_desired_page;
56645665
Buffer vmbuffer = InvalidBuffer;
56655666
BlockNumber block;
56665667

@@ -5682,7 +5683,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
56825683
* chain, and there's no further tuple to lock: return success to
56835684
* caller.
56845685
*/
5685-
return HeapTupleMayBeUpdated;
5686+
result = HeapTupleMayBeUpdated;
5687+
goto out_unlocked;
56865688
}
56875689

56885690
l4:
@@ -5695,9 +5697,12 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
56955697
* to recheck after we have the lock.
56965698
*/
56975699
if (PageIsAllVisible(BufferGetPage(buf)))
5700+
{
56985701
visibilitymap_pin(rel, block, &vmbuffer);
5702+
pinned_desired_page = true;
5703+
}
56995704
else
5700-
vmbuffer = InvalidBuffer;
5705+
pinned_desired_page = false;
57015706

57025707
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
57035708

@@ -5706,8 +5711,13 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
57065711
* all visible while we were busy locking the buffer, we'll have to
57075712
* unlock and re-lock, to avoid holding the buffer lock across I/O.
57085713
* That's a bit unfortunate, but hopefully shouldn't happen often.
5714+
*
5715+
* Note: in some paths through this function, we will reach here
5716+
* holding a pin on a vm page that may or may not be the one matching
5717+
* this page. If this page isn't all-visible, we won't use the vm
5718+
* page, but we hold onto such a pin till the end of the function.
57095719
*/
5710-
if (vmbuffer == InvalidBuffer && PageIsAllVisible(BufferGetPage(buf)))
5720+
if (!pinned_desired_page && PageIsAllVisible(BufferGetPage(buf)))
57115721
{
57125722
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
57135723
visibilitymap_pin(rel, block, &vmbuffer);
@@ -5733,8 +5743,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
57335743
*/
57345744
if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(mytup.t_data)))
57355745
{
5736-
UnlockReleaseBuffer(buf);
5737-
return HeapTupleMayBeUpdated;
5746+
result = HeapTupleMayBeUpdated;
5747+
goto out_locked;
57385748
}
57395749

57405750
old_infomask = mytup.t_data->t_infomask;
@@ -5941,20 +5951,18 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
59415951
priorXmax = HeapTupleHeaderGetUpdateXid(mytup.t_data);
59425952
ItemPointerCopy(&(mytup.t_data->t_ctid), &tupid);
59435953
UnlockReleaseBuffer(buf);
5944-
if (vmbuffer != InvalidBuffer)
5945-
ReleaseBuffer(vmbuffer);
59465954
}
59475955

59485956
result = HeapTupleMayBeUpdated;
59495957

59505958
out_locked:
59515959
UnlockReleaseBuffer(buf);
59525960

5961+
out_unlocked:
59535962
if (vmbuffer != InvalidBuffer)
59545963
ReleaseBuffer(vmbuffer);
59555964

59565965
return result;
5957-
59585966
}
59595967

59605968
/*

0 commit comments

Comments
 (0)
0