@@ -5635,6 +5635,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5635
5635
new_xmax ;
5636
5636
TransactionId priorXmax = InvalidTransactionId ;
5637
5637
bool cleared_all_frozen = false;
5638
+ bool pinned_desired_page ;
5638
5639
Buffer vmbuffer = InvalidBuffer ;
5639
5640
BlockNumber block ;
5640
5641
@@ -5656,7 +5657,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5656
5657
* chain, and there's no further tuple to lock: return success to
5657
5658
* caller.
5658
5659
*/
5659
- return HeapTupleMayBeUpdated ;
5660
+ result = HeapTupleMayBeUpdated ;
5661
+ goto out_unlocked ;
5660
5662
}
5661
5663
5662
5664
l4 :
@@ -5669,9 +5671,12 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5669
5671
* to recheck after we have the lock.
5670
5672
*/
5671
5673
if (PageIsAllVisible (BufferGetPage (buf )))
5674
+ {
5672
5675
visibilitymap_pin (rel , block , & vmbuffer );
5676
+ pinned_desired_page = true;
5677
+ }
5673
5678
else
5674
- vmbuffer = InvalidBuffer ;
5679
+ pinned_desired_page = false ;
5675
5680
5676
5681
LockBuffer (buf , BUFFER_LOCK_EXCLUSIVE );
5677
5682
@@ -5680,8 +5685,13 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5680
5685
* all visible while we were busy locking the buffer, we'll have to
5681
5686
* unlock and re-lock, to avoid holding the buffer lock across I/O.
5682
5687
* 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.
5683
5693
*/
5684
- if (vmbuffer == InvalidBuffer && PageIsAllVisible (BufferGetPage (buf )))
5694
+ if (! pinned_desired_page && PageIsAllVisible (BufferGetPage (buf )))
5685
5695
{
5686
5696
LockBuffer (buf , BUFFER_LOCK_UNLOCK );
5687
5697
visibilitymap_pin (rel , block , & vmbuffer );
@@ -5707,8 +5717,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5707
5717
*/
5708
5718
if (TransactionIdDidAbort (HeapTupleHeaderGetXmin (mytup .t_data )))
5709
5719
{
5710
- UnlockReleaseBuffer ( buf ) ;
5711
- return HeapTupleMayBeUpdated ;
5720
+ result = HeapTupleMayBeUpdated ;
5721
+ goto out_locked ;
5712
5722
}
5713
5723
5714
5724
old_infomask = mytup .t_data -> t_infomask ;
@@ -5915,20 +5925,18 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5915
5925
priorXmax = HeapTupleHeaderGetUpdateXid (mytup .t_data );
5916
5926
ItemPointerCopy (& (mytup .t_data -> t_ctid ), & tupid );
5917
5927
UnlockReleaseBuffer (buf );
5918
- if (vmbuffer != InvalidBuffer )
5919
- ReleaseBuffer (vmbuffer );
5920
5928
}
5921
5929
5922
5930
result = HeapTupleMayBeUpdated ;
5923
5931
5924
5932
out_locked :
5925
5933
UnlockReleaseBuffer (buf );
5926
5934
5935
+ out_unlocked :
5927
5936
if (vmbuffer != InvalidBuffer )
5928
5937
ReleaseBuffer (vmbuffer );
5929
5938
5930
5939
return result ;
5931
-
5932
5940
}
5933
5941
5934
5942
/*
0 commit comments