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

Commit 0b1d1a0

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 e94f2bc commit 0b1d1a0

File tree

1 file changed

+16
-8
lines changed

1 file changed

+16
-8
lines changed

src/backend/access/heap/heapam.c

+16-8
Original file line numberDiff line numberDiff line change
@@ -5677,6 +5677,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
56775677
new_xmax;
56785678
TransactionId priorXmax = InvalidTransactionId;
56795679
bool cleared_all_frozen = false;
5680+
bool pinned_desired_page;
56805681
Buffer vmbuffer = InvalidBuffer;
56815682
BlockNumber block;
56825683

@@ -5698,7 +5699,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
56985699
* chain, and there's no further tuple to lock: return success to
56995700
* caller.
57005701
*/
5701-
return HeapTupleMayBeUpdated;
5702+
result = HeapTupleMayBeUpdated;
5703+
goto out_unlocked;
57025704
}
57035705

57045706
l4:
@@ -5711,9 +5713,12 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
57115713
* to recheck after we have the lock.
57125714
*/
57135715
if (PageIsAllVisible(BufferGetPage(buf)))
5716+
{
57145717
visibilitymap_pin(rel, block, &vmbuffer);
5718+
pinned_desired_page = true;
5719+
}
57155720
else
5716-
vmbuffer = InvalidBuffer;
5721+
pinned_desired_page = false;
57175722

57185723
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
57195724

@@ -5722,8 +5727,13 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
57225727
* all visible while we were busy locking the buffer, we'll have to
57235728
* unlock and re-lock, to avoid holding the buffer lock across I/O.
57245729
* That's a bit unfortunate, but hopefully shouldn't happen often.
5730+
*
5731+
* Note: in some paths through this function, we will reach here
5732+
* holding a pin on a vm page that may or may not be the one matching
5733+
* this page. If this page isn't all-visible, we won't use the vm
5734+
* page, but we hold onto such a pin till the end of the function.
57255735
*/
5726-
if (vmbuffer == InvalidBuffer && PageIsAllVisible(BufferGetPage(buf)))
5736+
if (!pinned_desired_page && PageIsAllVisible(BufferGetPage(buf)))
57275737
{
57285738
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
57295739
visibilitymap_pin(rel, block, &vmbuffer);
@@ -5749,8 +5759,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
57495759
*/
57505760
if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(mytup.t_data)))
57515761
{
5752-
UnlockReleaseBuffer(buf);
5753-
return HeapTupleMayBeUpdated;
5762+
result = HeapTupleMayBeUpdated;
5763+
goto out_locked;
57545764
}
57555765

57565766
old_infomask = mytup.t_data->t_infomask;
@@ -5957,20 +5967,18 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
59575967
priorXmax = HeapTupleHeaderGetUpdateXid(mytup.t_data);
59585968
ItemPointerCopy(&(mytup.t_data->t_ctid), &tupid);
59595969
UnlockReleaseBuffer(buf);
5960-
if (vmbuffer != InvalidBuffer)
5961-
ReleaseBuffer(vmbuffer);
59625970
}
59635971

59645972
result = HeapTupleMayBeUpdated;
59655973

59665974
out_locked:
59675975
UnlockReleaseBuffer(buf);
59685976

5977+
out_unlocked:
59695978
if (vmbuffer != InvalidBuffer)
59705979
ReleaseBuffer(vmbuffer);
59715980

59725981
return result;
5973-
59745982
}
59755983

59765984
/*

0 commit comments

Comments
 (0)