@@ -1737,7 +1737,8 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
1737
1737
* broken.
1738
1738
*/
1739
1739
if (TransactionIdIsValid (prev_xmax ) &&
1740
- !HeapTupleUpdateXmaxMatchesXmin (prev_xmax , heapTuple -> t_data ))
1740
+ !TransactionIdEquals (prev_xmax ,
1741
+ HeapTupleHeaderGetXmin (heapTuple -> t_data )))
1741
1742
break ;
1742
1743
1743
1744
/*
@@ -1919,7 +1920,7 @@ heap_get_latest_tid(Relation relation,
1919
1920
* tuple. Check for XMIN match.
1920
1921
*/
1921
1922
if (TransactionIdIsValid (priorXmax ) &&
1922
- ! HeapTupleUpdateXmaxMatchesXmin (priorXmax , tp .t_data ))
1923
+ ! TransactionIdEquals (priorXmax , HeapTupleHeaderGetXmin ( tp .t_data ) ))
1923
1924
{
1924
1925
UnlockReleaseBuffer (buffer );
1925
1926
break ;
@@ -1951,50 +1952,6 @@ heap_get_latest_tid(Relation relation,
1951
1952
} /* end of loop */
1952
1953
}
1953
1954
1954
- /*
1955
- * HeapTupleUpdateXmaxMatchesXmin - verify update chain xmax/xmin lineage
1956
- *
1957
- * Given the new version of a tuple after some update, verify whether the
1958
- * given Xmax (corresponding to the previous version) matches the tuple's
1959
- * Xmin, taking into account that the Xmin might have been frozen after the
1960
- * update.
1961
- */
1962
- bool
1963
- HeapTupleUpdateXmaxMatchesXmin (TransactionId xmax , HeapTupleHeader htup )
1964
- {
1965
- TransactionId xmin = HeapTupleHeaderGetXmin (htup );
1966
-
1967
- /*
1968
- * If the xmax of the old tuple is identical to the xmin of the new one,
1969
- * it's a match.
1970
- */
1971
- if (TransactionIdEquals (xmax , xmin ))
1972
- return true;
1973
-
1974
- /*
1975
- * If the Xmin that was in effect prior to a freeze matches the Xmax,
1976
- * it's good too.
1977
- */
1978
- if (HeapTupleHeaderXminFrozen (htup ) &&
1979
- TransactionIdEquals (HeapTupleHeaderGetRawXmin (htup ), xmax ))
1980
- return true;
1981
-
1982
- /*
1983
- * When a tuple is frozen, the original Xmin is lost, but we know it's a
1984
- * committed transaction. So unless the Xmax is InvalidXid, we don't know
1985
- * for certain that there is a match, but there may be one; and we must
1986
- * return true so that a HOT chain that is half-frozen can be walked
1987
- * correctly.
1988
- *
1989
- * We no longer freeze tuples this way, but we must keep this in order to
1990
- * interpret pre-pg_upgrade pages correctly.
1991
- */
1992
- if (TransactionIdEquals (xmin , FrozenTransactionId ) &&
1993
- TransactionIdIsValid (xmax ))
1994
- return true;
1995
-
1996
- return false;
1997
- }
1998
1955
1999
1956
/*
2000
1957
* UpdateXmaxHintBits - update tuple hint bits after xmax transaction ends
@@ -5283,7 +5240,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5283
5240
* end of the chain, we're done, so return success.
5284
5241
*/
5285
5242
if (TransactionIdIsValid (priorXmax ) &&
5286
- !HeapTupleUpdateXmaxMatchesXmin (priorXmax , mytup .t_data ))
5243
+ !TransactionIdEquals (HeapTupleHeaderGetXmin (mytup .t_data ),
5244
+ priorXmax ))
5287
5245
{
5288
5246
UnlockReleaseBuffer (buf );
5289
5247
return HeapTupleMayBeUpdated ;
@@ -5729,23 +5687,14 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
5729
5687
Assert (TransactionIdIsValid (xid ));
5730
5688
5731
5689
/*
5732
- * The updating transaction cannot possibly be still running, but
5733
- * verify whether it has committed, and request to set the
5734
- * COMMITTED flag if so. (We normally don't see any tuples in
5735
- * this state, because they are removed by page pruning before we
5736
- * try to freeze the page; but this can happen if the updating
5737
- * transaction commits after the page is pruned but before
5738
- * HeapTupleSatisfiesVacuum).
5690
+ * If the xid is older than the cutoff, it has to have aborted,
5691
+ * otherwise the tuple would have gotten pruned away.
5739
5692
*/
5740
5693
if (TransactionIdPrecedes (xid , cutoff_xid ))
5741
5694
{
5742
- if (TransactionIdDidCommit (xid ))
5743
- * flags = FRM_MARK_COMMITTED | FRM_RETURN_IS_XID ;
5744
- else
5745
- {
5746
- * flags |= FRM_INVALIDATE_XMAX ;
5747
- xid = InvalidTransactionId ; /* not strictly necessary */
5748
- }
5695
+ Assert (!TransactionIdDidCommit (xid ));
5696
+ * flags |= FRM_INVALIDATE_XMAX ;
5697
+ xid = InvalidTransactionId ; /* not strictly necessary */
5749
5698
}
5750
5699
else
5751
5700
{
@@ -5816,51 +5765,65 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
5816
5765
5817
5766
/*
5818
5767
* It's an update; should we keep it? If the transaction is known
5819
- * aborted or crashed then it's okay to ignore it, otherwise not.
5768
+ * aborted then it's okay to ignore it, otherwise not. However,
5769
+ * if the Xid is older than the cutoff_xid, we must remove it.
5770
+ * Note that such an old updater cannot possibly be committed,
5771
+ * because HeapTupleSatisfiesVacuum would have returned
5772
+ * HEAPTUPLE_DEAD and we would not be trying to freeze the tuple.
5773
+ *
5774
+ * Note the TransactionIdDidAbort() test is just an optimization
5775
+ * and not strictly necessary for correctness.
5820
5776
*
5821
5777
* As with all tuple visibility routines, it's critical to test
5822
- * TransactionIdIsInProgress before TransactionIdDidCommit ,
5778
+ * TransactionIdIsInProgress before the transam.c routines ,
5823
5779
* because of race conditions explained in detail in tqual.c.
5824
- *
5825
- * We normally don't see committed updating transactions earlier
5826
- * than the cutoff xid, because they are removed by page pruning
5827
- * before we try to freeze the page; but it can happen if the
5828
- * updating transaction commits after the page is pruned but
5829
- * before HeapTupleSatisfiesVacuum.
5830
5780
*/
5831
5781
if (TransactionIdIsCurrentTransactionId (xid ) ||
5832
5782
TransactionIdIsInProgress (xid ))
5833
5783
{
5834
5784
Assert (!TransactionIdIsValid (update_xid ));
5835
5785
update_xid = xid ;
5836
5786
}
5837
- else if (TransactionIdDidCommit (xid ))
5787
+ else if (! TransactionIdDidAbort (xid ))
5838
5788
{
5839
5789
/*
5840
- * The transaction committed, so we can tell caller to set
5841
- * HEAP_XMAX_COMMITTED. (We can only do this because we know
5842
- * the transaction is not running.)
5790
+ * Test whether to tell caller to set HEAP_XMAX_COMMITTED
5791
+ * while we have the Xid still in cache. Note this can only
5792
+ * be done if the transaction is known not running.
5843
5793
*/
5794
+ if (TransactionIdDidCommit (xid ))
5795
+ update_committed = true;
5844
5796
Assert (!TransactionIdIsValid (update_xid ));
5845
- update_committed = true;
5846
5797
update_xid = xid ;
5847
5798
}
5848
5799
5849
- /*
5850
- * Not in progress, not committed -- must be aborted or crashed;
5851
- * we can ignore it.
5852
- */
5853
-
5854
5800
/*
5855
5801
* If we determined that it's an Xid corresponding to an update
5856
5802
* that must be retained, additionally add it to the list of
5857
- * members of the new Multi , in case we end up using that. (We
5803
+ * members of the new Multis , in case we end up using that. (We
5858
5804
* might still decide to use only an update Xid and not a multi,
5859
5805
* but it's easier to maintain the list as we walk the old members
5860
5806
* list.)
5807
+ *
5808
+ * It is possible to end up with a very old updater Xid that
5809
+ * crashed and thus did not mark itself as aborted in pg_clog.
5810
+ * That would manifest as a pre-cutoff Xid. Make sure to ignore
5811
+ * it.
5861
5812
*/
5862
5813
if (TransactionIdIsValid (update_xid ))
5863
- newmembers [nnewmembers ++ ] = members [i ];
5814
+ {
5815
+ if (!TransactionIdPrecedes (update_xid , cutoff_xid ))
5816
+ {
5817
+ newmembers [nnewmembers ++ ] = members [i ];
5818
+ }
5819
+ else
5820
+ {
5821
+ /* cannot have committed: would be HEAPTUPLE_DEAD */
5822
+ Assert (!TransactionIdDidCommit (update_xid ));
5823
+ update_xid = InvalidTransactionId ;
5824
+ update_committed = false;
5825
+ }
5826
+ }
5864
5827
}
5865
5828
else
5866
5829
{
@@ -5927,10 +5890,7 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
5927
5890
*
5928
5891
* It is assumed that the caller has checked the tuple with
5929
5892
* HeapTupleSatisfiesVacuum() and determined that it is not HEAPTUPLE_DEAD
5930
- * (else we should be removing the tuple, not freezing it). However, note
5931
- * that we don't remove HOT tuples even if they are dead, and it'd be incorrect
5932
- * to freeze them (because that would make them visible), so we mark them as
5933
- * update-committed, and needing further freezing later on.
5893
+ * (else we should be removing the tuple, not freezing it).
5934
5894
*
5935
5895
* NB: cutoff_xid *must* be <= the current global xmin, to ensure that any
5936
5896
* XID older than it could neither be running nor seen as running by any
@@ -6035,18 +5995,7 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
6035
5995
else if (TransactionIdIsNormal (xid ) &&
6036
5996
TransactionIdPrecedes (xid , cutoff_xid ))
6037
5997
{
6038
- /*
6039
- * Must freeze regular XIDs older than the cutoff. We must not freeze
6040
- * a HOT-updated tuple, though; doing so would bring it back to life.
6041
- */
6042
- if (HeapTupleHeaderIsHotUpdated (tuple ))
6043
- {
6044
- frz -> t_infomask |= HEAP_XMAX_COMMITTED ;
6045
- changed = true;
6046
- /* must not freeze */
6047
- }
6048
- else
6049
- freeze_xmax = true;
5998
+ freeze_xmax = true;
6050
5999
}
6051
6000
6052
6001
if (freeze_xmax )
0 commit comments