@@ -5677,6 +5677,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5677
5677
new_xmax ;
5678
5678
TransactionId priorXmax = InvalidTransactionId ;
5679
5679
bool cleared_all_frozen = false;
5680
+ bool pinned_desired_page ;
5680
5681
Buffer vmbuffer = InvalidBuffer ;
5681
5682
BlockNumber block ;
5682
5683
@@ -5698,7 +5699,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5698
5699
* chain, and there's no further tuple to lock: return success to
5699
5700
* caller.
5700
5701
*/
5701
- return HeapTupleMayBeUpdated ;
5702
+ result = HeapTupleMayBeUpdated ;
5703
+ goto out_unlocked ;
5702
5704
}
5703
5705
5704
5706
l4 :
@@ -5711,9 +5713,12 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5711
5713
* to recheck after we have the lock.
5712
5714
*/
5713
5715
if (PageIsAllVisible (BufferGetPage (buf )))
5716
+ {
5714
5717
visibilitymap_pin (rel , block , & vmbuffer );
5718
+ pinned_desired_page = true;
5719
+ }
5715
5720
else
5716
- vmbuffer = InvalidBuffer ;
5721
+ pinned_desired_page = false ;
5717
5722
5718
5723
LockBuffer (buf , BUFFER_LOCK_EXCLUSIVE );
5719
5724
@@ -5722,8 +5727,13 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5722
5727
* all visible while we were busy locking the buffer, we'll have to
5723
5728
* unlock and re-lock, to avoid holding the buffer lock across I/O.
5724
5729
* 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.
5725
5735
*/
5726
- if (vmbuffer == InvalidBuffer && PageIsAllVisible (BufferGetPage (buf )))
5736
+ if (! pinned_desired_page && PageIsAllVisible (BufferGetPage (buf )))
5727
5737
{
5728
5738
LockBuffer (buf , BUFFER_LOCK_UNLOCK );
5729
5739
visibilitymap_pin (rel , block , & vmbuffer );
@@ -5749,8 +5759,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5749
5759
*/
5750
5760
if (TransactionIdDidAbort (HeapTupleHeaderGetXmin (mytup .t_data )))
5751
5761
{
5752
- UnlockReleaseBuffer ( buf ) ;
5753
- return HeapTupleMayBeUpdated ;
5762
+ result = HeapTupleMayBeUpdated ;
5763
+ goto out_locked ;
5754
5764
}
5755
5765
5756
5766
old_infomask = mytup .t_data -> t_infomask ;
@@ -5957,20 +5967,18 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5957
5967
priorXmax = HeapTupleHeaderGetUpdateXid (mytup .t_data );
5958
5968
ItemPointerCopy (& (mytup .t_data -> t_ctid ), & tupid );
5959
5969
UnlockReleaseBuffer (buf );
5960
- if (vmbuffer != InvalidBuffer )
5961
- ReleaseBuffer (vmbuffer );
5962
5970
}
5963
5971
5964
5972
result = HeapTupleMayBeUpdated ;
5965
5973
5966
5974
out_locked :
5967
5975
UnlockReleaseBuffer (buf );
5968
5976
5977
+ out_unlocked :
5969
5978
if (vmbuffer != InvalidBuffer )
5970
5979
ReleaseBuffer (vmbuffer );
5971
5980
5972
5981
return result ;
5973
-
5974
5982
}
5975
5983
5976
5984
/*
0 commit comments