Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 76ec457

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 ccd6504 commit 76ec457

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
@@ -5635,6 +5635,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
56355635
new_xmax;
56365636
TransactionId priorXmax = InvalidTransactionId;
56375637
bool cleared_all_frozen = false;
5638+
bool pinned_desired_page;
56385639
Buffer vmbuffer = InvalidBuffer;
56395640
BlockNumber block;
56405641

@@ -5656,7 +5657,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
56565657
* chain, and there's no further tuple to lock: return success to
56575658
* caller.
56585659
*/
5659-
return HeapTupleMayBeUpdated;
5660+
result = HeapTupleMayBeUpdated;
5661+
goto out_unlocked;
56605662
}
56615663

56625664
l4:
@@ -5669,9 +5671,12 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
56695671
* to recheck after we have the lock.
56705672
*/
56715673
if (PageIsAllVisible(BufferGetPage(buf)))
5674+
{
56725675
visibilitymap_pin(rel, block, &vmbuffer);
5676+
pinned_desired_page = true;
5677+
}
56735678
else
5674-
vmbuffer = InvalidBuffer;
5679+
pinned_desired_page = false;
56755680

56765681
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
56775682

@@ -5680,8 +5685,13 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
56805685
* all visible while we were busy locking the buffer, we'll have to
56815686
* unlock and re-lock, to avoid holding the buffer lock across I/O.
56825687
* That's a bit unfortunate, but hopefully shouldn't happen often.
5688+
*
5689+
* Note: in some paths through this function, we will reach here
5690+
* holding a pin on a vm page that may or may not be the one matching
5691+
* this page. If this page isn't all-visible, we won't use the vm
5692+
* page, but we hold onto such a pin till the end of the function.
56835693
*/
5684-
if (vmbuffer == InvalidBuffer && PageIsAllVisible(BufferGetPage(buf)))
5694+
if (!pinned_desired_page && PageIsAllVisible(BufferGetPage(buf)))
56855695
{
56865696
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
56875697
visibilitymap_pin(rel, block, &vmbuffer);
@@ -5707,8 +5717,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
57075717
*/
57085718
if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(mytup.t_data)))
57095719
{
5710-
UnlockReleaseBuffer(buf);
5711-
return HeapTupleMayBeUpdated;
5720+
result = HeapTupleMayBeUpdated;
5721+
goto out_locked;
57125722
}
57135723

57145724
old_infomask = mytup.t_data->t_infomask;
@@ -5915,20 +5925,18 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
59155925
priorXmax = HeapTupleHeaderGetUpdateXid(mytup.t_data);
59165926
ItemPointerCopy(&(mytup.t_data->t_ctid), &tupid);
59175927
UnlockReleaseBuffer(buf);
5918-
if (vmbuffer != InvalidBuffer)
5919-
ReleaseBuffer(vmbuffer);
59205928
}
59215929

59225930
result = HeapTupleMayBeUpdated;
59235931

59245932
out_locked:
59255933
UnlockReleaseBuffer(buf);
59265934

5935+
out_unlocked:
59275936
if (vmbuffer != InvalidBuffer)
59285937
ReleaseBuffer(vmbuffer);
59295938

59305939
return result;
5931-
59325940
}
59335941

59345942
/*

0 commit comments

Comments
 (0)