LCOV - code coverage report
Current view: top level - src/backend/utils/time - tqual.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 264 598 44.1 %
Date: 2017-09-29 15:12:54 Functions: 11 14 78.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11