@@ -5661,6 +5661,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5661
5661
new_xmax ;
5662
5662
TransactionId priorXmax = InvalidTransactionId ;
5663
5663
bool cleared_all_frozen = false;
5664
+ bool pinned_desired_page ;
5664
5665
Buffer vmbuffer = InvalidBuffer ;
5665
5666
BlockNumber block ;
5666
5667
@@ -5682,7 +5683,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5682
5683
* chain, and there's no further tuple to lock: return success to
5683
5684
* caller.
5684
5685
*/
5685
- return HeapTupleMayBeUpdated ;
5686
+ result = HeapTupleMayBeUpdated ;
5687
+ goto out_unlocked ;
5686
5688
}
5687
5689
5688
5690
l4 :
@@ -5695,9 +5697,12 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5695
5697
* to recheck after we have the lock.
5696
5698
*/
5697
5699
if (PageIsAllVisible (BufferGetPage (buf )))
5700
+ {
5698
5701
visibilitymap_pin (rel , block , & vmbuffer );
5702
+ pinned_desired_page = true;
5703
+ }
5699
5704
else
5700
- vmbuffer = InvalidBuffer ;
5705
+ pinned_desired_page = false ;
5701
5706
5702
5707
LockBuffer (buf , BUFFER_LOCK_EXCLUSIVE );
5703
5708
@@ -5706,8 +5711,13 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5706
5711
* all visible while we were busy locking the buffer, we'll have to
5707
5712
* unlock and re-lock, to avoid holding the buffer lock across I/O.
5708
5713
* 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.
5709
5719
*/
5710
- if (vmbuffer == InvalidBuffer && PageIsAllVisible (BufferGetPage (buf )))
5720
+ if (! pinned_desired_page && PageIsAllVisible (BufferGetPage (buf )))
5711
5721
{
5712
5722
LockBuffer (buf , BUFFER_LOCK_UNLOCK );
5713
5723
visibilitymap_pin (rel , block , & vmbuffer );
@@ -5733,8 +5743,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5733
5743
*/
5734
5744
if (TransactionIdDidAbort (HeapTupleHeaderGetXmin (mytup .t_data )))
5735
5745
{
5736
- UnlockReleaseBuffer ( buf ) ;
5737
- return HeapTupleMayBeUpdated ;
5746
+ result = HeapTupleMayBeUpdated ;
5747
+ goto out_locked ;
5738
5748
}
5739
5749
5740
5750
old_infomask = mytup .t_data -> t_infomask ;
@@ -5941,20 +5951,18 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5941
5951
priorXmax = HeapTupleHeaderGetUpdateXid (mytup .t_data );
5942
5952
ItemPointerCopy (& (mytup .t_data -> t_ctid ), & tupid );
5943
5953
UnlockReleaseBuffer (buf );
5944
- if (vmbuffer != InvalidBuffer )
5945
- ReleaseBuffer (vmbuffer );
5946
5954
}
5947
5955
5948
5956
result = HeapTupleMayBeUpdated ;
5949
5957
5950
5958
out_locked :
5951
5959
UnlockReleaseBuffer (buf );
5952
5960
5961
+ out_unlocked :
5953
5962
if (vmbuffer != InvalidBuffer )
5954
5963
ReleaseBuffer (vmbuffer );
5955
5964
5956
5965
return result ;
5957
-
5958
5966
}
5959
5967
5960
5968
/*
0 commit comments