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

Lines changed: 16 additions & 8 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy