LCOV - differential code coverage report
Current view: top level - src/backend/access/heap - heapam_visibility.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 68.5 % 607 416 28 111 52 16 223 8 169 122 209 1 10
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 16 16 15 1 16
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a