LCOV - code coverage report
Current view: top level - src/backend/access/heap - heapam_visibility.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 355 555 64.0 %
Date: 2019-11-21 15:06:52 Functions: 15 15 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * heapam_visibility.c
       4             :  *    Tuple visibility rules for tuples stored in heap.
       5             :  *
       6             :  * NOTE: all the HeapTupleSatisfies routines will update the tuple's
       7             :  * "hint" status bits if we see that the inserting or deleting transaction
       8             :  * has now committed or aborted (and it is safe to set the hint bits).
       9             :  * If the hint bits are changed, MarkBufferDirtyHint is called on
      10             :  * the passed-in buffer.  The caller must hold not only a pin, but at least
      11             :  * shared buffer content lock on the buffer containing the tuple.
      12             :  *
      13             :  * NOTE: When using a non-MVCC snapshot, we must check
      14             :  * TransactionIdIsInProgress (which looks in the PGXACT array)
      15             :  * before TransactionIdDidCommit/TransactionIdDidAbort (which look in
      16             :  * pg_xact).  Otherwise we have a race condition: we might decide that a
      17             :  * just-committed transaction crashed, because none of the tests succeed.
      18             :  * xact.c is careful to record commit/abort in pg_xact before it unsets
      19             :  * MyPgXact->xid in the PGXACT array.  That fixes that problem, but it
      20             :  * also means there is a window where TransactionIdIsInProgress and
      21             :  * TransactionIdDidCommit will both return true.  If we check only
      22             :  * TransactionIdDidCommit, we could consider a tuple committed when a
      23             :  * later GetSnapshotData call will still think the originating transaction
      24             :  * is in progress, which leads to application-level inconsistency.  The
      25             :  * upshot is that we gotta check TransactionIdIsInProgress first in all
      26             :  * code paths, except for a few cases where we are looking at
      27             :  * subtransactions of our own main transaction and so there can't be any
      28             :  * race condition.
      29             :  *
      30             :  * When using an MVCC snapshot, we rely on XidInMVCCSnapshot rather than
      31             :  * TransactionIdIsInProgress, but the logic is otherwise the same: do not
      32             :  * check pg_xact until after deciding that the xact is no longer in progress.
      33             :  *
      34             :  *
      35             :  * Summary of visibility functions:
      36             :  *
      37             :  *   HeapTupleSatisfiesMVCC()
      38             :  *        visible to supplied snapshot, excludes current command
      39             :  *   HeapTupleSatisfiesUpdate()
      40             :  *        visible to instant snapshot, with user-supplied command
      41             :  *        counter and more complex result
      42             :  *   HeapTupleSatisfiesSelf()
      43             :  *        visible to instant snapshot and current command
      44             :  *   HeapTupleSatisfiesDirty()
      45             :  *        like HeapTupleSatisfiesSelf(), but includes open transactions
      46             :  *   HeapTupleSatisfiesVacuum()
      47             :  *        visible to any running transaction, used by VACUUM
      48             :  *   HeapTupleSatisfiesNonVacuumable()
      49             :  *        Snapshot-style API for HeapTupleSatisfiesVacuum
      50             :  *   HeapTupleSatisfiesToast()
      51             :  *        visible unless part of interrupted vacuum, used for TOAST
      52             :  *   HeapTupleSatisfiesAny()
      53             :  *        all tuples are visible
      54             :  *
      55             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
      56             :  * Portions Copyright (c) 1994, Regents of the University of California
      57             :  *
      58             :  * IDENTIFICATION
      59             :  *    src/backend/access/heap/heapam_visibility.c
      60             :  *
      61             :  *-------------------------------------------------------------------------
      62             :  */
      63             : 
      64             : #include "postgres.h"
      65             : 
      66             : #include "access/heapam.h"
      67             : #include "access/htup_details.h"
      68             : #include "access/multixact.h"
      69             : #include "access/subtrans.h"
      70             : #include "access/tableam.h"
      71             : #include "access/transam.h"
      72             : #include "access/xact.h"
      73             : #include "access/xlog.h"
      74             : #include "storage/bufmgr.h"
      75             : #include "storage/procarray.h"
      76             : #include "utils/builtins.h"
      77             : #include "utils/combocid.h"
      78             : #include "utils/snapmgr.h"
      79             : 
      80             : 
      81             : /*
      82             :  * SetHintBits()
      83             :  *
      84             :  * Set commit/abort hint bits on a tuple, if appropriate at this time.
      85             :  *
      86             :  * It is only safe to set a transaction-committed hint bit if we know the
      87             :  * transaction's commit record is guaranteed to be flushed to disk before the
      88             :  * buffer, or if the table is temporary or unlogged and will be obliterated by
      89             :  * a crash anyway.  We cannot change the LSN of the page here, because we may
      90             :  * hold only a share lock on the buffer, so we can only use the LSN to
      91             :  * interlock this if the buffer's LSN already is newer than the commit LSN;
      92             :  * otherwise we have to just refrain from setting the hint bit until some
      93             :  * future re-examination of the tuple.
      94             :  *
      95             :  * We can always set hint bits when marking a transaction aborted.  (Some
      96             :  * code in heapam.c relies on that!)
      97             :  *
      98             :  * Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
      99             :  * we can always set the hint bits, since pre-9.0 VACUUM FULL always used
     100             :  * synchronous commits and didn't move tuples that weren't previously
     101             :  * hinted.  (This is not known by this subroutine, but is applied by its
     102             :  * callers.)  Note: old-style VACUUM FULL is gone, but we have to keep this
     103             :  * module's support for MOVED_OFF/MOVED_IN flag bits for as long as we
     104             :  * support in-place update from pre-9.0 databases.
     105             :  *
     106             :  * Normal commits may be asynchronous, so for those we need to get the LSN
     107             :  * of the transaction and then check whether this is flushed.
     108             :  *
     109             :  * The caller should pass xid as the XID of the transaction to check, or
     110             :  * InvalidTransactionId if no check is needed.
     111             :  */
     112             : static inline void
     113    17354296 : SetHintBits(HeapTupleHeader tuple, Buffer buffer,
     114             :             uint16 infomask, TransactionId xid)
     115             : {
     116    17354296 :     if (TransactionIdIsValid(xid))
     117             :     {
     118             :         /* NB: xid must be known committed here! */
     119    17315326 :         XLogRecPtr  commitLSN = TransactionIdGetCommitLSN(xid);
     120             : 
     121    17397610 :         if (BufferIsPermanent(buffer) && XLogNeedsFlush(commitLSN) &&
     122       82284 :             BufferGetLSNAtomic(buffer) < commitLSN)
     123             :         {
     124             :             /* not flushed and no LSN interlock, so don't set hint */
     125       57356 :             return;
     126             :         }
     127             :     }
     128             : 
     129    17296940 :     tuple->t_infomask |= infomask;
     130    17296940 :     MarkBufferDirtyHint(buffer, true);
     131             : }
     132             : 
     133             : /*
     134             :  * HeapTupleSetHintBits --- exported version of SetHintBits()
     135             :  *
     136             :  * This must be separate because of C99's brain-dead notions about how to
     137             :  * implement inline functions.
     138             :  */
     139             : void
     140         250 : HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
     141             :                      uint16 infomask, TransactionId xid)
     142             : {
     143         250 :     SetHintBits(tuple, buffer, infomask, xid);
     144         250 : }
     145             : 
     146             : 
     147             : /*
     148             :  * HeapTupleSatisfiesSelf
     149             :  *      True iff heap tuple is valid "for itself".
     150             :  *
     151             :  * See SNAPSHOT_MVCC's definition for the intended behaviour.
     152             :  *
     153             :  * Note:
     154             :  *      Assumes heap tuple is valid.
     155             :  *
     156             :  * The satisfaction of "itself" requires the following:
     157             :  *
     158             :  * ((Xmin == my-transaction &&              the row was updated by the current transaction, and
     159             :  *      (Xmax is null                       it was not deleted
     160             :  *       [|| Xmax != my-transaction)])          [or it was deleted by another transaction]
     161             :  * ||
     162             :  *
     163             :  * (Xmin is committed &&                    the row was modified by a committed transaction, and
     164             :  *      (Xmax is null ||                    the row has not been deleted, or
     165             :  *          (Xmax != my-transaction &&          the row was deleted by another transaction
     166             :  *           Xmax is not committed)))           that has not been committed
     167             :  */
     168             : static bool
     169        3186 : HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
     170             : {
     171        3186 :     HeapTupleHeader tuple = htup->t_data;
     172             : 
     173             :     Assert(ItemPointerIsValid(&htup->t_self));
     174             :     Assert(htup->t_tableOid != InvalidOid);
     175             : 
     176        3186 :     if (!HeapTupleHeaderXminCommitted(tuple))
     177             :     {
     178        3142 :         if (HeapTupleHeaderXminInvalid(tuple))
     179           0 :             return false;
     180             : 
     181             :         /* Used by pre-9.0 binary upgrades */
     182        3142 :         if (tuple->t_infomask & HEAP_MOVED_OFF)
     183             :         {
     184           0 :             TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
     185             : 
     186           0 :             if (TransactionIdIsCurrentTransactionId(xvac))
     187           0 :                 return false;
     188           0 :             if (!TransactionIdIsInProgress(xvac))
     189             :             {
     190           0 :                 if (TransactionIdDidCommit(xvac))
     191             :                 {
     192           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
     193             :                                 InvalidTransactionId);
     194           0 :                     return false;
     195             :                 }
     196           0 :                 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
     197             :                             InvalidTransactionId);
     198             :             }
     199             :         }
     200             :         /* Used by pre-9.0 binary upgrades */
     201        3142 :         else if (tuple->t_infomask & HEAP_MOVED_IN)
     202             :         {
     203           0 :             TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
     204             : 
     205           0 :             if (!TransactionIdIsCurrentTransactionId(xvac))
     206             :             {
     207           0 :                 if (TransactionIdIsInProgress(xvac))
     208           0 :                     return false;
     209           0 :                 if (TransactionIdDidCommit(xvac))
     210           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
     211             :                                 InvalidTransactionId);
     212             :                 else
     213             :                 {
     214           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
     215             :                                 InvalidTransactionId);
     216           0 :                     return false;
     217             :                 }
     218             :             }
     219             :         }
     220        3142 :         else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
     221             :         {
     222        3142 :             if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid */
     223        3060 :                 return true;
     224             : 
     225          82 :             if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
     226          14 :                 return true;
     227             : 
     228          68 :             if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
     229             :             {
     230             :                 TransactionId xmax;
     231             : 
     232           0 :                 xmax = HeapTupleGetUpdateXid(tuple);
     233             : 
     234             :                 /* not LOCKED_ONLY, so it has to have an xmax */
     235             :                 Assert(TransactionIdIsValid(xmax));
     236             : 
     237             :                 /* updating subtransaction must have aborted */
     238           0 :                 if (!TransactionIdIsCurrentTransactionId(xmax))
     239           0 :                     return true;
     240             :                 else
     241           0 :                     return false;
     242             :             }
     243             : 
     244          68 :             if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
     245             :             {
     246             :                 /* deleting subtransaction must have aborted */
     247          12 :                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
     248             :                             InvalidTransactionId);
     249          12 :                 return true;
     250             :             }
     251             : 
     252          56 :             return false;
     253             :         }
     254           0 :         else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
     255           0 :             return false;
     256           0 :         else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
     257           0 :             SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
     258             :                         HeapTupleHeaderGetRawXmin(tuple));
     259             :         else
     260             :         {
     261             :             /* it must have aborted or crashed */
     262           0 :             SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
     263             :                         InvalidTransactionId);
     264           0 :             return false;
     265             :         }
     266             :     }
     267             : 
     268             :     /* by here, the inserting transaction has committed */
     269             : 
     270          44 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid or aborted */
     271          44 :         return true;
     272             : 
     273           0 :     if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
     274             :     {
     275           0 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
     276           0 :             return true;
     277           0 :         return false;           /* updated by other */
     278             :     }
     279             : 
     280           0 :     if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
     281             :     {
     282             :         TransactionId xmax;
     283             : 
     284           0 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
     285           0 :             return true;
     286             : 
     287           0 :         xmax = HeapTupleGetUpdateXid(tuple);
     288             : 
     289             :         /* not LOCKED_ONLY, so it has to have an xmax */
     290             :         Assert(TransactionIdIsValid(xmax));
     291             : 
     292           0 :         if (TransactionIdIsCurrentTransactionId(xmax))
     293           0 :             return false;
     294           0 :         if (TransactionIdIsInProgress(xmax))
     295           0 :             return true;
     296           0 :         if (TransactionIdDidCommit(xmax))
     297           0 :             return false;
     298             :         /* it must have aborted or crashed */
     299           0 :         return true;
     300             :     }
     301             : 
     302           0 :     if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
     303             :     {
     304           0 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
     305           0 :             return true;
     306           0 :         return false;
     307             :     }
     308             : 
     309           0 :     if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
     310           0 :         return true;
     311             : 
     312           0 :     if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
     313             :     {
     314             :         /* it must have aborted or crashed */
     315           0 :         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
     316             :                     InvalidTransactionId);
     317           0 :         return true;
     318             :     }
     319             : 
     320             :     /* xmax transaction committed */
     321             : 
     322           0 :     if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
     323             :     {
     324           0 :         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
     325             :                     InvalidTransactionId);
     326           0 :         return true;
     327             :     }
     328             : 
     329           0 :     SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
     330             :                 HeapTupleHeaderGetRawXmax(tuple));
     331           0 :     return false;
     332             : }
     333             : 
     334             : /*
     335             :  * HeapTupleSatisfiesAny
     336             :  *      Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
     337             :  */
     338             : static bool
     339    11837428 : HeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer)
     340             : {
     341    11837428 :     return true;
     342             : }
     343             : 
     344             : /*
     345             :  * HeapTupleSatisfiesToast
     346             :  *      True iff heap tuple is valid as a TOAST row.
     347             :  *
     348             :  * See SNAPSHOT_TOAST's definition for the intended behaviour.
     349             :  *
     350             :  * This is a simplified version that only checks for VACUUM moving conditions.
     351             :  * It's appropriate for TOAST usage because TOAST really doesn't want to do
     352             :  * its own time qual checks; if you can see the main table row that contains
     353             :  * a TOAST reference, you should be able to see the TOASTed value.  However,
     354             :  * vacuuming a TOAST table is independent of the main table, and in case such
     355             :  * a vacuum fails partway through, we'd better do this much checking.
     356             :  *
     357             :  * Among other things, this means you can't do UPDATEs of rows in a TOAST
     358             :  * table.
     359             :  */
     360             : static bool
     361      123952 : HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot,
     362             :                         Buffer buffer)
     363             : {
     364      123952 :     HeapTupleHeader tuple = htup->t_data;
     365             : 
     366             :     Assert(ItemPointerIsValid(&htup->t_self));
     367             :     Assert(htup->t_tableOid != InvalidOid);
     368             : 
     369      123952 :     if (!HeapTupleHeaderXminCommitted(tuple))
     370             :     {
     371      117352 :         if (HeapTupleHeaderXminInvalid(tuple))
     372           0 :             return false;
     373             : 
     374             :         /* Used by pre-9.0 binary upgrades */
     375      117352 :         if (tuple->t_infomask & HEAP_MOVED_OFF)
     376             :         {
     377           0 :             TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
     378             : 
     379           0 :             if (TransactionIdIsCurrentTransactionId(xvac))
     380           0 :                 return false;
     381           0 :             if (!TransactionIdIsInProgress(xvac))
     382             :             {
     383           0 :                 if (TransactionIdDidCommit(xvac))
     384             :                 {
     385           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
     386             :                                 InvalidTransactionId);
     387           0 :                     return false;
     388             :                 }
     389           0 :                 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
     390             :                             InvalidTransactionId);
     391             :             }
     392             :         }
     393             :         /* Used by pre-9.0 binary upgrades */
     394      117352 :         else if (tuple->t_infomask & HEAP_MOVED_IN)
     395             :         {
     396           0 :             TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
     397             : 
     398           0 :             if (!TransactionIdIsCurrentTransactionId(xvac))
     399             :             {
     400           0 :                 if (TransactionIdIsInProgress(xvac))
     401           0 :                     return false;
     402           0 :                 if (TransactionIdDidCommit(xvac))
     403           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
     404             :                                 InvalidTransactionId);
     405             :                 else
     406             :                 {
     407           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
     408             :                                 InvalidTransactionId);
     409           0 :                     return false;
     410             :                 }
     411             :             }
     412             :         }
     413             : 
     414             :         /*
     415             :          * An invalid Xmin can be left behind by a speculative insertion that
     416             :          * is canceled by super-deleting the tuple.  This also applies to
     417             :          * TOAST tuples created during speculative insertion.
     418             :          */
     419      117352 :         else if (!TransactionIdIsValid(HeapTupleHeaderGetXmin(tuple)))
     420           0 :             return false;
     421             :     }
     422             : 
     423             :     /* otherwise assume the tuple is valid for TOAST. */
     424      123952 :     return true;
     425             : }
     426             : 
     427             : /*
     428             :  * HeapTupleSatisfiesUpdate
     429             :  *
     430             :  *  This function returns a more detailed result code than most of the
     431             :  *  functions in this file, since UPDATE needs to know more than "is it
     432             :  *  visible?".  It also allows for user-supplied CommandId rather than
     433             :  *  relying on CurrentCommandId.
     434             :  *
     435             :  *  The possible return codes are:
     436             :  *
     437             :  *  TM_Invisible: the tuple didn't exist at all when the scan started, e.g. it
     438             :  *  was created by a later CommandId.
     439             :  *
     440             :  *  TM_Ok: The tuple is valid and visible, so it may be updated.
     441             :  *
     442             :  *  TM_SelfModified: The tuple was updated by the current transaction, after
     443             :  *  the current scan started.
     444             :  *
     445             :  *  TM_Updated: The tuple was updated by a committed transaction (including
     446             :  *  the case where the tuple was moved into a different partition).
     447             :  *
     448             :  *  TM_Deleted: The tuple was deleted by a committed transaction.
     449             :  *
     450             :  *  TM_BeingModified: The tuple is being updated by an in-progress transaction
     451             :  *  other than the current transaction.  (Note: this includes the case where
     452             :  *  the tuple is share-locked by a MultiXact, even if the MultiXact includes
     453             :  *  the current transaction.  Callers that want to distinguish that case must
     454             :  *  test for it themselves.)
     455             :  */
     456             : TM_Result
     457     1894296 : HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
     458             :                          Buffer buffer)
     459             : {
     460     1894296 :     HeapTupleHeader tuple = htup->t_data;
     461             : 
     462             :     Assert(ItemPointerIsValid(&htup->t_self));
     463             :     Assert(htup->t_tableOid != InvalidOid);
     464             : 
     465     1894296 :     if (!HeapTupleHeaderXminCommitted(tuple))
     466             :     {
     467      128278 :         if (HeapTupleHeaderXminInvalid(tuple))
     468           0 :             return TM_Invisible;
     469             : 
     470             :         /* Used by pre-9.0 binary upgrades */
     471      128278 :         if (tuple->t_infomask & HEAP_MOVED_OFF)
     472             :         {
     473           0 :             TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
     474             : 
     475           0 :             if (TransactionIdIsCurrentTransactionId(xvac))
     476           0 :                 return TM_Invisible;
     477           0 :             if (!TransactionIdIsInProgress(xvac))
     478             :             {
     479           0 :                 if (TransactionIdDidCommit(xvac))
     480             :                 {
     481           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
     482             :                                 InvalidTransactionId);
     483           0 :                     return TM_Invisible;
     484             :                 }
     485           0 :                 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
     486             :                             InvalidTransactionId);
     487             :             }
     488             :         }
     489             :         /* Used by pre-9.0 binary upgrades */
     490      128278 :         else if (tuple->t_infomask & HEAP_MOVED_IN)
     491             :         {
     492           0 :             TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
     493             : 
     494           0 :             if (!TransactionIdIsCurrentTransactionId(xvac))
     495             :             {
     496           0 :                 if (TransactionIdIsInProgress(xvac))
     497           0 :                     return TM_Invisible;
     498           0 :                 if (TransactionIdDidCommit(xvac))
     499           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
     500             :                                 InvalidTransactionId);
     501             :                 else
     502             :                 {
     503           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
     504             :                                 InvalidTransactionId);
     505           0 :                     return TM_Invisible;
     506             :                 }
     507             :             }
     508             :         }
     509      128278 :         else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
     510             :         {
     511      126054 :             if (HeapTupleHeaderGetCmin(tuple) >= curcid)
     512          16 :                 return TM_Invisible;    /* inserted after scan started */
     513             : 
     514      126038 :             if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid */
     515      125884 :                 return TM_Ok;
     516             : 
     517         154 :             if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
     518             :             {
     519             :                 TransactionId xmax;
     520             : 
     521         138 :                 xmax = HeapTupleHeaderGetRawXmax(tuple);
     522             : 
     523             :                 /*
     524             :                  * Careful here: even though this tuple was created by our own
     525             :                  * transaction, it might be locked by other transactions, if
     526             :                  * the original version was key-share locked when we updated
     527             :                  * it.
     528             :                  */
     529             : 
     530         138 :                 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
     531             :                 {
     532          10 :                     if (MultiXactIdIsRunning(xmax, true))
     533          10 :                         return TM_BeingModified;
     534             :                     else
     535           0 :                         return TM_Ok;
     536             :                 }
     537             : 
     538             :                 /*
     539             :                  * If the locker is gone, then there is nothing of interest
     540             :                  * left in this Xmax; otherwise, report the tuple as
     541             :                  * locked/updated.
     542             :                  */
     543         128 :                 if (!TransactionIdIsInProgress(xmax))
     544           0 :                     return TM_Ok;
     545         128 :                 return TM_BeingModified;
     546             :             }
     547             : 
     548          16 :             if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
     549             :             {
     550             :                 TransactionId xmax;
     551             : 
     552          12 :                 xmax = HeapTupleGetUpdateXid(tuple);
     553             : 
     554             :                 /* not LOCKED_ONLY, so it has to have an xmax */
     555             :                 Assert(TransactionIdIsValid(xmax));
     556             : 
     557             :                 /* deleting subtransaction must have aborted */
     558          12 :                 if (!TransactionIdIsCurrentTransactionId(xmax))
     559             :                 {
     560          12 :                     if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),
     561             :                                              false))
     562          12 :                         return TM_BeingModified;
     563           0 :                     return TM_Ok;
     564             :                 }
     565             :                 else
     566             :                 {
     567           0 :                     if (HeapTupleHeaderGetCmax(tuple) >= curcid)
     568           0 :                         return TM_SelfModified; /* updated after scan started */
     569             :                     else
     570           0 :                         return TM_Invisible;    /* updated before scan started */
     571             :                 }
     572             :             }
     573             : 
     574           4 :             if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
     575             :             {
     576             :                 /* deleting subtransaction must have aborted */
     577           0 :                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
     578             :                             InvalidTransactionId);
     579           0 :                 return TM_Ok;
     580             :             }
     581             : 
     582           4 :             if (HeapTupleHeaderGetCmax(tuple) >= curcid)
     583           4 :                 return TM_SelfModified; /* updated after scan started */
     584             :             else
     585           0 :                 return TM_Invisible;    /* updated before scan started */
     586             :         }
     587        2224 :         else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
     588           0 :             return TM_Invisible;
     589        2224 :         else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
     590        2224 :             SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
     591             :                         HeapTupleHeaderGetRawXmin(tuple));
     592             :         else
     593             :         {
     594             :             /* it must have aborted or crashed */
     595           0 :             SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
     596             :                         InvalidTransactionId);
     597           0 :             return TM_Invisible;
     598             :         }
     599             :     }
     600             : 
     601             :     /* by here, the inserting transaction has committed */
     602             : 
     603     1768242 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid or aborted */
     604     1753684 :         return TM_Ok;
     605             : 
     606       14558 :     if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
     607             :     {
     608         142 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
     609           0 :             return TM_Ok;
     610         142 :         if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid) ||
     611           0 :             HeapTupleHeaderIndicatesMovedPartitions(tuple))
     612         142 :             return TM_Updated;  /* updated by other */
     613             :         else
     614           0 :             return TM_Deleted;  /* deleted by other */
     615             :     }
     616             : 
     617       14416 :     if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
     618             :     {
     619             :         TransactionId xmax;
     620             : 
     621        1118 :         if (HEAP_LOCKED_UPGRADED(tuple->t_infomask))
     622           0 :             return TM_Ok;
     623             : 
     624        1118 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
     625             :         {
     626        1048 :             if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), true))
     627         200 :                 return TM_BeingModified;
     628             : 
     629         848 :             SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
     630         848 :             return TM_Ok;
     631             :         }
     632             : 
     633          70 :         xmax = HeapTupleGetUpdateXid(tuple);
     634          70 :         if (!TransactionIdIsValid(xmax))
     635             :         {
     636           0 :             if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
     637           0 :                 return TM_BeingModified;
     638             :         }
     639             : 
     640             :         /* not LOCKED_ONLY, so it has to have an xmax */
     641             :         Assert(TransactionIdIsValid(xmax));
     642             : 
     643          70 :         if (TransactionIdIsCurrentTransactionId(xmax))
     644             :         {
     645           0 :             if (HeapTupleHeaderGetCmax(tuple) >= curcid)
     646           0 :                 return TM_SelfModified; /* updated after scan started */
     647             :             else
     648           0 :                 return TM_Invisible;    /* updated before scan started */
     649             :         }
     650             : 
     651          70 :         if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
     652          58 :             return TM_BeingModified;
     653             : 
     654          12 :         if (TransactionIdDidCommit(xmax))
     655             :         {
     656           4 :             if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid) ||
     657           2 :                 HeapTupleHeaderIndicatesMovedPartitions(tuple))
     658           0 :                 return TM_Updated;
     659             :             else
     660           2 :                 return TM_Deleted;
     661             :         }
     662             : 
     663             :         /*
     664             :          * By here, the update in the Xmax is either aborted or crashed, but
     665             :          * what about the other members?
     666             :          */
     667             : 
     668          10 :         if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
     669             :         {
     670             :             /*
     671             :              * There's no member, even just a locker, alive anymore, so we can
     672             :              * mark the Xmax as invalid.
     673             :              */
     674          10 :             SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
     675             :                         InvalidTransactionId);
     676          10 :             return TM_Ok;
     677             :         }
     678             :         else
     679             :         {
     680             :             /* There are lockers running */
     681           0 :             return TM_BeingModified;
     682             :         }
     683             :     }
     684             : 
     685       13298 :     if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
     686             :     {
     687        8686 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
     688        8606 :             return TM_BeingModified;
     689          80 :         if (HeapTupleHeaderGetCmax(tuple) >= curcid)
     690          80 :             return TM_SelfModified; /* updated after scan started */
     691             :         else
     692           0 :             return TM_Invisible;    /* updated before scan started */
     693             :     }
     694             : 
     695        4612 :     if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
     696        2180 :         return TM_BeingModified;
     697             : 
     698        2432 :     if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
     699             :     {
     700             :         /* it must have aborted or crashed */
     701         134 :         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
     702             :                     InvalidTransactionId);
     703         134 :         return TM_Ok;
     704             :     }
     705             : 
     706             :     /* xmax transaction committed */
     707             : 
     708        2298 :     if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
     709             :     {
     710        2254 :         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
     711             :                     InvalidTransactionId);
     712        2254 :         return TM_Ok;
     713             :     }
     714             : 
     715          44 :     SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
     716             :                 HeapTupleHeaderGetRawXmax(tuple));
     717          44 :     if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid) ||
     718           0 :         HeapTupleHeaderIndicatesMovedPartitions(tuple))
     719          44 :         return TM_Updated;      /* updated by other */
     720             :     else
     721           0 :         return TM_Deleted;      /* deleted by other */
     722             : }
     723             : 
     724             : /*
     725             :  * HeapTupleSatisfiesDirty
     726             :  *      True iff heap tuple is valid including effects of open transactions.
     727             :  *
     728             :  * See SNAPSHOT_DIRTY's definition for the intended behaviour.
     729             :  *
     730             :  * This is essentially like HeapTupleSatisfiesSelf as far as effects of
     731             :  * the current transaction and committed/aborted xacts are concerned.
     732             :  * However, we also include the effects of other xacts still in progress.
     733             :  *
     734             :  * A special hack is that the passed-in snapshot struct is used as an
     735             :  * output argument to return the xids of concurrent xacts that affected the
     736             :  * tuple.  snapshot->xmin is set to the tuple's xmin if that is another
     737             :  * transaction that's still in progress; or to InvalidTransactionId if the
     738             :  * tuple's xmin is committed good, committed dead, or my own xact.
     739             :  * Similarly for snapshot->xmax and the tuple's xmax.  If the tuple was
     740             :  * inserted speculatively, meaning that the inserter might still back down
     741             :  * on the insertion without aborting the whole transaction, the associated
     742             :  * token is also returned in snapshot->speculativeToken.
     743             :  */
     744             : static bool
     745      473448 : HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
     746             :                         Buffer buffer)
     747             : {
     748      473448 :     HeapTupleHeader tuple = htup->t_data;
     749             : 
     750             :     Assert(ItemPointerIsValid(&htup->t_self));
     751             :     Assert(htup->t_tableOid != InvalidOid);
     752             : 
     753      473448 :     snapshot->xmin = snapshot->xmax = InvalidTransactionId;
     754      473448 :     snapshot->speculativeToken = 0;
     755             : 
     756      473448 :     if (!HeapTupleHeaderXminCommitted(tuple))
     757             :     {
     758       28444 :         if (HeapTupleHeaderXminInvalid(tuple))
     759         248 :             return false;
     760             : 
     761             :         /* Used by pre-9.0 binary upgrades */
     762       28196 :         if (tuple->t_infomask & HEAP_MOVED_OFF)
     763             :         {
     764           0 :             TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
     765             : 
     766           0 :             if (TransactionIdIsCurrentTransactionId(xvac))
     767           0 :                 return false;
     768           0 :             if (!TransactionIdIsInProgress(xvac))
     769             :             {
     770           0 :                 if (TransactionIdDidCommit(xvac))
     771             :                 {
     772           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
     773             :                                 InvalidTransactionId);
     774           0 :                     return false;
     775             :                 }
     776           0 :                 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
     777             :                             InvalidTransactionId);
     778             :             }
     779             :         }
     780             :         /* Used by pre-9.0 binary upgrades */
     781       28196 :         else if (tuple->t_infomask & HEAP_MOVED_IN)
     782             :         {
     783           0 :             TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
     784             : 
     785           0 :             if (!TransactionIdIsCurrentTransactionId(xvac))
     786             :             {
     787           0 :                 if (TransactionIdIsInProgress(xvac))
     788           0 :                     return false;
     789           0 :                 if (TransactionIdDidCommit(xvac))
     790           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
     791             :                                 InvalidTransactionId);
     792             :                 else
     793             :                 {
     794           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
     795             :                                 InvalidTransactionId);
     796           0 :                     return false;
     797             :                 }
     798             :             }
     799             :         }
     800       28196 :         else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
     801             :         {
     802       22298 :             if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid */
     803         252 :                 return true;
     804             : 
     805       22046 :             if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
     806         310 :                 return true;
     807             : 
     808       21736 :             if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
     809             :             {
     810             :                 TransactionId xmax;
     811             : 
     812           0 :                 xmax = HeapTupleGetUpdateXid(tuple);
     813             : 
     814             :                 /* not LOCKED_ONLY, so it has to have an xmax */
     815             :                 Assert(TransactionIdIsValid(xmax));
     816             : 
     817             :                 /* updating subtransaction must have aborted */
     818           0 :                 if (!TransactionIdIsCurrentTransactionId(xmax))
     819           0 :                     return true;
     820             :                 else
     821           0 :                     return false;
     822             :             }
     823             : 
     824       21736 :             if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
     825             :             {
     826             :                 /* deleting subtransaction must have aborted */
     827           0 :                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
     828             :                             InvalidTransactionId);
     829           0 :                 return true;
     830             :             }
     831             : 
     832       21736 :             return false;
     833             :         }
     834        5898 :         else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
     835             :         {
     836             :             /*
     837             :              * Return the speculative token to caller.  Caller can worry about
     838             :              * xmax, since it requires a conclusively locked row version, and
     839             :              * a concurrent update to this tuple is a conflict of its
     840             :              * purposes.
     841             :              */
     842          64 :             if (HeapTupleHeaderIsSpeculative(tuple))
     843             :             {
     844           0 :                 snapshot->speculativeToken =
     845           0 :                     HeapTupleHeaderGetSpeculativeToken(tuple);
     846             : 
     847             :                 Assert(snapshot->speculativeToken != 0);
     848             :             }
     849             : 
     850          64 :             snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
     851             :             /* XXX shouldn't we fall through to look at xmax? */
     852          64 :             return true;        /* in insertion by other */
     853             :         }
     854        5834 :         else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
     855        5568 :             SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
     856             :                         HeapTupleHeaderGetRawXmin(tuple));
     857             :         else
     858             :         {
     859             :             /* it must have aborted or crashed */
     860         266 :             SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
     861             :                         InvalidTransactionId);
     862         266 :             return false;
     863             :         }
     864             :     }
     865             : 
     866             :     /* by here, the inserting transaction has committed */
     867             : 
     868      450572 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid or aborted */
     869      226756 :         return true;
     870             : 
     871      223816 :     if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
     872             :     {
     873       59682 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
     874           0 :             return true;
     875       59682 :         return false;           /* updated by other */
     876             :     }
     877             : 
     878      164134 :     if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
     879             :     {
     880             :         TransactionId xmax;
     881             : 
     882          32 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
     883          18 :             return true;
     884             : 
     885          14 :         xmax = HeapTupleGetUpdateXid(tuple);
     886             : 
     887             :         /* not LOCKED_ONLY, so it has to have an xmax */
     888             :         Assert(TransactionIdIsValid(xmax));
     889             : 
     890          14 :         if (TransactionIdIsCurrentTransactionId(xmax))
     891           2 :             return false;
     892          12 :         if (TransactionIdIsInProgress(xmax))
     893             :         {
     894           0 :             snapshot->xmax = xmax;
     895           0 :             return true;
     896             :         }
     897          12 :         if (TransactionIdDidCommit(xmax))
     898          12 :             return false;
     899             :         /* it must have aborted or crashed */
     900           0 :         return true;
     901             :     }
     902             : 
     903      164102 :     if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
     904             :     {
     905      163316 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
     906          38 :             return true;
     907      163278 :         return false;
     908             :     }
     909             : 
     910         786 :     if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
     911             :     {
     912          28 :         if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
     913          24 :             snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
     914          28 :         return true;
     915             :     }
     916             : 
     917         758 :     if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
     918             :     {
     919             :         /* it must have aborted or crashed */
     920          12 :         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
     921             :                     InvalidTransactionId);
     922          12 :         return true;
     923             :     }
     924             : 
     925             :     /* xmax transaction committed */
     926             : 
     927         746 :     if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
     928             :     {
     929         198 :         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
     930             :                     InvalidTransactionId);
     931         198 :         return true;
     932             :     }
     933             : 
     934         548 :     SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
     935             :                 HeapTupleHeaderGetRawXmax(tuple));
     936         548 :     return false;               /* updated by other */
     937             : }
     938             : 
     939             : /*
     940             :  * HeapTupleSatisfiesMVCC
     941             :  *      True iff heap tuple is valid for the given MVCC snapshot.
     942             :  *
     943             :  * See SNAPSHOT_MVCC's definition for the intended behaviour.
     944             :  *
     945             :  * Notice that here, we will not update the tuple status hint bits if the
     946             :  * inserting/deleting transaction is still running according to our snapshot,
     947             :  * even if in reality it's committed or aborted by now.  This is intentional.
     948             :  * Checking the true transaction state would require access to high-traffic
     949             :  * shared data structures, creating contention we'd rather do without, and it
     950             :  * would not change the result of our visibility check anyway.  The hint bits
     951             :  * will be updated by the first visitor that has a snapshot new enough to see
     952             :  * the inserting/deleting transaction as done.  In the meantime, the cost of
     953             :  * leaving the hint bits unset is basically that each HeapTupleSatisfiesMVCC
     954             :  * call will need to run TransactionIdIsCurrentTransactionId in addition to
     955             :  * XidInMVCCSnapshot (but it would have to do the latter anyway).  In the old
     956             :  * coding where we tried to set the hint bits as soon as possible, we instead
     957             :  * did TransactionIdIsInProgress in each call --- to no avail, as long as the
     958             :  * inserting/deleting transaction was still running --- which was more cycles
     959             :  * and more contention on the PGXACT array.
     960             :  */
     961             : static bool
     962   186806914 : HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
     963             :                        Buffer buffer)
     964             : {
     965   186806914 :     HeapTupleHeader tuple = htup->t_data;
     966             : 
     967             :     Assert(ItemPointerIsValid(&htup->t_self));
     968             :     Assert(htup->t_tableOid != InvalidOid);
     969             : 
     970   186806914 :     if (!HeapTupleHeaderXminCommitted(tuple))
     971             :     {
     972    17907092 :         if (HeapTupleHeaderXminInvalid(tuple))
     973      109966 :             return false;
     974             : 
     975             :         /* Used by pre-9.0 binary upgrades */
     976    17797126 :         if (tuple->t_infomask & HEAP_MOVED_OFF)
     977             :         {
     978           0 :             TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
     979             : 
     980           0 :             if (TransactionIdIsCurrentTransactionId(xvac))
     981           0 :                 return false;
     982           0 :             if (!XidInMVCCSnapshot(xvac, snapshot))
     983             :             {
     984           0 :                 if (TransactionIdDidCommit(xvac))
     985             :                 {
     986           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
     987             :                                 InvalidTransactionId);
     988           0 :                     return false;
     989             :                 }
     990           0 :                 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
     991             :                             InvalidTransactionId);
     992             :             }
     993             :         }
     994             :         /* Used by pre-9.0 binary upgrades */
     995    17797126 :         else if (tuple->t_infomask & HEAP_MOVED_IN)
     996             :         {
     997           0 :             TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
     998             : 
     999           0 :             if (!TransactionIdIsCurrentTransactionId(xvac))
    1000             :             {
    1001           0 :                 if (XidInMVCCSnapshot(xvac, snapshot))
    1002           0 :                     return false;
    1003           0 :                 if (TransactionIdDidCommit(xvac))
    1004           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
    1005             :                                 InvalidTransactionId);
    1006             :                 else
    1007             :                 {
    1008           0 :                     SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
    1009             :                                 InvalidTransactionId);
    1010           0 :                     return false;
    1011             :                 }
    1012             :             }
    1013             :         }
    1014    17797126 :         else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
    1015             :         {
    1016     9929860 :             if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
    1017       29942 :                 return false;   /* inserted after scan started */
    1018             : 
    1019     9899918 :             if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid */
    1020     9765628 :                 return true;
    1021             : 
    1022      134290 :             if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
    1023        4050 :                 return true;
    1024             : 
    1025      130240 :             if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
    1026             :             {
    1027             :                 TransactionId xmax;
    1028             : 
    1029          12 :                 xmax = HeapTupleGetUpdateXid(tuple);
    1030             : 
    1031             :                 /* not LOCKED_ONLY, so it has to have an xmax */
    1032             :                 Assert(TransactionIdIsValid(xmax));
    1033             : 
    1034             :                 /* updating subtransaction must have aborted */
    1035          12 :                 if (!TransactionIdIsCurrentTransactionId(xmax))
    1036          12 :                     return true;
    1037           0 :                 else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
    1038           0 :                     return true;    /* updated after scan started */
    1039             :                 else
    1040           0 :                     return false;   /* updated before scan started */
    1041             :             }
    1042             : 
    1043      130228 :             if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
    1044             :             {
    1045             :                 /* deleting subtransaction must have aborted */
    1046          12 :                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
    1047             :                             InvalidTransactionId);
    1048          12 :                 return true;
    1049             :             }
    1050             : 
    1051      130216 :             if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
    1052        1872 :                 return true;    /* deleted after scan started */
    1053             :             else
    1054      128344 :                 return false;   /* deleted before scan started */
    1055             :         }
    1056     7867266 :         else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
    1057       10190 :             return false;
    1058     7857076 :         else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
    1059     7847296 :             SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
    1060             :                         HeapTupleHeaderGetRawXmin(tuple));
    1061             :         else
    1062             :         {
    1063             :             /* it must have aborted or crashed */
    1064        9780 :             SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
    1065             :                         InvalidTransactionId);
    1066        9780 :             return false;
    1067             :         }
    1068             :     }
    1069             :     else
    1070             :     {
    1071             :         /* xmin is committed, but maybe not according to our snapshot */
    1072   334604122 :         if (!HeapTupleHeaderXminFrozen(tuple) &&
    1073   165704300 :             XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
    1074         378 :             return false;       /* treat as still in progress */
    1075             :     }
    1076             : 
    1077             :     /* by here, the inserting transaction has committed */
    1078             : 
    1079   176746740 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid or aborted */
    1080   172642110 :         return true;
    1081             : 
    1082     4104630 :     if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
    1083       43774 :         return true;
    1084             : 
    1085     4060856 :     if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
    1086             :     {
    1087             :         TransactionId xmax;
    1088             : 
    1089             :         /* already checked above */
    1090             :         Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
    1091             : 
    1092         274 :         xmax = HeapTupleGetUpdateXid(tuple);
    1093             : 
    1094             :         /* not LOCKED_ONLY, so it has to have an xmax */
    1095             :         Assert(TransactionIdIsValid(xmax));
    1096             : 
    1097         274 :         if (TransactionIdIsCurrentTransactionId(xmax))
    1098             :         {
    1099          46 :             if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
    1100           0 :                 return true;    /* deleted after scan started */
    1101             :             else
    1102          46 :                 return false;   /* deleted before scan started */
    1103             :         }
    1104         228 :         if (XidInMVCCSnapshot(xmax, snapshot))
    1105          32 :             return true;
    1106         196 :         if (TransactionIdDidCommit(xmax))
    1107         186 :             return false;       /* updating transaction committed */
    1108             :         /* it must have aborted or crashed */
    1109          10 :         return true;
    1110             :     }
    1111             : 
    1112     4060582 :     if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
    1113             :     {
    1114      415774 :         if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
    1115             :         {
    1116      110034 :             if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
    1117         830 :                 return true;    /* deleted after scan started */
    1118             :             else
    1119      109204 :                 return false;   /* deleted before scan started */
    1120             :         }
    1121             : 
    1122      305740 :         if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
    1123        4318 :             return true;
    1124             : 
    1125      301422 :         if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
    1126             :         {
    1127             :             /* it must have aborted or crashed */
    1128        3310 :             SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
    1129             :                         InvalidTransactionId);
    1130        3310 :             return true;
    1131             :         }
    1132             : 
    1133             :         /* xmax transaction committed */
    1134      298112 :         SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
    1135             :                     HeapTupleHeaderGetRawXmax(tuple));
    1136             :     }
    1137             :     else
    1138             :     {
    1139             :         /* xmax is committed, but maybe not according to our snapshot */
    1140     3644808 :         if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
    1141          54 :             return true;        /* treat as still in progress */
    1142             :     }
    1143             : 
    1144             :     /* xmax transaction committed */
    1145             : 
    1146     3942866 :     return false;
    1147             : }
    1148             : 
    1149             : 
    1150             : /*
    1151             :  * HeapTupleSatisfiesVacuum
    1152             :  *
    1153             :  *  Determine the status of tuples for VACUUM purposes.  Here, what
    1154             :  *  we mainly want to know is if a tuple is potentially visible to *any*
    1155             :  *  running transaction.  If so, it can't be removed yet by VACUUM.
    1156             :  *
    1157             :  * OldestXmin is a cutoff XID (obtained from GetOldestXmin()).  Tuples
    1158             :  * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might
    1159             :  * still be visible to some open transaction, so we can't remove them,
    1160             :  * even if we see that the deleting transaction has committed.
    1161             :  */
    1162             : HTSV_Result
    1163    53017204 : HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin,
    1164             :                          Buffer buffer)
    1165             : {
    1166    53017204 :     HeapTupleHeader tuple = htup->t_data;
    1167             : 
    1168             :     Assert(ItemPointerIsValid(&htup->t_self));
    1169             :     Assert(htup->t_tableOid != InvalidOid);
    1170             : 
    1171             :     /*
    1172             :      * Has inserting transaction committed?
    1173             :      *
    1174             :      * If the inserting transaction aborted, then the tuple was never visible
    1175             :      * to any other transaction, so we can delete it immediately.
    1176             :      */
    1177    53017204 :     if (!HeapTupleHeaderXminCommitted(tuple))
    1178             :     {
    1179    11479320 :         if (HeapTupleHeaderXminInvalid(tuple))
    1180        8058 :             return HEAPTUPLE_DEAD;
    1181             :         /* Used by pre-9.0 binary upgrades */
    1182    11471262 :         else if (tuple->t_infomask & HEAP_MOVED_OFF)
    1183             :         {
    1184           0 :             TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
    1185             : 
    1186           0 :             if (TransactionIdIsCurrentTransactionId(xvac))
    1187           0 :                 return HEAPTUPLE_DELETE_IN_PROGRESS;
    1188           0 :             if (TransactionIdIsInProgress(xvac))
    1189           0 :                 return HEAPTUPLE_DELETE_IN_PROGRESS;
    1190           0 :             if (TransactionIdDidCommit(xvac))
    1191             :             {
    1192           0 :                 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
    1193             :                             InvalidTransactionId);
    1194           0 :                 return HEAPTUPLE_DEAD;
    1195             :             }
    1196           0 :             SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
    1197             :                         InvalidTransactionId);
    1198             :         }
    1199             :         /* Used by pre-9.0 binary upgrades */
    1200    11471262 :         else if (tuple->t_infomask & HEAP_MOVED_IN)
    1201             :         {
    1202           0 :             TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
    1203             : 
    1204           0 :             if (TransactionIdIsCurrentTransactionId(xvac))
    1205           0 :                 return HEAPTUPLE_INSERT_IN_PROGRESS;
    1206           0 :             if (TransactionIdIsInProgress(xvac))
    1207           0 :                 return HEAPTUPLE_INSERT_IN_PROGRESS;
    1208           0 :             if (TransactionIdDidCommit(xvac))
    1209           0 :                 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
    1210             :                             InvalidTransactionId);
    1211             :             else
    1212             :             {
    1213           0 :                 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
    1214             :                             InvalidTransactionId);
    1215           0 :                 return HEAPTUPLE_DEAD;
    1216             :             }
    1217             :         }
    1218    11471262 :         else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
    1219             :         {
    1220     3526902 :             if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid */
    1221     3520582 :                 return HEAPTUPLE_INSERT_IN_PROGRESS;
    1222             :             /* only locked? run infomask-only check first, for performance */
    1223       12534 :             if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) ||
    1224        6214 :                 HeapTupleHeaderIsOnlyLocked(tuple))
    1225         106 :                 return HEAPTUPLE_INSERT_IN_PROGRESS;
    1226             :             /* inserted and then deleted by same xact */
    1227        6214 :             if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple)))
    1228        6214 :                 return HEAPTUPLE_DELETE_IN_PROGRESS;
    1229             :             /* deleting subtransaction must have aborted */
    1230           0 :             return HEAPTUPLE_INSERT_IN_PROGRESS;
    1231             :         }
    1232     7944360 :         else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
    1233             :         {
    1234             :             /*
    1235             :              * It'd be possible to discern between INSERT/DELETE in progress
    1236             :              * here by looking at xmax - but that doesn't seem beneficial for
    1237             :              * the majority of callers and even detrimental for some. We'd
    1238             :              * rather have callers look at/wait for xmin than xmax. It's
    1239             :              * always correct to return INSERT_IN_PROGRESS because that's
    1240             :              * what's happening from the view of other backends.
    1241             :              */
    1242       16918 :             return HEAPTUPLE_INSERT_IN_PROGRESS;
    1243             :         }
    1244     7927442 :         else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
    1245     7910154 :             SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
    1246             :                         HeapTupleHeaderGetRawXmin(tuple));
    1247             :         else
    1248             :         {
    1249             :             /*
    1250             :              * Not in Progress, Not Committed, so either Aborted or crashed
    1251             :              */
    1252       17288 :             SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
    1253             :                         InvalidTransactionId);
    1254       17288 :             return HEAPTUPLE_DEAD;
    1255             :         }
    1256             : 
    1257             :         /*
    1258             :          * At this point the xmin is known committed, but we might not have
    1259             :          * been able to set the hint bit yet; so we can no longer Assert that
    1260             :          * it's set.
    1261             :          */
    1262             :     }
    1263             : 
    1264             :     /*
    1265             :      * Okay, the inserter committed, so it was good at some point.  Now what
    1266             :      * about the deleting transaction?
    1267             :      */
    1268    49448038 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)
    1269    45898644 :         return HEAPTUPLE_LIVE;
    1270             : 
    1271     3549394 :     if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
    1272             :     {
    1273             :         /*
    1274             :          * "Deleting" xact really only locked it, so the tuple is live in any
    1275             :          * case.  However, we should make sure that either XMAX_COMMITTED or
    1276             :          * XMAX_INVALID gets set once the xact is gone, to reduce the costs of
    1277             :          * examining the tuple for future xacts.
    1278             :          */
    1279        3026 :         if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
    1280             :         {
    1281        3026 :             if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
    1282             :             {
    1283             :                 /*
    1284             :                  * If it's a pre-pg_upgrade tuple, the multixact cannot
    1285             :                  * possibly be running; otherwise have to check.
    1286             :                  */
    1287         732 :                 if (!HEAP_LOCKED_UPGRADED(tuple->t_infomask) &&
    1288         366 :                     MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),
    1289             :                                          true))
    1290           4 :                     return HEAPTUPLE_LIVE;
    1291         362 :                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
    1292             :             }
    1293             :             else
    1294             :             {
    1295        2660 :                 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
    1296           0 :                     return HEAPTUPLE_LIVE;
    1297        2660 :                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
    1298             :                             InvalidTransactionId);
    1299             :             }
    1300             :         }
    1301             : 
    1302             :         /*
    1303             :          * We don't really care whether xmax did commit, abort or crash. We
    1304             :          * know that xmax did lock the tuple, but it did not and will never
    1305             :          * actually update it.
    1306             :          */
    1307             : 
    1308        3022 :         return HEAPTUPLE_LIVE;
    1309             :     }
    1310             : 
    1311     3546368 :     if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
    1312             :     {
    1313           4 :         TransactionId xmax = HeapTupleGetUpdateXid(tuple);
    1314             : 
    1315             :         /* already checked above */
    1316             :         Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
    1317             : 
    1318             :         /* not LOCKED_ONLY, so it has to have an xmax */
    1319             :         Assert(TransactionIdIsValid(xmax));
    1320             : 
    1321           4 :         if (TransactionIdIsInProgress(xmax))
    1322           0 :             return HEAPTUPLE_DELETE_IN_PROGRESS;
    1323           4 :         else if (TransactionIdDidCommit(xmax))
    1324             :         {
    1325             :             /*
    1326             :              * The multixact might still be running due to lockers.  If the
    1327             :              * updater is below the xid horizon, we have to return DEAD
    1328             :              * regardless -- otherwise we could end up with a tuple where the
    1329             :              * updater has to be removed due to the horizon, but is not pruned
    1330             :              * away.  It's not a problem to prune that tuple, because any
    1331             :              * remaining lockers will also be present in newer tuple versions.
    1332             :              */
    1333           4 :             if (!TransactionIdPrecedes(xmax, OldestXmin))
    1334           0 :                 return HEAPTUPLE_RECENTLY_DEAD;
    1335             : 
    1336           4 :             return HEAPTUPLE_DEAD;
    1337             :         }
    1338           0 :         else if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
    1339             :         {
    1340             :             /*
    1341             :              * Not in Progress, Not Committed, so either Aborted or crashed.
    1342             :              * Mark the Xmax as invalid.
    1343             :              */
    1344           0 :             SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
    1345             :         }
    1346             : 
    1347           0 :         return HEAPTUPLE_LIVE;
    1348             :     }
    1349             : 
    1350     3546364 :     if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
    1351             :     {
    1352     1264066 :         if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
    1353       11112 :             return HEAPTUPLE_DELETE_IN_PROGRESS;
    1354     1252954 :         else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
    1355     1251236 :             SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
    1356             :                         HeapTupleHeaderGetRawXmax(tuple));
    1357             :         else
    1358             :         {
    1359             :             /*
    1360             :              * Not in Progress, Not Committed, so either Aborted or crashed
    1361             :              */
    1362        1718 :             SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
    1363             :                         InvalidTransactionId);
    1364        1718 :             return HEAPTUPLE_LIVE;
    1365             :         }
    1366             : 
    1367             :         /*
    1368             :          * At this point the xmax is known committed, but we might not have
    1369             :          * been able to set the hint bit yet; so we can no longer Assert that
    1370             :          * it's set.
    1371             :          */
    1372             :     }
    1373             : 
    1374             :     /*
    1375             :      * Deleter committed, but perhaps it was recent enough that some open
    1376             :      * transactions could still see the tuple.
    1377             :      */
    1378     3533534 :     if (!TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin))
    1379     2076824 :         return HEAPTUPLE_RECENTLY_DEAD;
    1380             : 
    1381             :     /* Otherwise, it's dead and removable */
    1382     1456710 :     return HEAPTUPLE_DEAD;
    1383             : }
    1384             : 
    1385             : 
    1386             : /*
    1387             :  * HeapTupleSatisfiesNonVacuumable
    1388             :  *
    1389             :  *  True if tuple might be visible to some transaction; false if it's
    1390             :  *  surely dead to everyone, ie, vacuumable.
    1391             :  *
    1392             :  *  See SNAPSHOT_NON_VACUUMABLE's definition for the intended behaviour.
    1393             :  *
    1394             :  *  This is an interface to HeapTupleSatisfiesVacuum that's callable via
    1395             :  *  HeapTupleSatisfiesSnapshot, so it can be used through a Snapshot.
    1396             :  *  snapshot->xmin must have been set up with the xmin horizon to use.
    1397             :  */
    1398             : static bool
    1399       42216 : HeapTupleSatisfiesNonVacuumable(HeapTuple htup, Snapshot snapshot,
    1400             :                                 Buffer buffer)
    1401             : {
    1402       42216 :     return HeapTupleSatisfiesVacuum(htup, snapshot->xmin, buffer)
    1403       42216 :         != HEAPTUPLE_DEAD;
    1404             : }
    1405             : 
    1406             : 
    1407             : /*
    1408             :  * HeapTupleIsSurelyDead
    1409             :  *
    1410             :  *  Cheaply determine whether a tuple is surely dead to all onlookers.
    1411             :  *  We sometimes use this in lieu of HeapTupleSatisfiesVacuum when the
    1412             :  *  tuple has just been tested by another visibility routine (usually
    1413             :  *  HeapTupleSatisfiesMVCC) and, therefore, any hint bits that can be set
    1414             :  *  should already be set.  We assume that if no hint bits are set, the xmin
    1415             :  *  or xmax transaction is still running.  This is therefore faster than
    1416             :  *  HeapTupleSatisfiesVacuum, because we don't consult PGXACT nor CLOG.
    1417             :  *  It's okay to return false when in doubt, but we must return true only
    1418             :  *  if the tuple is removable.
    1419             :  */
    1420             : bool
    1421      892858 : HeapTupleIsSurelyDead(HeapTuple htup, TransactionId OldestXmin)
    1422             : {
    1423      892858 :     HeapTupleHeader tuple = htup->t_data;
    1424             : 
    1425             :     Assert(ItemPointerIsValid(&htup->t_self));
    1426             :     Assert(htup->t_tableOid != InvalidOid);
    1427             : 
    1428             :     /*
    1429             :      * If the inserting transaction is marked invalid, then it aborted, and
    1430             :      * the tuple is definitely dead.  If it's marked neither committed nor
    1431             :      * invalid, then we assume it's still alive (since the presumption is that
    1432             :      * all relevant hint bits were just set moments ago).
    1433             :      */
    1434      892858 :     if (!HeapTupleHeaderXminCommitted(tuple))
    1435      154008 :         return HeapTupleHeaderXminInvalid(tuple) ? true : false;
    1436             : 
    1437             :     /*
    1438             :      * If the inserting transaction committed, but any deleting transaction
    1439             :      * aborted, the tuple is still alive.
    1440             :      */
    1441      738850 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)
    1442          16 :         return false;
    1443             : 
    1444             :     /*
    1445             :      * If the XMAX is just a lock, the tuple is still alive.
    1446             :      */
    1447      738834 :     if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
    1448           0 :         return false;
    1449             : 
    1450             :     /*
    1451             :      * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
    1452             :      * know without checking pg_multixact.
    1453             :      */
    1454      738834 :     if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
    1455          84 :         return false;
    1456             : 
    1457             :     /* If deleter isn't known to have committed, assume it's still running. */
    1458      738750 :     if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
    1459      248272 :         return false;
    1460             : 
    1461             :     /* Deleter committed, so tuple is dead if the XID is old enough. */
    1462      490478 :     return TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin);
    1463             : }
    1464             : 
    1465             : /*
    1466             :  * Is the tuple really only locked?  That is, is it not updated?
    1467             :  *
    1468             :  * It's easy to check just infomask bits if the locker is not a multi; but
    1469             :  * otherwise we need to verify that the updating transaction has not aborted.
    1470             :  *
    1471             :  * This function is here because it follows the same visibility rules laid out
    1472             :  * at the top of this file.
    1473             :  */
    1474             : bool
    1475       58788 : HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
    1476             : {
    1477             :     TransactionId xmax;
    1478             : 
    1479             :     /* if there's no valid Xmax, then there's obviously no update either */
    1480       58788 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)
    1481           0 :         return true;
    1482             : 
    1483       58788 :     if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
    1484         988 :         return true;
    1485             : 
    1486             :     /* invalid xmax means no update */
    1487       57800 :     if (!TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple)))
    1488           0 :         return true;
    1489             : 
    1490             :     /*
    1491             :      * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
    1492             :      * necessarily have been updated
    1493             :      */
    1494       57800 :     if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
    1495       57750 :         return false;
    1496             : 
    1497             :     /* ... but if it's a multi, then perhaps the updating Xid aborted. */
    1498          50 :     xmax = HeapTupleGetUpdateXid(tuple);
    1499             : 
    1500             :     /* not LOCKED_ONLY, so it has to have an xmax */
    1501             :     Assert(TransactionIdIsValid(xmax));
    1502             : 
    1503          50 :     if (TransactionIdIsCurrentTransactionId(xmax))
    1504           0 :         return false;
    1505          50 :     if (TransactionIdIsInProgress(xmax))
    1506           8 :         return false;
    1507          42 :     if (TransactionIdDidCommit(xmax))
    1508          22 :         return false;
    1509             : 
    1510             :     /*
    1511             :      * not current, not in progress, not committed -- must have aborted or
    1512             :      * crashed
    1513             :      */
    1514          20 :     return true;
    1515             : }
    1516             : 
    1517             : /*
    1518             :  * check whether the transaction id 'xid' is in the pre-sorted array 'xip'.
    1519             :  */
    1520             : static bool
    1521       38718 : TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num)
    1522             : {
    1523       38718 :     return bsearch(&xid, xip, num,
    1524       38718 :                    sizeof(TransactionId), xidComparator) != NULL;
    1525             : }
    1526             : 
    1527             : /*
    1528             :  * See the comments for HeapTupleSatisfiesMVCC for the semantics this function
    1529             :  * obeys.
    1530             :  *
    1531             :  * Only usable on tuples from catalog tables!
    1532             :  *
    1533             :  * We don't need to support HEAP_MOVED_(IN|OFF) for now because we only support
    1534             :  * reading catalog pages which couldn't have been created in an older version.
    1535             :  *
    1536             :  * We don't set any hint bits in here as it seems unlikely to be beneficial as
    1537             :  * those should already be set by normal access and it seems to be too
    1538             :  * dangerous to do so as the semantics of doing so during timetravel are more
    1539             :  * complicated than when dealing "only" with the present.
    1540             :  */
    1541             : static bool
    1542       30582 : HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
    1543             :                                Buffer buffer)
    1544             : {
    1545       30582 :     HeapTupleHeader tuple = htup->t_data;
    1546       30582 :     TransactionId xmin = HeapTupleHeaderGetXmin(tuple);
    1547       30582 :     TransactionId xmax = HeapTupleHeaderGetRawXmax(tuple);
    1548             : 
    1549             :     Assert(ItemPointerIsValid(&htup->t_self));
    1550             :     Assert(htup->t_tableOid != InvalidOid);
    1551             : 
    1552             :     /* inserting transaction aborted */
    1553       30582 :     if (HeapTupleHeaderXminInvalid(tuple))
    1554             :     {
    1555             :         Assert(!TransactionIdDidCommit(xmin));
    1556         138 :         return false;
    1557             :     }
    1558             :     /* check if it's one of our txids, toplevel is also in there */
    1559       30444 :     else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
    1560             :     {
    1561             :         bool        resolved;
    1562         516 :         CommandId   cmin = HeapTupleHeaderGetRawCommandId(tuple);
    1563         516 :         CommandId   cmax = InvalidCommandId;
    1564             : 
    1565             :         /*
    1566             :          * another transaction might have (tried to) delete this tuple or
    1567             :          * cmin/cmax was stored in a combocid. So we need to lookup the actual
    1568             :          * values externally.
    1569             :          */
    1570         516 :         resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
    1571             :                                                  htup, buffer,
    1572             :                                                  &cmin, &cmax);
    1573             : 
    1574         516 :         if (!resolved)
    1575           0 :             elog(ERROR, "could not resolve cmin/cmax of catalog tuple");
    1576             : 
    1577             :         Assert(cmin != InvalidCommandId);
    1578             : 
    1579         516 :         if (cmin >= snapshot->curcid)
    1580         102 :             return false;       /* inserted after scan started */
    1581             :         /* fall through */
    1582             :     }
    1583             :     /* committed before our xmin horizon. Do a normal visibility check. */
    1584       29928 :     else if (TransactionIdPrecedes(xmin, snapshot->xmin))
    1585             :     {
    1586             :         Assert(!(HeapTupleHeaderXminCommitted(tuple) &&
    1587             :                  !TransactionIdDidCommit(xmin)));
    1588             : 
    1589             :         /* check for hint bit first, consult clog afterwards */
    1590       26922 :         if (!HeapTupleHeaderXminCommitted(tuple) &&
    1591          12 :             !TransactionIdDidCommit(xmin))
    1592           0 :             return false;
    1593             :         /* fall through */
    1594             :     }
    1595             :     /* beyond our xmax horizon, i.e. invisible */
    1596        3018 :     else if (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
    1597             :     {
    1598         208 :         return false;
    1599             :     }
    1600             :     /* check if it's a committed transaction in [xmin, xmax) */
    1601        2810 :     else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
    1602             :     {
    1603             :         /* fall through */
    1604             :     }
    1605             : 
    1606             :     /*
    1607             :      * none of the above, i.e. between [xmin, xmax) but hasn't committed. I.e.
    1608             :      * invisible.
    1609             :      */
    1610             :     else
    1611             :     {
    1612           0 :         return false;
    1613             :     }
    1614             : 
    1615             :     /* at this point we know xmin is visible, go on to check xmax */
    1616             : 
    1617             :     /* xid invalid or aborted */
    1618       30134 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)
    1619       24538 :         return true;
    1620             :     /* locked tuples are always visible */
    1621        5596 :     else if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
    1622        1644 :         return true;
    1623             : 
    1624             :     /*
    1625             :      * We can see multis here if we're looking at user tables or if somebody
    1626             :      * SELECT ... FOR SHARE/UPDATE a system table.
    1627             :      */
    1628        3952 :     else if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
    1629             :     {
    1630          80 :         xmax = HeapTupleGetUpdateXid(tuple);
    1631             :     }
    1632             : 
    1633             :     /* check if it's one of our txids, toplevel is also in there */
    1634        3952 :     if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
    1635             :     {
    1636             :         bool        resolved;
    1637             :         CommandId   cmin;
    1638         292 :         CommandId   cmax = HeapTupleHeaderGetRawCommandId(tuple);
    1639             : 
    1640             :         /* Lookup actual cmin/cmax values */
    1641         292 :         resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
    1642             :                                                  htup, buffer,
    1643             :                                                  &cmin, &cmax);
    1644             : 
    1645         292 :         if (!resolved)
    1646           0 :             elog(ERROR, "could not resolve combocid to cmax");
    1647             : 
    1648             :         Assert(cmax != InvalidCommandId);
    1649             : 
    1650         292 :         if (cmax >= snapshot->curcid)
    1651         154 :             return true;        /* deleted after scan started */
    1652             :         else
    1653         138 :             return false;       /* deleted before scan started */
    1654             :     }
    1655             :     /* below xmin horizon, normal transaction state is valid */
    1656        3660 :     else if (TransactionIdPrecedes(xmax, snapshot->xmin))
    1657             :     {
    1658             :         Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED &&
    1659             :                  !TransactionIdDidCommit(xmax)));
    1660             : 
    1661             :         /* check hint bit first */
    1662        1788 :         if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
    1663        1698 :             return false;
    1664             : 
    1665             :         /* check clog */
    1666          90 :         return !TransactionIdDidCommit(xmax);
    1667             :     }
    1668             :     /* above xmax horizon, we cannot possibly see the deleting transaction */
    1669        1872 :     else if (TransactionIdFollowsOrEquals(xmax, snapshot->xmax))
    1670         360 :         return true;
    1671             :     /* xmax is between [xmin, xmax), check known committed array */
    1672        1512 :     else if (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt))
    1673        1512 :         return false;
    1674             :     /* xmax is between [xmin, xmax), but known not to have committed yet */
    1675             :     else
    1676           0 :         return true;
    1677             : }
    1678             : 
    1679             : /*
    1680             :  * HeapTupleSatisfiesVisibility
    1681             :  *      True iff heap tuple satisfies a time qual.
    1682             :  *
    1683             :  * Notes:
    1684             :  *  Assumes heap tuple is valid, and buffer at least share locked.
    1685             :  *
    1686             :  *  Hint bits in the HeapTuple's t_infomask may be updated as a side effect;
    1687             :  *  if so, the indicated buffer is marked dirty.
    1688             :  */
    1689             : bool
    1690   199317726 : HeapTupleSatisfiesVisibility(HeapTuple tup, Snapshot snapshot, Buffer buffer)
    1691             : {
    1692   199317726 :     switch (snapshot->snapshot_type)
    1693             :     {
    1694             :         case SNAPSHOT_MVCC:
    1695   186806914 :             return HeapTupleSatisfiesMVCC(tup, snapshot, buffer);
    1696             :             break;
    1697             :         case SNAPSHOT_SELF:
    1698        3186 :             return HeapTupleSatisfiesSelf(tup, snapshot, buffer);
    1699             :             break;
    1700             :         case SNAPSHOT_ANY:
    1701    11837428 :             return HeapTupleSatisfiesAny(tup, snapshot, buffer);
    1702             :             break;
    1703             :         case SNAPSHOT_TOAST:
    1704      123952 :             return HeapTupleSatisfiesToast(tup, snapshot, buffer);
    1705             :             break;
    1706             :         case SNAPSHOT_DIRTY:
    1707      473448 :             return HeapTupleSatisfiesDirty(tup, snapshot, buffer);
    1708             :             break;
    1709             :         case SNAPSHOT_HISTORIC_MVCC:
    1710       30582 :             return HeapTupleSatisfiesHistoricMVCC(tup, snapshot, buffer);
    1711             :             break;
    1712             :         case SNAPSHOT_NON_VACUUMABLE:
    1713       42216 :             return HeapTupleSatisfiesNonVacuumable(tup, snapshot, buffer);
    1714             :             break;
    1715             :     }
    1716             : 
    1717           0 :     return false;               /* keep compiler quiet */
    1718             : }

Generated by: LCOV version 1.13