LCOV - differential code coverage report
Current view: top level - src/backend/access/heap - heapam_visibility.c (source / functions) Coverage Total Hit UNC LBC UBC GBC GIC GNC CBC DUB DCB
Current: 0e5ff9b9b45a657aea12440478dc002e9b01f138 vs 0123ce131fca454009439dfa3b2266d1d40737d7 Lines: 79.6 % 558 444 22 3 89 3 1 48 392 98 23
Current Date: 2026-03-14 14:10:32 -0400 Functions: 100.0 % 19 19 12 7 1
Baseline: lcov-20260315-024220-baseline Branches: 70.4 % 510 359 25 3 123 3 31 325 84 18
Baseline Date: 2026-03-14 15:27:56 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(1,7] days: 100.0 % 28 28 28
(30,360] days: 47.6 % 42 20 22 20
(360..) days: 81.1 % 488 396 3 89 3 1 392
Function coverage date bins:
(1,7] days: 100.0 % 2 2 2
(30,360] days: 100.0 % 2 2 2
(360..) days: 100.0 % 15 15 8 7
Branch coverage date bins:
(1,7] days: 100.0 % 18 18 18
(30,360] days: 34.2 % 38 13 25 13
(360..) days: 72.2 % 454 328 3 123 3 325

 Age         Owner                    Branch data    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-2026, 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/tableam.h"
                                 73                 :                : #include "access/transam.h"
                                 74                 :                : #include "access/xact.h"
                                 75                 :                : #include "access/xlog.h"
                                 76                 :                : #include "storage/bufmgr.h"
                                 77                 :                : #include "storage/procarray.h"
                                 78                 :                : #include "utils/builtins.h"
                                 79                 :                : #include "utils/snapmgr.h"
                                 80                 :                : 
                                 81                 :                : 
                                 82                 :                : /*
                                 83                 :                :  * To be allowed to set hint bits, SetHintBits() needs to call
                                 84                 :                :  * BufferBeginSetHintBits(). However, that's not free, and some callsites call
                                 85                 :                :  * SetHintBits() on many tuples in a row. For those it makes sense to amortize
                                 86                 :                :  * the cost of BufferBeginSetHintBits(). Additionally it's desirable to defer
                                 87                 :                :  * the cost of BufferBeginSetHintBits() until a hint bit needs to actually be
                                 88                 :                :  * set. This enum serves as the necessary state space passed to
                                 89                 :                :  * SetHintBitsExt().
                                 90                 :                :  */
                                 91                 :                : typedef enum SetHintBitsState
                                 92                 :                : {
                                 93                 :                :     /* not yet checked if hint bits may be set */
                                 94                 :                :     SHB_INITIAL,
                                 95                 :                :     /* failed to get permission to set hint bits, don't check again */
                                 96                 :                :     SHB_DISABLED,
                                 97                 :                :     /* allowed to set hint bits */
                                 98                 :                :     SHB_ENABLED,
                                 99                 :                : } SetHintBitsState;
                                100                 :                : 
                                101                 :                : /*
                                102                 :                :  * SetHintBitsExt()
                                103                 :                :  *
                                104                 :                :  * Set commit/abort hint bits on a tuple, if appropriate at this time.
                                105                 :                :  *
                                106                 :                :  * To be allowed to set a hint bit on a tuple, the page must not be undergoing
                                107                 :                :  * IO at this time (otherwise we e.g. could corrupt PG's page checksum or even
                                108                 :                :  * the filesystem's, as is known to happen with btrfs).
                                109                 :                :  *
                                110                 :                :  * The right to set a hint bit can be acquired on a page level with
                                111                 :                :  * BufferBeginSetHintBits(). Only a single backend gets the right to set hint
                                112                 :                :  * bits at a time.  Alternatively, if called with a NULL SetHintBitsState*,
                                113                 :                :  * hint bits are set with BufferSetHintBits16().
                                114                 :                :  *
                                115                 :                :  * It is only safe to set a transaction-committed hint bit if we know the
                                116                 :                :  * transaction's commit record is guaranteed to be flushed to disk before the
                                117                 :                :  * buffer, or if the table is temporary or unlogged and will be obliterated by
                                118                 :                :  * a crash anyway.  We cannot change the LSN of the page here, because we may
                                119                 :                :  * hold only a share lock on the buffer, so we can only use the LSN to
                                120                 :                :  * interlock this if the buffer's LSN already is newer than the commit LSN;
                                121                 :                :  * otherwise we have to just refrain from setting the hint bit until some
                                122                 :                :  * future re-examination of the tuple.
                                123                 :                :  *
                                124                 :                :  * We can always set hint bits when marking a transaction aborted.  (Some
                                125                 :                :  * code in heapam.c relies on that!)
                                126                 :                :  *
                                127                 :                :  * Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
                                128                 :                :  * we can always set the hint bits, since pre-9.0 VACUUM FULL always used
                                129                 :                :  * synchronous commits and didn't move tuples that weren't previously
                                130                 :                :  * hinted.  (This is not known by this subroutine, but is applied by its
                                131                 :                :  * callers.)  Note: old-style VACUUM FULL is gone, but we have to keep this
                                132                 :                :  * module's support for MOVED_OFF/MOVED_IN flag bits for as long as we
                                133                 :                :  * support in-place update from pre-9.0 databases.
                                134                 :                :  *
                                135                 :                :  * Normal commits may be asynchronous, so for those we need to get the LSN
                                136                 :                :  * of the transaction and then check whether this is flushed.
                                137                 :                :  *
                                138                 :                :  * The caller should pass xid as the XID of the transaction to check, or
                                139                 :                :  * InvalidTransactionId if no check is needed.
                                140                 :                :  */
                                141                 :                : static inline void
    5 andres@anarazel.de        142                 :GNC    10526332 : SetHintBitsExt(HeapTupleHeader tuple, Buffer buffer,
                                143                 :                :                uint16 infomask, TransactionId xid, SetHintBitsState *state)
                                144                 :                : {
                                145                 :                :     /*
                                146                 :                :      * In batched mode, if we previously did not get permission to set hint
                                147                 :                :      * bits, don't try again - in all likelihood IO is still going on.
                                148                 :                :      */
                                149   [ +  +  +  + ]:       10526332 :     if (state && *state == SHB_DISABLED)
                                150                 :             12 :         return;
                                151                 :                : 
 6801 tgl@sss.pgh.pa.us         152         [ +  + ]:CBC    10526320 :     if (TransactionIdIsValid(xid))
                                153                 :                :     {
    5 andres@anarazel.de        154         [ +  + ]:GNC    10396916 :         if (BufferIsPermanent(buffer))
                                155                 :                :         {
                                156                 :                :             /* NB: xid must be known committed here! */
                                157                 :        9449351 :             XLogRecPtr  commitLSN = TransactionIdGetCommitLSN(xid);
                                158                 :                : 
                                159   [ +  +  +  + ]:        9640161 :             if (XLogNeedsFlush(commitLSN) &&
                                160                 :         190810 :                 BufferGetLSNAtomic(buffer) < commitLSN)
                                161                 :                :             {
                                162                 :                :                 /* not flushed and no LSN interlock, so don't set hint */
                                163                 :         168631 :                 return;
                                164                 :                :             }
                                165                 :                :         }
                                166                 :                :     }
                                167                 :                : 
                                168                 :                :     /*
                                169                 :                :      * If we're not operating in batch mode, use BufferSetHintBits16() to mark
                                170                 :                :      * the page dirty, that's cheaper than
                                171                 :                :      * BufferBeginSetHintBits()/BufferFinishSetHintBits(). That's important
                                172                 :                :      * for cases where we set a lot of hint bits on a page individually.
                                173                 :                :      */
                                174         [ +  + ]:       10357689 :     if (!state)
                                175                 :                :     {
                                176                 :        7074331 :         BufferSetHintBits16(&tuple->t_infomask,
                                177                 :        7074331 :                             tuple->t_infomask | infomask, buffer);
                                178                 :        7074331 :         return;
                                179                 :                :     }
                                180                 :                : 
                                181         [ +  + ]:        3283358 :     if (*state == SHB_INITIAL)
                                182                 :                :     {
                                183         [ +  + ]:          98870 :         if (!BufferBeginSetHintBits(buffer))
                                184                 :                :         {
                                185                 :             10 :             *state = SHB_DISABLED;
 3681 andres@anarazel.de        186                 :CBC          10 :             return;
                                187                 :                :         }
                                188                 :                : 
    5 andres@anarazel.de        189                 :GNC       98860 :         *state = SHB_ENABLED;
                                190                 :                :     }
 6801 tgl@sss.pgh.pa.us         191                 :CBC     3283348 :     tuple->t_infomask |= infomask;
                                192                 :                : }
                                193                 :                : 
                                194                 :                : /*
                                195                 :                :  * Simple wrapper around SetHintBitExt(), use when operating on a single
                                196                 :                :  * tuple.
                                197                 :                :  */
                                198                 :                : static inline void
    5 andres@anarazel.de        199                 :GNC     5911601 : SetHintBits(HeapTupleHeader tuple, Buffer buffer,
                                200                 :                :             uint16 infomask, TransactionId xid)
                                201                 :                : {
                                202                 :        5911601 :     SetHintBitsExt(tuple, buffer, infomask, xid, NULL);
 6801 tgl@sss.pgh.pa.us         203                 :GIC     5911601 : }
                                204                 :                : 
                                205                 :                : /*
                                206                 :                :  * HeapTupleSetHintBits --- exported version of SetHintBits()
                                207                 :                :  *
                                208                 :                :  * This must be separate because of C99's brain-dead notions about how to
                                209                 :                :  * implement inline functions.
                                210                 :                :  */
                                211                 :                : void
 6788 tgl@sss.pgh.pa.us         212                 :CBC         230 : HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
                                213                 :                :                      uint16 infomask, TransactionId xid)
                                214                 :                : {
                                215                 :                :     /*
                                216                 :                :      * The uses from heapam.c rely on being able to perform the hint bit
                                217                 :                :      * updates, which can only be guaranteed if we are holding an exclusive
                                218                 :                :      * lock on the buffer - which all callers are doing.
                                219                 :                :      */
   62 andres@anarazel.de        220         [ -  + ]:GNC         230 :     Assert(BufferIsLockedByMeInMode(buffer, BUFFER_LOCK_EXCLUSIVE));
                                221                 :                : 
 6788 tgl@sss.pgh.pa.us         222                 :CBC         230 :     SetHintBits(tuple, buffer, infomask, xid);
                                223                 :            230 : }
                                224                 :                : 
                                225                 :                : /*
                                226                 :                :  * If HEAP_MOVED_OFF or HEAP_MOVED_IN are set on the tuple, remove them and
                                227                 :                :  * adjust hint bits. See the comment for SetHintBits() for more background.
                                228                 :                :  *
                                229                 :                :  * This helper returns false if the row ought to be invisible, true otherwise.
                                230                 :                :  */
                                231                 :                : static inline bool
   86 andres@anarazel.de        232                 :GNC    28346875 : HeapTupleCleanMoved(HeapTupleHeader tuple, Buffer buffer)
                                233                 :                : {
                                234                 :                :     TransactionId xvac;
                                235                 :                : 
                                236                 :                :     /* only used by pre-9.0 binary upgrades */
                                237         [ +  - ]:       28346875 :     if (likely(!(tuple->t_infomask & (HEAP_MOVED_OFF | HEAP_MOVED_IN))))
                                238                 :       28346875 :         return true;
                                239                 :                : 
   86 andres@anarazel.de        240                 :UNC           0 :     xvac = HeapTupleHeaderGetXvac(tuple);
                                241                 :                : 
                                242         [ #  # ]:              0 :     if (TransactionIdIsCurrentTransactionId(xvac))
                                243         [ #  # ]:              0 :         elog(ERROR, "encountered tuple with HEAP_MOVED considered current");
                                244                 :                : 
                                245         [ #  # ]:              0 :     if (TransactionIdIsInProgress(xvac))
                                246         [ #  # ]:              0 :         elog(ERROR, "encountered tuple with HEAP_MOVED considered in-progress");
                                247                 :                : 
                                248         [ #  # ]:              0 :     if (tuple->t_infomask & HEAP_MOVED_OFF)
                                249                 :                :     {
                                250         [ #  # ]:              0 :         if (TransactionIdDidCommit(xvac))
                                251                 :                :         {
                                252                 :              0 :             SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
                                253                 :                :                         InvalidTransactionId);
                                254                 :              0 :             return false;
                                255                 :                :         }
                                256                 :              0 :         SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
                                257                 :                :                     InvalidTransactionId);
                                258                 :                :     }
                                259         [ #  # ]:              0 :     else if (tuple->t_infomask & HEAP_MOVED_IN)
                                260                 :                :     {
                                261         [ #  # ]:              0 :         if (TransactionIdDidCommit(xvac))
                                262                 :              0 :             SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
                                263                 :                :                         InvalidTransactionId);
                                264                 :                :         else
                                265                 :                :         {
                                266                 :              0 :             SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
                                267                 :                :                         InvalidTransactionId);
                                268                 :              0 :             return false;
                                269                 :                :         }
                                270                 :                :     }
                                271                 :                : 
                                272                 :              0 :     return true;
                                273                 :                : }
                                274                 :                : 
                                275                 :                : /*
                                276                 :                :  * HeapTupleSatisfiesSelf
                                277                 :                :  *      True iff heap tuple is valid "for itself".
                                278                 :                :  *
                                279                 :                :  * See SNAPSHOT_MVCC's definition for the intended behaviour.
                                280                 :                :  *
                                281                 :                :  * Note:
                                282                 :                :  *      Assumes heap tuple is valid.
                                283                 :                :  *
                                284                 :                :  * The satisfaction of "itself" requires the following:
                                285                 :                :  *
                                286                 :                :  * ((Xmin == my-transaction &&              the row was updated by the current transaction, and
                                287                 :                :  *      (Xmax is null                       it was not deleted
                                288                 :                :  *       [|| Xmax != my-transaction)])          [or it was deleted by another transaction]
                                289                 :                :  * ||
                                290                 :                :  *
                                291                 :                :  * (Xmin is committed &&                    the row was modified by a committed transaction, and
                                292                 :                :  *      (Xmax is null ||                    the row has not been deleted, or
                                293                 :                :  *          (Xmax != my-transaction &&          the row was deleted by another transaction
                                294                 :                :  *           Xmax is not committed)))           that has not been committed
                                295                 :                :  */
                                296                 :                : static bool
 4619 rhaas@postgresql.org      297                 :CBC      402664 : HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
                                298                 :                : {
                                299                 :         402664 :     HeapTupleHeader tuple = htup->t_data;
                                300                 :                : 
                                301         [ -  + ]:         402664 :     Assert(ItemPointerIsValid(&htup->t_self));
                                302         [ -  + ]:         402664 :     Assert(htup->t_tableOid != InvalidOid);
                                303                 :                : 
 4466                           304         [ +  + ]:         402664 :     if (!HeapTupleHeaderXminCommitted(tuple))
                                305                 :                :     {
                                306         [ -  + ]:         402613 :         if (HeapTupleHeaderXminInvalid(tuple))
10057 bruce@momjian.us          307                 :UBC           0 :             return false;
                                308                 :                : 
   86 andres@anarazel.de        309         [ -  + ]:GNC      402613 :         if (!HeapTupleCleanMoved(tuple, buffer))
   86 andres@anarazel.de        310                 :UNC           0 :             return false;
 4466 rhaas@postgresql.org      311         [ +  - ]:CBC      402613 :         else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
                                312                 :                :         {
10360 vadim4o@yahoo.com         313         [ +  + ]:         402613 :             if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid */
10057 bruce@momjian.us          314                 :         402552 :                 return true;
                                315                 :                : 
 4673                           316         [ +  + ]:             61 :             if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
 7626 tgl@sss.pgh.pa.us         317                 :             10 :                 return true;
                                318                 :                : 
 4799 alvherre@alvh.no-ip.      319         [ -  + ]:             51 :             if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
                                320                 :                :             {
                                321                 :                :                 TransactionId xmax;
                                322                 :                : 
 4799 alvherre@alvh.no-ip.      323                 :UBC           0 :                 xmax = HeapTupleGetUpdateXid(tuple);
                                324                 :                : 
                                325                 :                :                 /* not LOCKED_ONLY, so it has to have an xmax */
 4489                           326         [ #  # ]:              0 :                 Assert(TransactionIdIsValid(xmax));
                                327                 :                : 
                                328                 :                :                 /* updating subtransaction must have aborted */
 4799                           329         [ #  # ]:              0 :                 if (!TransactionIdIsCurrentTransactionId(xmax))
                                330                 :              0 :                     return true;
                                331                 :                :                 else
                                332                 :              0 :                     return false;
                                333                 :                :             }
                                334                 :                : 
 4799 alvherre@alvh.no-ip.      335         [ +  + ]:CBC          51 :             if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
                                336                 :                :             {
                                337                 :                :                 /* deleting subtransaction must have aborted */
 6788 tgl@sss.pgh.pa.us         338                 :              9 :                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
                                339                 :                :                             InvalidTransactionId);
 7927                           340                 :              9 :                 return true;
                                341                 :                :             }
                                342                 :                : 
 9952 vadim4o@yahoo.com         343                 :             42 :             return false;
                                344                 :                :         }
 4466 rhaas@postgresql.org      345         [ #  # ]:UBC           0 :         else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
10057 bruce@momjian.us          346                 :              0 :             return false;
 4466 rhaas@postgresql.org      347         [ #  # ]:              0 :         else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
 6788 tgl@sss.pgh.pa.us         348                 :              0 :             SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
                                349                 :                :                         HeapTupleHeaderGetRawXmin(tuple));
                                350                 :                :         else
                                351                 :                :         {
                                352                 :                :             /* it must have aborted or crashed */
                                353                 :              0 :             SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
                                354                 :                :                         InvalidTransactionId);
 7617                           355                 :              0 :             return false;
                                356                 :                :         }
                                357                 :                :     }
                                358                 :                : 
                                359                 :                :     /* by here, the inserting transaction has committed */
                                360                 :                : 
10360 vadim4o@yahoo.com         361         [ +  - ]:CBC          51 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid or aborted */
10057 bruce@momjian.us          362                 :             51 :         return true;
                                363                 :                : 
10360 vadim4o@yahoo.com         364         [ #  # ]:UBC           0 :     if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
                                365                 :                :     {
 4799 alvherre@alvh.no-ip.      366         [ #  # ]:              0 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
 9952 vadim4o@yahoo.com         367                 :              0 :             return true;
 9791 bruce@momjian.us          368                 :              0 :         return false;           /* updated by other */
                                369                 :                :     }
                                370                 :                : 
 7626 tgl@sss.pgh.pa.us         371         [ #  # ]:              0 :     if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
                                372                 :                :     {
                                373                 :                :         TransactionId xmax;
                                374                 :                : 
 4799 alvherre@alvh.no-ip.      375         [ #  # ]:              0 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
                                376                 :              0 :             return true;
                                377                 :                : 
                                378                 :              0 :         xmax = HeapTupleGetUpdateXid(tuple);
                                379                 :                : 
                                380                 :                :         /* not LOCKED_ONLY, so it has to have an xmax */
 4489                           381         [ #  # ]:              0 :         Assert(TransactionIdIsValid(xmax));
                                382                 :                : 
 4799                           383         [ #  # ]:              0 :         if (TransactionIdIsCurrentTransactionId(xmax))
                                384                 :              0 :             return false;
                                385         [ #  # ]:              0 :         if (TransactionIdIsInProgress(xmax))
                                386                 :              0 :             return true;
                                387         [ #  # ]:              0 :         if (TransactionIdDidCommit(xmax))
                                388                 :              0 :             return false;
                                389                 :                :         /* it must have aborted or crashed */
 7626 tgl@sss.pgh.pa.us         390                 :              0 :         return true;
                                391                 :                :     }
                                392                 :                : 
 4799 alvherre@alvh.no-ip.      393         [ #  # ]:              0 :     if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
                                394                 :                :     {
                                395         [ #  # ]:              0 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
 9952 vadim4o@yahoo.com         396                 :              0 :             return true;
10057 bruce@momjian.us          397                 :              0 :         return false;
                                398                 :                :     }
                                399                 :                : 
 4799 alvherre@alvh.no-ip.      400         [ #  # ]:              0 :     if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
 7617 tgl@sss.pgh.pa.us         401                 :              0 :         return true;
                                402                 :                : 
 4799 alvherre@alvh.no-ip.      403         [ #  # ]:              0 :     if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
                                404                 :                :     {
                                405                 :                :         /* it must have aborted or crashed */
 6788 tgl@sss.pgh.pa.us         406                 :              0 :         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
                                407                 :                :                     InvalidTransactionId);
10057 bruce@momjian.us          408                 :              0 :         return true;
                                409                 :                :     }
                                410                 :                : 
                                411                 :                :     /* xmax transaction committed */
                                412                 :                : 
 4799 alvherre@alvh.no-ip.      413         [ #  # ]:              0 :     if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
                                414                 :                :     {
 6788 tgl@sss.pgh.pa.us         415                 :              0 :         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
                                416                 :                :                     InvalidTransactionId);
 9952 vadim4o@yahoo.com         417                 :              0 :         return true;
                                418                 :                :     }
                                419                 :                : 
 6788 tgl@sss.pgh.pa.us         420                 :              0 :     SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
                                421                 :                :                 HeapTupleHeaderGetRawXmax(tuple));
10057 bruce@momjian.us          422                 :              0 :     return false;
                                423                 :                : }
                                424                 :                : 
                                425                 :                : /*
                                426                 :                :  * HeapTupleSatisfiesAny
                                427                 :                :  *      Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
                                428                 :                :  */
                                429                 :                : static bool
 4619 rhaas@postgresql.org      430                 :CBC     8327201 : HeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer)
                                431                 :                : {
 6930 tgl@sss.pgh.pa.us         432                 :        8327201 :     return true;
                                433                 :                : }
                                434                 :                : 
                                435                 :                : /*
                                436                 :                :  * HeapTupleSatisfiesToast
                                437                 :                :  *      True iff heap tuple is valid as a TOAST row.
                                438                 :                :  *
                                439                 :                :  * See SNAPSHOT_TOAST's definition for the intended behaviour.
                                440                 :                :  *
                                441                 :                :  * This is a simplified version that only checks for VACUUM moving conditions.
                                442                 :                :  * It's appropriate for TOAST usage because TOAST really doesn't want to do
                                443                 :                :  * its own time qual checks; if you can see the main table row that contains
                                444                 :                :  * a TOAST reference, you should be able to see the TOASTed value.  However,
                                445                 :                :  * vacuuming a TOAST table is independent of the main table, and in case such
                                446                 :                :  * a vacuum fails partway through, we'd better do this much checking.
                                447                 :                :  *
                                448                 :                :  * Among other things, this means you can't do UPDATEs of rows in a TOAST
                                449                 :                :  * table.
                                450                 :                :  */
                                451                 :                : static bool
 4619 rhaas@postgresql.org      452                 :          86023 : HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot,
                                453                 :                :                         Buffer buffer)
                                454                 :                : {
                                455                 :          86023 :     HeapTupleHeader tuple = htup->t_data;
                                456                 :                : 
                                457         [ -  + ]:          86023 :     Assert(ItemPointerIsValid(&htup->t_self));
                                458         [ -  + ]:          86023 :     Assert(htup->t_tableOid != InvalidOid);
                                459                 :                : 
 4466                           460         [ +  + ]:          86023 :     if (!HeapTupleHeaderXminCommitted(tuple))
                                461                 :                :     {
                                462         [ -  + ]:          64346 :         if (HeapTupleHeaderXminInvalid(tuple))
 8824 tgl@sss.pgh.pa.us         463                 :UBC           0 :             return false;
                                464                 :                : 
   86 andres@anarazel.de        465         [ -  + ]:GNC       64346 :         if (!HeapTupleCleanMoved(tuple, buffer))
   86 andres@anarazel.de        466                 :UNC           0 :             return false;
                                467                 :                : 
                                468                 :                :         /*
                                469                 :                :          * An invalid Xmin can be left behind by a speculative insertion that
                                470                 :                :          * is canceled by super-deleting the tuple.  This also applies to
                                471                 :                :          * TOAST tuples created during speculative insertion.
                                472                 :                :          */
 3964 andres@anarazel.de        473         [ -  + ]:CBC       64346 :         else if (!TransactionIdIsValid(HeapTupleHeaderGetXmin(tuple)))
 3964 andres@anarazel.de        474                 :UBC           0 :             return false;
                                475                 :                :     }
                                476                 :                : 
                                477                 :                :     /* otherwise assume the tuple is valid for TOAST. */
 8824 tgl@sss.pgh.pa.us         478                 :CBC       86023 :     return true;
                                479                 :                : }
                                480                 :                : 
                                481                 :                : /*
                                482                 :                :  * HeapTupleSatisfiesUpdate
                                483                 :                :  *
                                484                 :                :  *  This function returns a more detailed result code than most of the
                                485                 :                :  *  functions in this file, since UPDATE needs to know more than "is it
                                486                 :                :  *  visible?".  It also allows for user-supplied CommandId rather than
                                487                 :                :  *  relying on CurrentCommandId.
                                488                 :                :  *
                                489                 :                :  *  The possible return codes are:
                                490                 :                :  *
                                491                 :                :  *  TM_Invisible: the tuple didn't exist at all when the scan started, e.g. it
                                492                 :                :  *  was created by a later CommandId.
                                493                 :                :  *
                                494                 :                :  *  TM_Ok: The tuple is valid and visible, so it may be updated.
                                495                 :                :  *
                                496                 :                :  *  TM_SelfModified: The tuple was updated by the current transaction, after
                                497                 :                :  *  the current scan started.
                                498                 :                :  *
                                499                 :                :  *  TM_Updated: The tuple was updated by a committed transaction (including
                                500                 :                :  *  the case where the tuple was moved into a different partition).
                                501                 :                :  *
                                502                 :                :  *  TM_Deleted: The tuple was deleted by a committed transaction.
                                503                 :                :  *
                                504                 :                :  *  TM_BeingModified: The tuple is being updated by an in-progress transaction
                                505                 :                :  *  other than the current transaction.  (Note: this includes the case where
                                506                 :                :  *  the tuple is share-locked by a MultiXact, even if the MultiXact includes
                                507                 :                :  *  the current transaction.  Callers that want to distinguish that case must
                                508                 :                :  *  test for it themselves.)
                                509                 :                :  */
                                510                 :                : TM_Result
 4619 rhaas@postgresql.org      511                 :        2456378 : HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
                                512                 :                :                          Buffer buffer)
                                513                 :                : {
                                514                 :        2456378 :     HeapTupleHeader tuple = htup->t_data;
                                515                 :                : 
                                516         [ -  + ]:        2456378 :     Assert(ItemPointerIsValid(&htup->t_self));
                                517         [ -  + ]:        2456378 :     Assert(htup->t_tableOid != InvalidOid);
                                518                 :                : 
 4466                           519         [ +  + ]:        2456378 :     if (!HeapTupleHeaderXminCommitted(tuple))
                                520                 :                :     {
                                521         [ -  + ]:         251143 :         if (HeapTupleHeaderXminInvalid(tuple))
 2549 andres@anarazel.de        522                 :UBC           0 :             return TM_Invisible;
                                523                 :                : 
   86 andres@anarazel.de        524         [ -  + ]:GNC      251143 :         else if (!HeapTupleCleanMoved(tuple, buffer))
   86 andres@anarazel.de        525                 :UNC           0 :             return TM_Invisible;
 4466 rhaas@postgresql.org      526         [ +  + ]:CBC      251143 :         else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
                                527                 :                :         {
 8674 bruce@momjian.us          528         [ +  + ]:         247539 :             if (HeapTupleHeaderGetCmin(tuple) >= curcid)
 2549 andres@anarazel.de        529                 :             21 :                 return TM_Invisible;    /* inserted after scan started */
                                530                 :                : 
 8593 bruce@momjian.us          531         [ +  + ]:         247518 :             if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid */
 2549 andres@anarazel.de        532                 :         207292 :                 return TM_Ok;
                                533                 :                : 
 4470 alvherre@alvh.no-ip.      534         [ +  + ]:          40226 :             if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
                                535                 :                :             {
                                536                 :                :                 TransactionId xmax;
                                537                 :                : 
                                538                 :          40216 :                 xmax = HeapTupleHeaderGetRawXmax(tuple);
                                539                 :                : 
                                540                 :                :                 /*
                                541                 :                :                  * Careful here: even though this tuple was created by our own
                                542                 :                :                  * transaction, it might be locked by other transactions, if
                                543                 :                :                  * the original version was key-share locked when we updated
                                544                 :                :                  * it.
                                545                 :                :                  */
                                546                 :                : 
                                547         [ +  + ]:          40216 :                 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
                                548                 :                :                 {
 3992                           549         [ +  - ]:             31 :                     if (MultiXactIdIsRunning(xmax, true))
 2549 andres@anarazel.de        550                 :             31 :                         return TM_BeingModified;
                                551                 :                :                     else
 2549 andres@anarazel.de        552                 :UBC           0 :                         return TM_Ok;
                                553                 :                :                 }
                                554                 :                : 
                                555                 :                :                 /*
                                556                 :                :                  * If the locker is gone, then there is nothing of interest
                                557                 :                :                  * left in this Xmax; otherwise, report the tuple as
                                558                 :                :                  * locked/updated.
                                559                 :                :                  */
 4470 alvherre@alvh.no-ip.      560         [ -  + ]:CBC       40185 :                 if (!TransactionIdIsInProgress(xmax))
 2549 andres@anarazel.de        561                 :UBC           0 :                     return TM_Ok;
 2549 andres@anarazel.de        562                 :CBC       40185 :                 return TM_BeingModified;
                                563                 :                :             }
                                564                 :                : 
 4799 alvherre@alvh.no-ip.      565         [ +  + ]:             10 :             if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
                                566                 :                :             {
                                567                 :                :                 TransactionId xmax;
                                568                 :                : 
                                569                 :              7 :                 xmax = HeapTupleGetUpdateXid(tuple);
                                570                 :                : 
                                571                 :                :                 /* not LOCKED_ONLY, so it has to have an xmax */
 4489                           572         [ -  + ]:              7 :                 Assert(TransactionIdIsValid(xmax));
                                573                 :                : 
                                574                 :                :                 /* deleting subtransaction must have aborted */
 4799                           575         [ +  - ]:              7 :                 if (!TransactionIdIsCurrentTransactionId(xmax))
                                576                 :                :                 {
 3992                           577         [ +  - ]:              7 :                     if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),
                                578                 :                :                                              false))
 2549 andres@anarazel.de        579                 :              7 :                         return TM_BeingModified;
 2549 andres@anarazel.de        580                 :UBC           0 :                     return TM_Ok;
                                581                 :                :                 }
                                582                 :                :                 else
                                583                 :                :                 {
 4799 alvherre@alvh.no-ip.      584         [ #  # ]:              0 :                     if (HeapTupleHeaderGetCmax(tuple) >= curcid)
 2549 andres@anarazel.de        585                 :              0 :                         return TM_SelfModified; /* updated after scan started */
                                586                 :                :                     else
                                587                 :              0 :                         return TM_Invisible;    /* updated before scan started */
                                588                 :                :                 }
                                589                 :                :             }
                                590                 :                : 
 4799 alvherre@alvh.no-ip.      591         [ -  + ]:CBC           3 :             if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
                                592                 :                :             {
                                593                 :                :                 /* deleting subtransaction must have aborted */
 6788 tgl@sss.pgh.pa.us         594                 :UBC           0 :                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
                                595                 :                :                             InvalidTransactionId);
 2549 andres@anarazel.de        596                 :              0 :                 return TM_Ok;
                                597                 :                :             }
                                598                 :                : 
 8674 bruce@momjian.us          599         [ +  - ]:CBC           3 :             if (HeapTupleHeaderGetCmax(tuple) >= curcid)
 2549 andres@anarazel.de        600                 :              3 :                 return TM_SelfModified; /* updated after scan started */
                                601                 :                :             else
 2549 andres@anarazel.de        602                 :UBC           0 :                 return TM_Invisible;    /* updated before scan started */
                                603                 :                :         }
 4466 rhaas@postgresql.org      604         [ -  + ]:CBC        3604 :         else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
 2549 andres@anarazel.de        605                 :UBC           0 :             return TM_Invisible;
 4466 rhaas@postgresql.org      606         [ +  - ]:CBC        3604 :         else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
 6788 tgl@sss.pgh.pa.us         607                 :           3604 :             SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
                                608                 :                :                         HeapTupleHeaderGetRawXmin(tuple));
                                609                 :                :         else
                                610                 :                :         {
                                611                 :                :             /* it must have aborted or crashed */
 6788 tgl@sss.pgh.pa.us         612                 :UBC           0 :             SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
                                613                 :                :                         InvalidTransactionId);
 2549 andres@anarazel.de        614                 :              0 :             return TM_Invisible;
                                615                 :                :         }
                                616                 :                :     }
                                617                 :                : 
                                618                 :                :     /* by here, the inserting transaction has committed */
                                619                 :                : 
 8593 bruce@momjian.us          620         [ +  + ]:CBC     2208839 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid or aborted */
 2549 andres@anarazel.de        621                 :        1687130 :         return TM_Ok;
                                622                 :                : 
 8852 tgl@sss.pgh.pa.us         623         [ +  + ]:         521709 :     if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
                                624                 :                :     {
 4799 alvherre@alvh.no-ip.      625         [ -  + ]:            164 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
 2549 andres@anarazel.de        626                 :UBC           0 :             return TM_Ok;
 1847 alvherre@alvh.no-ip.      627         [ +  - ]:CBC         164 :         if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
 2549 andres@anarazel.de        628                 :            164 :             return TM_Updated;  /* updated by other */
                                629                 :                :         else
 2549 andres@anarazel.de        630                 :UBC           0 :             return TM_Deleted;  /* deleted by other */
                                631                 :                :     }
                                632                 :                : 
 7626 tgl@sss.pgh.pa.us         633         [ +  + ]:CBC      521545 :     if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
                                634                 :                :     {
                                635                 :                :         TransactionId xmax;
                                636                 :                : 
 3551 alvherre@alvh.no-ip.      637         [ -  + ]:          73981 :         if (HEAP_LOCKED_UPGRADED(tuple->t_infomask))
 2549 andres@anarazel.de        638                 :UBC           0 :             return TM_Ok;
                                639                 :                : 
 4799 alvherre@alvh.no-ip.      640         [ +  + ]:CBC       73981 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
                                641                 :                :         {
 3551                           642         [ +  + ]:          71826 :             if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), true))
 2549 andres@anarazel.de        643                 :          71321 :                 return TM_BeingModified;
                                644                 :                : 
 4799 alvherre@alvh.no-ip.      645                 :            505 :             SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
 2549 andres@anarazel.de        646                 :            505 :             return TM_Ok;
                                647                 :                :         }
                                648                 :                : 
 4799 alvherre@alvh.no-ip.      649                 :           2155 :         xmax = HeapTupleGetUpdateXid(tuple);
 4247                           650         [ -  + ]:           2155 :         if (!TransactionIdIsValid(xmax))
                                651                 :                :         {
 4247 alvherre@alvh.no-ip.      652         [ #  # ]:UBC           0 :             if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
 2549 andres@anarazel.de        653                 :              0 :                 return TM_BeingModified;
                                654                 :                :         }
                                655                 :                : 
                                656                 :                :         /* not LOCKED_ONLY, so it has to have an xmax */
 4489 alvherre@alvh.no-ip.      657         [ -  + ]:CBC        2155 :         Assert(TransactionIdIsValid(xmax));
                                658                 :                : 
 4799                           659         [ -  + ]:           2155 :         if (TransactionIdIsCurrentTransactionId(xmax))
                                660                 :                :         {
 4799 alvherre@alvh.no-ip.      661         [ #  # ]:UBC           0 :             if (HeapTupleHeaderGetCmax(tuple) >= curcid)
 2549 andres@anarazel.de        662                 :              0 :                 return TM_SelfModified; /* updated after scan started */
                                663                 :                :             else
                                664                 :              0 :                 return TM_Invisible;    /* updated before scan started */
                                665                 :                :         }
                                666                 :                : 
 4247 alvherre@alvh.no-ip.      667         [ +  + ]:CBC        2155 :         if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
 2549 andres@anarazel.de        668                 :           2152 :             return TM_BeingModified;
                                669                 :                : 
 4799 alvherre@alvh.no-ip.      670         [ -  + ]:              3 :         if (TransactionIdDidCommit(xmax))
                                671                 :                :         {
 1847 alvherre@alvh.no-ip.      672         [ #  # ]:LBC         (1) :             if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
 2549 andres@anarazel.de        673                 :UBC           0 :                 return TM_Updated;
                                674                 :                :             else
 2549 andres@anarazel.de        675                 :LBC         (1) :                 return TM_Deleted;
                                676                 :                :         }
                                677                 :                : 
                                678                 :                :         /*
                                679                 :                :          * By here, the update in the Xmax is either aborted or crashed, but
                                680                 :                :          * what about the other members?
                                681                 :                :          */
                                682                 :                : 
 4247 alvherre@alvh.no-ip.      683         [ +  - ]:CBC           3 :         if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
                                684                 :                :         {
                                685                 :                :             /*
                                686                 :                :              * There's no member, even just a locker, alive anymore, so we can
                                687                 :                :              * mark the Xmax as invalid.
                                688                 :                :              */
 4489                           689                 :              3 :             SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
                                690                 :                :                         InvalidTransactionId);
 2549 andres@anarazel.de        691                 :              3 :             return TM_Ok;
                                692                 :                :         }
                                693                 :                :         else
                                694                 :                :         {
                                695                 :                :             /* There are lockers running */
 2549 andres@anarazel.de        696                 :UBC           0 :             return TM_BeingModified;
                                697                 :                :         }
                                698                 :                :     }
                                699                 :                : 
 4799 alvherre@alvh.no-ip.      700         [ +  + ]:CBC      447564 :     if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
                                701                 :                :     {
                                702         [ +  + ]:         442602 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
 2549 andres@anarazel.de        703                 :         442526 :             return TM_BeingModified;
 8674 bruce@momjian.us          704         [ +  - ]:             76 :         if (HeapTupleHeaderGetCmax(tuple) >= curcid)
 2549 andres@anarazel.de        705                 :             76 :             return TM_SelfModified; /* updated after scan started */
                                706                 :                :         else
 2549 andres@anarazel.de        707                 :UBC           0 :             return TM_Invisible;    /* updated before scan started */
                                708                 :                :     }
                                709                 :                : 
 4799 alvherre@alvh.no-ip.      710         [ +  + ]:CBC        4962 :     if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
 2549 andres@anarazel.de        711                 :           1398 :         return TM_BeingModified;
                                712                 :                : 
 4799 alvherre@alvh.no-ip.      713         [ +  + ]:           3564 :     if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
                                714                 :                :     {
                                715                 :                :         /* it must have aborted or crashed */
 6788 tgl@sss.pgh.pa.us         716                 :            190 :         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
                                717                 :                :                     InvalidTransactionId);
 2549 andres@anarazel.de        718                 :            190 :         return TM_Ok;
                                719                 :                :     }
                                720                 :                : 
                                721                 :                :     /* xmax transaction committed */
                                722                 :                : 
 4799 alvherre@alvh.no-ip.      723         [ +  + ]:           3374 :     if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
                                724                 :                :     {
 6788 tgl@sss.pgh.pa.us         725                 :           3305 :         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
                                726                 :                :                     InvalidTransactionId);
 2549 andres@anarazel.de        727                 :           3305 :         return TM_Ok;
                                728                 :                :     }
                                729                 :                : 
 6788 tgl@sss.pgh.pa.us         730                 :             69 :     SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
                                731                 :                :                 HeapTupleHeaderGetRawXmax(tuple));
 1847 alvherre@alvh.no-ip.      732         [ +  + ]:             69 :     if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
 2549 andres@anarazel.de        733                 :             68 :         return TM_Updated;      /* updated by other */
                                734                 :                :     else
                                735                 :              1 :         return TM_Deleted;      /* deleted by other */
                                736                 :                : }
                                737                 :                : 
                                738                 :                : /*
                                739                 :                :  * HeapTupleSatisfiesDirty
                                740                 :                :  *      True iff heap tuple is valid including effects of open transactions.
                                741                 :                :  *
                                742                 :                :  * See SNAPSHOT_DIRTY's definition for the intended behaviour.
                                743                 :                :  *
                                744                 :                :  * This is essentially like HeapTupleSatisfiesSelf as far as effects of
                                745                 :                :  * the current transaction and committed/aborted xacts are concerned.
                                746                 :                :  * However, we also include the effects of other xacts still in progress.
                                747                 :                :  *
                                748                 :                :  * A special hack is that the passed-in snapshot struct is used as an
                                749                 :                :  * output argument to return the xids of concurrent xacts that affected the
                                750                 :                :  * tuple.  snapshot->xmin is set to the tuple's xmin if that is another
                                751                 :                :  * transaction that's still in progress; or to InvalidTransactionId if the
                                752                 :                :  * tuple's xmin is committed good, committed dead, or my own xact.
                                753                 :                :  * Similarly for snapshot->xmax and the tuple's xmax.  If the tuple was
                                754                 :                :  * inserted speculatively, meaning that the inserter might still back down
                                755                 :                :  * on the insertion without aborting the whole transaction, the associated
                                756                 :                :  * token is also returned in snapshot->speculativeToken.
                                757                 :                :  */
                                758                 :                : static bool
 4619 rhaas@postgresql.org      759                 :        5939378 : HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
                                760                 :                :                         Buffer buffer)
                                761                 :                : {
                                762                 :        5939378 :     HeapTupleHeader tuple = htup->t_data;
                                763                 :                : 
                                764         [ -  + ]:        5939378 :     Assert(ItemPointerIsValid(&htup->t_self));
                                765         [ -  + ]:        5939378 :     Assert(htup->t_tableOid != InvalidOid);
                                766                 :                : 
 6930 tgl@sss.pgh.pa.us         767                 :        5939378 :     snapshot->xmin = snapshot->xmax = InvalidTransactionId;
 3964 andres@anarazel.de        768                 :        5939378 :     snapshot->speculativeToken = 0;
                                769                 :                : 
 4466 rhaas@postgresql.org      770         [ +  + ]:        5939378 :     if (!HeapTupleHeaderXminCommitted(tuple))
                                771                 :                :     {
                                772         [ +  + ]:        5583559 :         if (HeapTupleHeaderXminInvalid(tuple))
 9952 vadim4o@yahoo.com         773                 :            495 :             return false;
                                774                 :                : 
   86 andres@anarazel.de        775         [ -  + ]:GNC     5583064 :         if (!HeapTupleCleanMoved(tuple, buffer))
   86 andres@anarazel.de        776                 :UNC           0 :             return false;
 4466 rhaas@postgresql.org      777         [ +  + ]:CBC     5583064 :         else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
                                778                 :                :         {
 9952 vadim4o@yahoo.com         779         [ +  + ]:        5557553 :             if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid */
                                780                 :          31051 :                 return true;
                                781                 :                : 
 4673 bruce@momjian.us          782         [ +  + ]:        5526502 :             if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
 7626 tgl@sss.pgh.pa.us         783                 :           5040 :                 return true;
                                784                 :                : 
 4799 alvherre@alvh.no-ip.      785         [ +  + ]:        5521462 :             if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
                                786                 :                :             {
                                787                 :                :                 TransactionId xmax;
                                788                 :                : 
                                789                 :             16 :                 xmax = HeapTupleGetUpdateXid(tuple);
                                790                 :                : 
                                791                 :                :                 /* not LOCKED_ONLY, so it has to have an xmax */
 4489                           792         [ -  + ]:             16 :                 Assert(TransactionIdIsValid(xmax));
                                793                 :                : 
                                794                 :                :                 /* updating subtransaction must have aborted */
 4799                           795         [ -  + ]:             16 :                 if (!TransactionIdIsCurrentTransactionId(xmax))
 4799 alvherre@alvh.no-ip.      796                 :UBC           0 :                     return true;
                                797                 :                :                 else
 4799 alvherre@alvh.no-ip.      798                 :CBC          16 :                     return false;
                                799                 :                :             }
                                800                 :                : 
                                801         [ -  + ]:        5521446 :             if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
                                802                 :                :             {
                                803                 :                :                 /* deleting subtransaction must have aborted */
 6788 tgl@sss.pgh.pa.us         804                 :UBC           0 :                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
                                805                 :                :                             InvalidTransactionId);
 7927                           806                 :              0 :                 return true;
                                807                 :                :             }
                                808                 :                : 
 9952 vadim4o@yahoo.com         809                 :CBC     5521446 :             return false;
                                810                 :                :         }
 4466 rhaas@postgresql.org      811         [ +  + ]:          25511 :         else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
                                812                 :                :         {
                                813                 :                :             /*
                                814                 :                :              * Return the speculative token to caller.  Caller can worry about
                                815                 :                :              * xmax, since it requires a conclusively locked row version, and
                                816                 :                :              * a concurrent update to this tuple is a conflict of its
                                817                 :                :              * purposes.
                                818                 :                :              */
 3964 andres@anarazel.de        819         [ +  + ]:             46 :             if (HeapTupleHeaderIsSpeculative(tuple))
                                820                 :                :             {
                                821                 :              2 :                 snapshot->speculativeToken =
                                822                 :              2 :                     HeapTupleHeaderGetSpeculativeToken(tuple);
                                823                 :                : 
                                824         [ -  + ]:              2 :                 Assert(snapshot->speculativeToken != 0);
                                825                 :                :             }
                                826                 :                : 
 4466 rhaas@postgresql.org      827                 :             46 :             snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
                                828                 :                :             /* XXX shouldn't we fall through to look at xmax? */
 9791 bruce@momjian.us          829                 :             46 :             return true;        /* in insertion by other */
                                830                 :                :         }
 4466 rhaas@postgresql.org      831         [ +  + ]:          25465 :         else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
 6788 tgl@sss.pgh.pa.us         832                 :          25043 :             SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
                                833                 :                :                         HeapTupleHeaderGetRawXmin(tuple));
                                834                 :                :         else
                                835                 :                :         {
                                836                 :                :             /* it must have aborted or crashed */
                                837                 :            422 :             SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
                                838                 :                :                         InvalidTransactionId);
 7617                           839                 :            422 :             return false;
                                840                 :                :         }
                                841                 :                :     }
                                842                 :                : 
                                843                 :                :     /* by here, the inserting transaction has committed */
                                844                 :                : 
 9952 vadim4o@yahoo.com         845         [ +  + ]:         380862 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid or aborted */
                                846                 :         133245 :         return true;
                                847                 :                : 
                                848         [ +  + ]:         247617 :     if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
                                849                 :                :     {
 4799 alvherre@alvh.no-ip.      850         [ -  + ]:          92335 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
 9952 vadim4o@yahoo.com         851                 :UBC           0 :             return true;
 9791 bruce@momjian.us          852                 :CBC       92335 :         return false;           /* updated by other */
                                853                 :                :     }
                                854                 :                : 
 7626 tgl@sss.pgh.pa.us         855         [ +  + ]:         155282 :     if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
                                856                 :                :     {
                                857                 :                :         TransactionId xmax;
                                858                 :                : 
 4799 alvherre@alvh.no-ip.      859         [ +  + ]:             30 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
                                860                 :             13 :             return true;
                                861                 :                : 
                                862                 :             17 :         xmax = HeapTupleGetUpdateXid(tuple);
                                863                 :                : 
                                864                 :                :         /* not LOCKED_ONLY, so it has to have an xmax */
 4489                           865         [ -  + ]:             17 :         Assert(TransactionIdIsValid(xmax));
                                866                 :                : 
 4799                           867         [ +  + ]:             17 :         if (TransactionIdIsCurrentTransactionId(xmax))
                                868                 :              1 :             return false;
                                869         [ -  + ]:             16 :         if (TransactionIdIsInProgress(xmax))
                                870                 :                :         {
 4799 alvherre@alvh.no-ip.      871                 :UBC           0 :             snapshot->xmax = xmax;
                                872                 :              0 :             return true;
                                873                 :                :         }
 4799 alvherre@alvh.no-ip.      874         [ +  - ]:CBC          16 :         if (TransactionIdDidCommit(xmax))
                                875                 :             16 :             return false;
                                876                 :                :         /* it must have aborted or crashed */
 7626 tgl@sss.pgh.pa.us         877                 :UBC           0 :         return true;
                                878                 :                :     }
                                879                 :                : 
 4799 alvherre@alvh.no-ip.      880         [ +  + ]:CBC      155252 :     if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
                                881                 :                :     {
                                882         [ +  + ]:         116271 :         if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
 9386 inoue@tpf.co.jp           883                 :             50 :             return true;
 9952 vadim4o@yahoo.com         884                 :         116221 :         return false;
                                885                 :                :     }
                                886                 :                : 
 4799 alvherre@alvh.no-ip.      887         [ +  + ]:          38981 :     if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
                                888                 :                :     {
 4608                           889         [ +  + ]:             22 :         if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
                                890                 :             12 :             snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
 7617 tgl@sss.pgh.pa.us         891                 :             22 :         return true;
                                892                 :                :     }
                                893                 :                : 
 4799 alvherre@alvh.no-ip.      894         [ +  + ]:          38959 :     if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
                                895                 :                :     {
                                896                 :                :         /* it must have aborted or crashed */
 6788 tgl@sss.pgh.pa.us         897                 :             39 :         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
                                898                 :                :                     InvalidTransactionId);
 7617                           899                 :             39 :         return true;
                                900                 :                :     }
                                901                 :                : 
                                902                 :                :     /* xmax transaction committed */
                                903                 :                : 
 4799 alvherre@alvh.no-ip.      904         [ +  + ]:          38920 :     if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
                                905                 :                :     {
 6788 tgl@sss.pgh.pa.us         906                 :          13491 :         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
                                907                 :                :                     InvalidTransactionId);
 9952 vadim4o@yahoo.com         908                 :          13491 :         return true;
                                909                 :                :     }
                                910                 :                : 
 6788 tgl@sss.pgh.pa.us         911                 :          25429 :     SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
                                912                 :                :                 HeapTupleHeaderGetRawXmax(tuple));
 9791 bruce@momjian.us          913                 :          25429 :     return false;               /* updated by other */
                                914                 :                : }
                                915                 :                : 
                                916                 :                : /*
                                917                 :                :  * HeapTupleSatisfiesMVCC
                                918                 :                :  *      True iff heap tuple is valid for the given MVCC snapshot.
                                919                 :                :  *
                                920                 :                :  * See SNAPSHOT_MVCC's definition for the intended behaviour.
                                921                 :                :  *
                                922                 :                :  * Notice that here, we will not update the tuple status hint bits if the
                                923                 :                :  * inserting/deleting transaction is still running according to our snapshot,
                                924                 :                :  * even if in reality it's committed or aborted by now.  This is intentional.
                                925                 :                :  * Checking the true transaction state would require access to high-traffic
                                926                 :                :  * shared data structures, creating contention we'd rather do without, and it
                                927                 :                :  * would not change the result of our visibility check anyway.  The hint bits
                                928                 :                :  * will be updated by the first visitor that has a snapshot new enough to see
                                929                 :                :  * the inserting/deleting transaction as done.  In the meantime, the cost of
                                930                 :                :  * leaving the hint bits unset is basically that each HeapTupleSatisfiesMVCC
                                931                 :                :  * call will need to run TransactionIdIsCurrentTransactionId in addition to
                                932                 :                :  * XidInMVCCSnapshot (but it would have to do the latter anyway).  In the old
                                933                 :                :  * coding where we tried to set the hint bits as soon as possible, we instead
                                934                 :                :  * did TransactionIdIsInProgress in each call --- to no avail, as long as the
                                935                 :                :  * inserting/deleting transaction was still running --- which was more cycles
                                936                 :                :  * and more contention on ProcArrayLock.
                                937                 :                :  */
                                938                 :                : static inline bool
 4619 rhaas@postgresql.org      939                 :       83515729 : HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
                                940                 :                :                        Buffer buffer, SetHintBitsState *state)
                                941                 :                : {
                                942                 :       83515729 :     HeapTupleHeader tuple = htup->t_data;
                                943                 :                : 
                                944                 :                :     /*
                                945                 :                :      * Assert that the caller has registered the snapshot.  This function
                                946                 :                :      * doesn't care about the registration as such, but in general you
                                947                 :                :      * shouldn't try to use a snapshot without registration because it might
                                948                 :                :      * get invalidated while it's still in use, and this is a convenient place
                                949                 :                :      * to check for that.
                                950                 :                :      */
  369 heikki.linnakangas@i      951   [ +  +  -  + ]:       83515729 :     Assert(snapshot->regd_count > 0 || snapshot->active_count > 0);
                                952                 :                : 
 4619 rhaas@postgresql.org      953         [ -  + ]:       83515729 :     Assert(ItemPointerIsValid(&htup->t_self));
                                954         [ -  + ]:       83515729 :     Assert(htup->t_tableOid != InvalidOid);
                                955                 :                : 
 4466                           956         [ +  + ]:       83515729 :     if (!HeapTupleHeaderXminCommitted(tuple))
                                957                 :                :     {
                                958         [ +  + ]:       15609651 :         if (HeapTupleHeaderXminInvalid(tuple))
 9951 vadim4o@yahoo.com         959                 :         206134 :             return false;
                                960                 :                : 
   86 andres@anarazel.de        961         [ -  + ]:GNC    15403517 :         if (!HeapTupleCleanMoved(tuple, buffer))
   86 andres@anarazel.de        962                 :UNC           0 :             return false;
 4466 rhaas@postgresql.org      963         [ +  + ]:CBC    15403517 :         else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
                                964                 :                :         {
 8674 bruce@momjian.us          965         [ +  + ]:       11084768 :             if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
 9951 vadim4o@yahoo.com         966                 :           6463 :                 return false;   /* inserted after scan started */
                                967                 :                : 
                                968         [ +  + ]:       11078305 :             if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid */
                                969                 :        8131181 :                 return true;
                                970                 :                : 
 4673 bruce@momjian.us          971         [ +  + ]:        2947124 :             if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
 7626 tgl@sss.pgh.pa.us         972                 :           2160 :                 return true;
                                973                 :                : 
 4799 alvherre@alvh.no-ip.      974         [ +  + ]:        2944964 :             if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
                                975                 :                :             {
                                976                 :                :                 TransactionId xmax;
                                977                 :                : 
                                978                 :              7 :                 xmax = HeapTupleGetUpdateXid(tuple);
                                979                 :                : 
                                980                 :                :                 /* not LOCKED_ONLY, so it has to have an xmax */
 4489                           981         [ -  + ]:              7 :                 Assert(TransactionIdIsValid(xmax));
                                982                 :                : 
                                983                 :                :                 /* updating subtransaction must have aborted */
 4799                           984         [ +  - ]:              7 :                 if (!TransactionIdIsCurrentTransactionId(xmax))
                                985                 :              7 :                     return true;
 4799 alvherre@alvh.no-ip.      986         [ #  # ]:UBC           0 :                 else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
                                987                 :              0 :                     return true;    /* updated after scan started */
                                988                 :                :                 else
 3189 tgl@sss.pgh.pa.us         989                 :              0 :                     return false;   /* updated before scan started */
                                990                 :                :             }
                                991                 :                : 
 4799 alvherre@alvh.no-ip.      992         [ +  + ]:CBC     2944957 :             if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
                                993                 :                :             {
                                994                 :                :                 /* deleting subtransaction must have aborted */
    5 andres@anarazel.de        995                 :GNC          35 :                 SetHintBitsExt(tuple, buffer, HEAP_XMAX_INVALID,
                                996                 :                :                                InvalidTransactionId, state);
 7927 tgl@sss.pgh.pa.us         997                 :CBC          35 :                 return true;
                                998                 :                :             }
                                999                 :                : 
 8674 bruce@momjian.us         1000         [ +  + ]:        2944922 :             if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
 9951 vadim4o@yahoo.com        1001                 :            848 :                 return true;    /* deleted after scan started */
                               1002                 :                :             else
                               1003                 :        2944074 :                 return false;   /* deleted before scan started */
                               1004                 :                :         }
 3854 tgl@sss.pgh.pa.us        1005         [ +  + ]:        4318749 :         else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
 9951 vadim4o@yahoo.com        1006                 :          27546 :             return false;
 4466 rhaas@postgresql.org     1007         [ +  + ]:        4291203 :         else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
    5 andres@anarazel.de       1008                 :GNC     4236907 :             SetHintBitsExt(tuple, buffer, HEAP_XMIN_COMMITTED,
                               1009                 :                :                            HeapTupleHeaderGetRawXmin(tuple), state);
                               1010                 :                :         else
                               1011                 :                :         {
                               1012                 :                :             /* it must have aborted or crashed */
                               1013                 :          54296 :             SetHintBitsExt(tuple, buffer, HEAP_XMIN_INVALID,
                               1014                 :                :                            InvalidTransactionId, state);
 7617 tgl@sss.pgh.pa.us        1015                 :CBC       54296 :             return false;
                               1016                 :                :         }
                               1017                 :                :     }
                               1018                 :                :     else
                               1019                 :                :     {
                               1020                 :                :         /* xmin is committed, but maybe not according to our snapshot */
 3854                          1021   [ +  +  +  + ]:      131605072 :         if (!HeapTupleHeaderXminFrozen(tuple) &&
                               1022                 :       63698994 :             XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
                               1023                 :           4578 :             return false;       /* treat as still in progress */
                               1024                 :                :     }
                               1025                 :                : 
                               1026                 :                :     /* by here, the inserting transaction has committed */
                               1027                 :                : 
 9951 vadim4o@yahoo.com        1028         [ +  + ]:       72138407 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid or aborted */
                               1029                 :       65972017 :         return true;
                               1030                 :                : 
 4799 alvherre@alvh.no-ip.     1031         [ +  + ]:        6166390 :     if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
 7626 tgl@sss.pgh.pa.us        1032                 :         216686 :         return true;
                               1033                 :                : 
                               1034         [ +  + ]:        5949704 :     if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
                               1035                 :                :     {
                               1036                 :                :         TransactionId xmax;
                               1037                 :                : 
                               1038                 :                :         /* already checked above */
 4799 alvherre@alvh.no-ip.     1039         [ -  + ]:          78653 :         Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
                               1040                 :                : 
                               1041                 :          78653 :         xmax = HeapTupleGetUpdateXid(tuple);
                               1042                 :                : 
                               1043                 :                :         /* not LOCKED_ONLY, so it has to have an xmax */
 4489                          1044         [ -  + ]:          78653 :         Assert(TransactionIdIsValid(xmax));
                               1045                 :                : 
 4799                          1046         [ +  + ]:          78653 :         if (TransactionIdIsCurrentTransactionId(xmax))
                               1047                 :                :         {
                               1048         [ -  + ]:             23 :             if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
 4799 alvherre@alvh.no-ip.     1049                 :UBC           0 :                 return true;    /* deleted after scan started */
                               1050                 :                :             else
 4799 alvherre@alvh.no-ip.     1051                 :CBC          23 :                 return false;   /* deleted before scan started */
                               1052                 :                :         }
 3854 tgl@sss.pgh.pa.us        1053         [ +  + ]:          78630 :         if (XidInMVCCSnapshot(xmax, snapshot))
 4799 alvherre@alvh.no-ip.     1054                 :           2126 :             return true;
                               1055         [ +  + ]:          76504 :         if (TransactionIdDidCommit(xmax))
 3854 tgl@sss.pgh.pa.us        1056                 :          76488 :             return false;       /* updating transaction committed */
                               1057                 :                :         /* it must have aborted or crashed */
 9951 vadim4o@yahoo.com        1058                 :             16 :         return true;
                               1059                 :                :     }
                               1060                 :                : 
                               1061         [ +  + ]:        5871051 :     if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
                               1062                 :                :     {
 4799 alvherre@alvh.no-ip.     1063         [ +  + ]:         483366 :         if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
                               1064                 :                :         {
 8674 bruce@momjian.us         1065         [ +  + ]:         144512 :             if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
 9791                          1066                 :           1367 :                 return true;    /* deleted after scan started */
                               1067                 :                :             else
                               1068                 :         143145 :                 return false;   /* deleted before scan started */
                               1069                 :                :         }
                               1070                 :                : 
 3854 tgl@sss.pgh.pa.us        1071         [ +  + ]:         338854 :         if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
 7617                          1072                 :          15361 :             return true;
                               1073                 :                : 
 4799 alvherre@alvh.no-ip.     1074         [ +  + ]:         323493 :         if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
                               1075                 :                :         {
                               1076                 :                :             /* it must have aborted or crashed */
    5 andres@anarazel.de       1077                 :GNC        6805 :             SetHintBitsExt(tuple, buffer, HEAP_XMAX_INVALID,
                               1078                 :                :                            InvalidTransactionId, state);
 9951 vadim4o@yahoo.com        1079                 :CBC        6805 :             return true;
                               1080                 :                :         }
                               1081                 :                : 
                               1082                 :                :         /* xmax transaction committed */
    5 andres@anarazel.de       1083                 :GNC      316688 :         SetHintBitsExt(tuple, buffer, HEAP_XMAX_COMMITTED,
                               1084                 :                :                        HeapTupleHeaderGetRawXmax(tuple), state);
                               1085                 :                :     }
                               1086                 :                :     else
                               1087                 :                :     {
                               1088                 :                :         /* xmax is committed, but maybe not according to our snapshot */
 3854 tgl@sss.pgh.pa.us        1089         [ +  + ]:CBC     5387685 :         if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
                               1090                 :           1088 :             return true;        /* treat as still in progress */
                               1091                 :                :     }
                               1092                 :                : 
                               1093                 :                :     /* xmax transaction committed */
                               1094                 :                : 
 9951 vadim4o@yahoo.com        1095                 :        5703285 :     return false;
                               1096                 :                : }
                               1097                 :                : 
                               1098                 :                : 
                               1099                 :                : /*
                               1100                 :                :  * HeapTupleSatisfiesVacuum
                               1101                 :                :  *
                               1102                 :                :  *  Determine the status of tuples for VACUUM purposes.  Here, what
                               1103                 :                :  *  we mainly want to know is if a tuple is potentially visible to *any*
                               1104                 :                :  *  running transaction.  If so, it can't be removed yet by VACUUM.
                               1105                 :                :  *
                               1106                 :                :  * OldestXmin is a cutoff XID (obtained from
                               1107                 :                :  * GetOldestNonRemovableTransactionId()).  Tuples deleted by XIDs >=
                               1108                 :                :  * OldestXmin are deemed "recently dead"; they might still be visible to some
                               1109                 :                :  * open transaction, so we can't remove them, even if we see that the deleting
                               1110                 :                :  * transaction has committed.
                               1111                 :                :  */
                               1112                 :                : HTSV_Result
 4619 rhaas@postgresql.org     1113                 :        7780310 : HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin,
                               1114                 :                :                          Buffer buffer)
                               1115                 :                : {
 2041 andres@anarazel.de       1116                 :        7780310 :     TransactionId dead_after = InvalidTransactionId;
                               1117                 :                :     HTSV_Result res;
                               1118                 :                : 
                               1119                 :        7780310 :     res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
                               1120                 :                : 
                               1121         [ +  + ]:        7780310 :     if (res == HEAPTUPLE_RECENTLY_DEAD)
                               1122                 :                :     {
                               1123         [ -  + ]:         146786 :         Assert(TransactionIdIsValid(dead_after));
                               1124                 :                : 
                               1125         [ +  + ]:         146786 :         if (TransactionIdPrecedes(dead_after, OldestXmin))
                               1126                 :          17555 :             res = HEAPTUPLE_DEAD;
                               1127                 :                :     }
                               1128                 :                :     else
                               1129         [ -  + ]:        7633524 :         Assert(!TransactionIdIsValid(dead_after));
                               1130                 :                : 
                               1131                 :        7780310 :     return res;
                               1132                 :                : }
                               1133                 :                : 
                               1134                 :                : /*
                               1135                 :                :  * Work horse for HeapTupleSatisfiesVacuum and similar routines.
                               1136                 :                :  *
                               1137                 :                :  * In contrast to HeapTupleSatisfiesVacuum this routine, when encountering a
                               1138                 :                :  * tuple that could still be visible to some backend, stores the xid that
                               1139                 :                :  * needs to be compared with the horizon in *dead_after, and returns
                               1140                 :                :  * HEAPTUPLE_RECENTLY_DEAD. The caller then can perform the comparison with
                               1141                 :                :  * the horizon.  This is e.g. useful when comparing with different horizons.
                               1142                 :                :  *
                               1143                 :                :  * Note: HEAPTUPLE_DEAD can still be returned here, e.g. if the inserting
                               1144                 :                :  * transaction aborted.
                               1145                 :                :  */
                               1146                 :                : HTSV_Result
                               1147                 :       26440987 : HeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *dead_after)
                               1148                 :                : {
 4619 rhaas@postgresql.org     1149                 :       26440987 :     HeapTupleHeader tuple = htup->t_data;
                               1150                 :                : 
                               1151         [ -  + ]:       26440987 :     Assert(ItemPointerIsValid(&htup->t_self));
                               1152         [ -  + ]:       26440987 :     Assert(htup->t_tableOid != InvalidOid);
 2041 andres@anarazel.de       1153         [ -  + ]:       26440987 :     Assert(dead_after != NULL);
                               1154                 :                : 
                               1155                 :       26440987 :     *dead_after = InvalidTransactionId;
                               1156                 :                : 
                               1157                 :                :     /*
                               1158                 :                :      * Has inserting transaction committed?
                               1159                 :                :      *
                               1160                 :                :      * If the inserting transaction aborted, then the tuple was never visible
                               1161                 :                :      * to any other transaction, so we can delete it immediately.
                               1162                 :                :      */
 4466 rhaas@postgresql.org     1163         [ +  + ]:       26440987 :     if (!HeapTupleHeaderXminCommitted(tuple))
                               1164                 :                :     {
                               1165         [ +  + ]:        6658514 :         if (HeapTupleHeaderXminInvalid(tuple))
 9012 tgl@sss.pgh.pa.us        1166                 :          16322 :             return HEAPTUPLE_DEAD;
   86 andres@anarazel.de       1167         [ -  + ]:GNC     6642192 :         else if (!HeapTupleCleanMoved(tuple, buffer))
   86 andres@anarazel.de       1168                 :UNC           0 :             return HEAPTUPLE_DEAD;
 4302 andres@anarazel.de       1169         [ +  + ]:CBC     6642192 :         else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
                               1170                 :                :         {
 8210 tgl@sss.pgh.pa.us        1171         [ +  + ]:        2101530 :             if (tuple->t_infomask & HEAP_XMAX_INVALID)   /* xid invalid */
                               1172                 :        2065416 :                 return HEAPTUPLE_INSERT_IN_PROGRESS;
                               1173                 :                :             /* only locked? run infomask-only check first, for performance */
 4622 alvherre@alvh.no-ip.     1174   [ +  +  -  + ]:          64097 :             if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) ||
                               1175                 :          27983 :                 HeapTupleHeaderIsOnlyLocked(tuple))
 8210 tgl@sss.pgh.pa.us        1176                 :           8131 :                 return HEAPTUPLE_INSERT_IN_PROGRESS;
                               1177                 :                :             /* inserted and then deleted by same xact */
 4302 andres@anarazel.de       1178         [ +  - ]:          27983 :             if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple)))
                               1179                 :          27983 :                 return HEAPTUPLE_DELETE_IN_PROGRESS;
                               1180                 :                :             /* deleting subtransaction must have aborted */
 4302 andres@anarazel.de       1181                 :UBC           0 :             return HEAPTUPLE_INSERT_IN_PROGRESS;
                               1182                 :                :         }
 4302 andres@anarazel.de       1183         [ +  + ]:CBC     4540662 :         else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
                               1184                 :                :         {
                               1185                 :                :             /*
                               1186                 :                :              * It'd be possible to discern between INSERT/DELETE in progress
                               1187                 :                :              * here by looking at xmax - but that doesn't seem beneficial for
                               1188                 :                :              * the majority of callers and even detrimental for some. We'd
                               1189                 :                :              * rather have callers look at/wait for xmin than xmax. It's
                               1190                 :                :              * always correct to return INSERT_IN_PROGRESS because that's
                               1191                 :                :              * what's happening from the view of other backends.
                               1192                 :                :              */
                               1193                 :           4339 :             return HEAPTUPLE_INSERT_IN_PROGRESS;
                               1194                 :                :         }
 4466 rhaas@postgresql.org     1195         [ +  + ]:        4536323 :         else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
 6788 tgl@sss.pgh.pa.us        1196                 :        4501542 :             SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
                               1197                 :                :                         HeapTupleHeaderGetRawXmin(tuple));
                               1198                 :                :         else
                               1199                 :                :         {
                               1200                 :                :             /*
                               1201                 :                :              * Not in Progress, Not Committed, so either Aborted or crashed
                               1202                 :                :              */
                               1203                 :          34781 :             SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
                               1204                 :                :                         InvalidTransactionId);
 9012                          1205                 :          34781 :             return HEAPTUPLE_DEAD;
                               1206                 :                :         }
                               1207                 :                : 
                               1208                 :                :         /*
                               1209                 :                :          * At this point the xmin is known committed, but we might not have
                               1210                 :                :          * been able to set the hint bit yet; so we can no longer Assert that
                               1211                 :                :          * it's set.
                               1212                 :                :          */
                               1213                 :                :     }
                               1214                 :                : 
                               1215                 :                :     /*
                               1216                 :                :      * Okay, the inserter committed, so it was good at some point.  Now what
                               1217                 :                :      * about the deleting transaction?
                               1218                 :                :      */
                               1219         [ +  + ]:       24284015 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)
                               1220                 :       22145990 :         return HEAPTUPLE_LIVE;
                               1221                 :                : 
 4799 alvherre@alvh.no-ip.     1222         [ +  + ]:        2138025 :     if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
                               1223                 :                :     {
                               1224                 :                :         /*
                               1225                 :                :          * "Deleting" xact really only locked it, so the tuple is live in any
                               1226                 :                :          * case.  However, we should make sure that either XMAX_COMMITTED or
                               1227                 :                :          * XMAX_INVALID gets set once the xact is gone, to reduce the costs of
                               1228                 :                :          * examining the tuple for future xacts.
                               1229                 :                :          */
 8829 tgl@sss.pgh.pa.us        1230         [ +  - ]:          13502 :         if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
                               1231                 :                :         {
 7626                          1232         [ +  + ]:          13502 :             if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
                               1233                 :                :             {
                               1234                 :                :                 /*
                               1235                 :                :                  * If it's a pre-pg_upgrade tuple, the multixact cannot
                               1236                 :                :                  * possibly be running; otherwise have to check.
                               1237                 :                :                  */
 3551 alvherre@alvh.no-ip.     1238   [ +  -  +  + ]:            496 :                 if (!HEAP_LOCKED_UPGRADED(tuple->t_infomask) &&
 4247                          1239                 :            248 :                     MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),
                               1240                 :                :                                          true))
 7626 tgl@sss.pgh.pa.us        1241                 :             21 :                     return HEAPTUPLE_LIVE;
 4799 alvherre@alvh.no-ip.     1242                 :            227 :                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
                               1243                 :                :             }
                               1244                 :                :             else
                               1245                 :                :             {
                               1246         [ +  + ]:          13254 :                 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
 7626 tgl@sss.pgh.pa.us        1247                 :GBC           4 :                     return HEAPTUPLE_LIVE;
 4799 alvherre@alvh.no-ip.     1248                 :CBC       13250 :                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
                               1249                 :                :                             InvalidTransactionId);
                               1250                 :                :             }
                               1251                 :                :         }
                               1252                 :                : 
                               1253                 :                :         /*
                               1254                 :                :          * We don't really care whether xmax did commit, abort or crash. We
                               1255                 :                :          * know that xmax did lock the tuple, but it did not and will never
                               1256                 :                :          * actually update it.
                               1257                 :                :          */
                               1258                 :                : 
 8852 tgl@sss.pgh.pa.us        1259                 :          13477 :         return HEAPTUPLE_LIVE;
                               1260                 :                :     }
                               1261                 :                : 
 7626                          1262         [ +  + ]:        2124523 :     if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
                               1263                 :                :     {
 3054 andres@anarazel.de       1264                 :            102 :         TransactionId xmax = HeapTupleGetUpdateXid(tuple);
                               1265                 :                : 
                               1266                 :                :         /* already checked above */
                               1267         [ -  + ]:            102 :         Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
                               1268                 :                : 
                               1269                 :                :         /* not LOCKED_ONLY, so it has to have an xmax */
 4489 alvherre@alvh.no-ip.     1270         [ -  + ]:            102 :         Assert(TransactionIdIsValid(xmax));
                               1271                 :                : 
 3054 andres@anarazel.de       1272         [ +  + ]:            102 :         if (TransactionIdIsInProgress(xmax))
 3054 andres@anarazel.de       1273                 :GBC           1 :             return HEAPTUPLE_DELETE_IN_PROGRESS;
 3054 andres@anarazel.de       1274         [ +  - ]:CBC         101 :         else if (TransactionIdDidCommit(xmax))
                               1275                 :                :         {
                               1276                 :                :             /*
                               1277                 :                :              * The multixact might still be running due to lockers.  Need to
                               1278                 :                :              * allow for pruning if below the xid horizon regardless --
                               1279                 :                :              * otherwise we could end up with a tuple where the updater has to
                               1280                 :                :              * be removed due to the horizon, but is not pruned away.  It's
                               1281                 :                :              * not a problem to prune that tuple, because any remaining
                               1282                 :                :              * lockers will also be present in newer tuple versions.
                               1283                 :                :              */
 2041                          1284                 :            101 :             *dead_after = xmax;
                               1285                 :            101 :             return HEAPTUPLE_RECENTLY_DEAD;
                               1286                 :                :         }
 3054 andres@anarazel.de       1287         [ #  # ]:UBC           0 :         else if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
                               1288                 :                :         {
                               1289                 :                :             /*
                               1290                 :                :              * Not in Progress, Not Committed, so either Aborted or crashed.
                               1291                 :                :              * Mark the Xmax as invalid.
                               1292                 :                :              */
                               1293                 :              0 :             SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
                               1294                 :                :         }
                               1295                 :                : 
 4489 alvherre@alvh.no-ip.     1296                 :              0 :         return HEAPTUPLE_LIVE;
                               1297                 :                :     }
                               1298                 :                : 
 9012 tgl@sss.pgh.pa.us        1299         [ +  + ]:CBC     2124421 :     if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
                               1300                 :                :     {
 4799 alvherre@alvh.no-ip.     1301         [ +  + ]:        1344263 :         if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
 9008 tgl@sss.pgh.pa.us        1302                 :          54801 :             return HEAPTUPLE_DELETE_IN_PROGRESS;
 4799 alvherre@alvh.no-ip.     1303         [ +  + ]:        1289462 :         else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
 6788 tgl@sss.pgh.pa.us        1304                 :        1287493 :             SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
                               1305                 :                :                         HeapTupleHeaderGetRawXmax(tuple));
                               1306                 :                :         else
                               1307                 :                :         {
                               1308                 :                :             /*
                               1309                 :                :              * Not in Progress, Not Committed, so either Aborted or crashed
                               1310                 :                :              */
                               1311                 :           1969 :             SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
                               1312                 :                :                         InvalidTransactionId);
 9012                          1313                 :           1969 :             return HEAPTUPLE_LIVE;
                               1314                 :                :         }
                               1315                 :                : 
                               1316                 :                :         /*
                               1317                 :                :          * At this point the xmax is known committed, but we might not have
                               1318                 :                :          * been able to set the hint bit yet; so we can no longer Assert that
                               1319                 :                :          * it's set.
                               1320                 :                :          */
                               1321                 :                :     }
                               1322                 :                : 
                               1323                 :                :     /*
                               1324                 :                :      * Deleter committed, allow caller to check if it was recent enough that
                               1325                 :                :      * some open transactions could still see the tuple.
                               1326                 :                :      */
 2041 andres@anarazel.de       1327                 :        2067651 :     *dead_after = HeapTupleHeaderGetRawXmax(tuple);
                               1328                 :        2067651 :     return HEAPTUPLE_RECENTLY_DEAD;
                               1329                 :                : }
                               1330                 :                : 
                               1331                 :                : 
                               1332                 :                : /*
                               1333                 :                :  * HeapTupleSatisfiesNonVacuumable
                               1334                 :                :  *
                               1335                 :                :  *  True if tuple might be visible to some transaction; false if it's
                               1336                 :                :  *  surely dead to everyone, ie, vacuumable.
                               1337                 :                :  *
                               1338                 :                :  *  See SNAPSHOT_NON_VACUUMABLE's definition for the intended behaviour.
                               1339                 :                :  *
                               1340                 :                :  *  This is an interface to HeapTupleSatisfiesVacuum that's callable via
                               1341                 :                :  *  HeapTupleSatisfiesSnapshot, so it can be used through a Snapshot.
                               1342                 :                :  *  snapshot->vistest must have been set up with the horizon to use.
                               1343                 :                :  */
                               1344                 :                : static bool
 3111 tgl@sss.pgh.pa.us        1345                 :         361436 : HeapTupleSatisfiesNonVacuumable(HeapTuple htup, Snapshot snapshot,
                               1346                 :                :                                 Buffer buffer)
                               1347                 :                : {
 2041 andres@anarazel.de       1348                 :         361436 :     TransactionId dead_after = InvalidTransactionId;
                               1349                 :                :     HTSV_Result res;
                               1350                 :                : 
                               1351                 :         361436 :     res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
                               1352                 :                : 
                               1353         [ +  + ]:         361436 :     if (res == HEAPTUPLE_RECENTLY_DEAD)
                               1354                 :                :     {
                               1355         [ -  + ]:          82071 :         Assert(TransactionIdIsValid(dead_after));
                               1356                 :                : 
                               1357         [ +  + ]:          82071 :         if (GlobalVisTestIsRemovableXid(snapshot->vistest, dead_after))
                               1358                 :          67428 :             res = HEAPTUPLE_DEAD;
                               1359                 :                :     }
                               1360                 :                :     else
                               1361         [ -  + ]:         279365 :         Assert(!TransactionIdIsValid(dead_after));
                               1362                 :                : 
                               1363                 :         361436 :     return res != HEAPTUPLE_DEAD;
                               1364                 :                : }
                               1365                 :                : 
                               1366                 :                : 
                               1367                 :                : /*
                               1368                 :                :  * HeapTupleIsSurelyDead
                               1369                 :                :  *
                               1370                 :                :  *  Cheaply determine whether a tuple is surely dead to all onlookers.
                               1371                 :                :  *  We sometimes use this in lieu of HeapTupleSatisfiesVacuum when the
                               1372                 :                :  *  tuple has just been tested by another visibility routine (usually
                               1373                 :                :  *  HeapTupleSatisfiesMVCC) and, therefore, any hint bits that can be set
                               1374                 :                :  *  should already be set.  We assume that if no hint bits are set, the xmin
                               1375                 :                :  *  or xmax transaction is still running.  This is therefore faster than
                               1376                 :                :  *  HeapTupleSatisfiesVacuum, because we consult neither procarray nor CLOG.
                               1377                 :                :  *  It's okay to return false when in doubt, but we must return true only
                               1378                 :                :  *  if the tuple is removable.
                               1379                 :                :  */
                               1380                 :                : bool
                               1381                 :        6500366 : HeapTupleIsSurelyDead(HeapTuple htup, GlobalVisState *vistest)
                               1382                 :                : {
 4619 rhaas@postgresql.org     1383                 :        6500366 :     HeapTupleHeader tuple = htup->t_data;
                               1384                 :                : 
                               1385         [ -  + ]:        6500366 :     Assert(ItemPointerIsValid(&htup->t_self));
                               1386         [ -  + ]:        6500366 :     Assert(htup->t_tableOid != InvalidOid);
                               1387                 :                : 
                               1388                 :                :     /*
                               1389                 :                :      * If the inserting transaction is marked invalid, then it aborted, and
                               1390                 :                :      * the tuple is definitely dead.  If it's marked neither committed nor
                               1391                 :                :      * invalid, then we assume it's still alive (since the presumption is that
                               1392                 :                :      * all relevant hint bits were just set moments ago).
                               1393                 :                :      */
 4466                          1394         [ +  + ]:        6500366 :     if (!HeapTupleHeaderXminCommitted(tuple))
 1649 michael@paquier.xyz      1395                 :        5649677 :         return HeapTupleHeaderXminInvalid(tuple);
                               1396                 :                : 
                               1397                 :                :     /*
                               1398                 :                :      * If the inserting transaction committed, but any deleting transaction
                               1399                 :                :      * aborted, the tuple is still alive.
                               1400                 :                :      */
 4799 alvherre@alvh.no-ip.     1401         [ +  + ]:         850689 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)
                               1402                 :             40 :         return false;
                               1403                 :                : 
                               1404                 :                :     /*
                               1405                 :                :      * If the XMAX is just a lock, the tuple is still alive.
                               1406                 :                :      */
                               1407         [ +  + ]:         850649 :     if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
 4799 alvherre@alvh.no-ip.     1408                 :GBC           2 :         return false;
                               1409                 :                : 
                               1410                 :                :     /*
                               1411                 :                :      * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
                               1412                 :                :      * know without checking pg_multixact.
                               1413                 :                :      */
 4799 alvherre@alvh.no-ip.     1414         [ +  + ]:CBC      850647 :     if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
 5065 rhaas@postgresql.org     1415                 :            146 :         return false;
                               1416                 :                : 
                               1417                 :                :     /* If deleter isn't known to have committed, assume it's still running. */
                               1418         [ +  + ]:         850501 :     if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
                               1419                 :         219050 :         return false;
                               1420                 :                : 
                               1421                 :                :     /* Deleter committed, so tuple is dead if the XID is old enough. */
 2041 andres@anarazel.de       1422                 :         631451 :     return GlobalVisTestIsRemovableXid(vistest,
                               1423                 :                :                                        HeapTupleHeaderGetRawXmax(tuple));
                               1424                 :                : }
                               1425                 :                : 
                               1426                 :                : /*
                               1427                 :                :  * Is the tuple really only locked?  That is, is it not updated?
                               1428                 :                :  *
                               1429                 :                :  * It's easy to check just infomask bits if the locker is not a multi; but
                               1430                 :                :  * otherwise we need to verify that the updating transaction has not aborted.
                               1431                 :                :  *
                               1432                 :                :  * This function is here because it follows the same visibility rules laid out
                               1433                 :                :  * at the top of this file.
                               1434                 :                :  */
                               1435                 :                : bool
 4799 alvherre@alvh.no-ip.     1436                 :         114970 : HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
                               1437                 :                : {
                               1438                 :                :     TransactionId xmax;
                               1439                 :                : 
                               1440                 :                :     /* if there's no valid Xmax, then there's obviously no update either */
                               1441         [ -  + ]:         114970 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)
 4799 alvherre@alvh.no-ip.     1442                 :UBC           0 :         return true;
                               1443                 :                : 
 4799 alvherre@alvh.no-ip.     1444         [ +  + ]:CBC      114970 :     if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
                               1445                 :          71681 :         return true;
                               1446                 :                : 
                               1447                 :                :     /* invalid xmax means no update */
                               1448         [ -  + ]:          43289 :     if (!TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple)))
 4799 alvherre@alvh.no-ip.     1449                 :UBC           0 :         return true;
                               1450                 :                : 
                               1451                 :                :     /*
                               1452                 :                :      * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
                               1453                 :                :      * necessarily have been updated
                               1454                 :                :      */
 4799 alvherre@alvh.no-ip.     1455         [ +  + ]:CBC       43289 :     if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
                               1456                 :          41141 :         return false;
                               1457                 :                : 
                               1458                 :                :     /* ... but if it's a multi, then perhaps the updating Xid aborted. */
                               1459                 :           2148 :     xmax = HeapTupleGetUpdateXid(tuple);
                               1460                 :                : 
                               1461                 :                :     /* not LOCKED_ONLY, so it has to have an xmax */
 4489                          1462         [ -  + ]:           2148 :     Assert(TransactionIdIsValid(xmax));
                               1463                 :                : 
 4799                          1464         [ -  + ]:           2148 :     if (TransactionIdIsCurrentTransactionId(xmax))
 4799 alvherre@alvh.no-ip.     1465                 :UBC           0 :         return false;
 4799 alvherre@alvh.no-ip.     1466         [ +  + ]:CBC        2148 :     if (TransactionIdIsInProgress(xmax))
                               1467                 :           2112 :         return false;
                               1468         [ +  + ]:             36 :     if (TransactionIdDidCommit(xmax))
                               1469                 :             12 :         return false;
                               1470                 :                : 
                               1471                 :                :     /*
                               1472                 :                :      * not current, not in progress, not committed -- must have aborted or
                               1473                 :                :      * crashed
                               1474                 :                :      */
                               1475                 :             24 :     return true;
                               1476                 :                : }
                               1477                 :                : 
                               1478                 :                : /*
                               1479                 :                :  * check whether the transaction id 'xid' is in the pre-sorted array 'xip'.
                               1480                 :                :  */
                               1481                 :                : static bool
 4395 rhaas@postgresql.org     1482                 :          53071 : TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num)
                               1483                 :                : {
 1473 tgl@sss.pgh.pa.us        1484   [ +  +  +  + ]:          73777 :     return num > 0 &&
                               1485                 :          20706 :         bsearch(&xid, xip, num, sizeof(TransactionId), xidComparator) != NULL;
                               1486                 :                : }
                               1487                 :                : 
                               1488                 :                : /*
                               1489                 :                :  * See the comments for HeapTupleSatisfiesMVCC for the semantics this function
                               1490                 :                :  * obeys.
                               1491                 :                :  *
                               1492                 :                :  * Only usable on tuples from catalog tables!
                               1493                 :                :  *
                               1494                 :                :  * We don't need to support HEAP_MOVED_(IN|OFF) for now because we only support
                               1495                 :                :  * reading catalog pages which couldn't have been created in an older version.
                               1496                 :                :  *
                               1497                 :                :  * We don't set any hint bits in here as it seems unlikely to be beneficial as
                               1498                 :                :  * those should already be set by normal access and it seems to be too
                               1499                 :                :  * dangerous to do so as the semantics of doing so during timetravel are more
                               1500                 :                :  * complicated than when dealing "only" with the present.
                               1501                 :                :  */
                               1502                 :                : static bool
 4395 rhaas@postgresql.org     1503                 :          44425 : HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
                               1504                 :                :                                Buffer buffer)
                               1505                 :                : {
                               1506                 :          44425 :     HeapTupleHeader tuple = htup->t_data;
                               1507                 :          44425 :     TransactionId xmin = HeapTupleHeaderGetXmin(tuple);
                               1508                 :          44425 :     TransactionId xmax = HeapTupleHeaderGetRawXmax(tuple);
                               1509                 :                : 
                               1510         [ -  + ]:          44425 :     Assert(ItemPointerIsValid(&htup->t_self));
                               1511         [ -  + ]:          44425 :     Assert(htup->t_tableOid != InvalidOid);
                               1512                 :                : 
                               1513                 :                :     /* inserting transaction aborted */
                               1514         [ +  + ]:          44425 :     if (HeapTupleHeaderXminInvalid(tuple))
                               1515                 :                :     {
                               1516         [ -  + ]:             75 :         Assert(!TransactionIdDidCommit(xmin));
                               1517                 :             75 :         return false;
                               1518                 :                :     }
                               1519                 :                :     /* check if it's one of our txids, toplevel is also in there */
                               1520         [ +  + ]:          44350 :     else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
                               1521                 :                :     {
                               1522                 :                :         bool        resolved;
                               1523                 :            513 :         CommandId   cmin = HeapTupleHeaderGetRawCommandId(tuple);
                               1524                 :            513 :         CommandId   cmax = InvalidCommandId;
                               1525                 :                : 
                               1526                 :                :         /*
                               1527                 :                :          * another transaction might have (tried to) delete this tuple or
                               1528                 :                :          * cmin/cmax was stored in a combo CID. So we need to lookup the
                               1529                 :                :          * actual values externally.
                               1530                 :                :          */
                               1531                 :            513 :         resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
                               1532                 :                :                                                  htup, buffer,
                               1533                 :                :                                                  &cmin, &cmax);
                               1534                 :                : 
                               1535                 :                :         /*
                               1536                 :                :          * If we haven't resolved the combo CID to cmin/cmax, that means we
                               1537                 :                :          * have not decoded the combo CID yet. That means the cmin is
                               1538                 :                :          * definitely in the future, and we're not supposed to see the tuple
                               1539                 :                :          * yet.
                               1540                 :                :          *
                               1541                 :                :          * XXX This only applies to decoding of in-progress transactions. In
                               1542                 :                :          * regular logical decoding we only execute this code at commit time,
                               1543                 :                :          * at which point we should have seen all relevant combo CIDs. So
                               1544                 :                :          * ideally, we should error out in this case but in practice, this
                               1545                 :                :          * won't happen. If we are too worried about this then we can add an
                               1546                 :                :          * elog inside ResolveCminCmaxDuringDecoding.
                               1547                 :                :          *
                               1548                 :                :          * XXX For the streaming case, we can track the largest combo CID
                               1549                 :                :          * assigned, and error out based on this (when unable to resolve combo
                               1550                 :                :          * CID below that observed maximum value).
                               1551                 :                :          */
                               1552         [ +  + ]:            513 :         if (!resolved)
 2045 akapila@postgresql.o     1553                 :             73 :             return false;
                               1554                 :                : 
 4395 rhaas@postgresql.org     1555         [ -  + ]:            508 :         Assert(cmin != InvalidCommandId);
                               1556                 :                : 
                               1557         [ +  + ]:            508 :         if (cmin >= snapshot->curcid)
 4331 bruce@momjian.us         1558                 :             68 :             return false;       /* inserted after scan started */
                               1559                 :                :         /* fall through */
                               1560                 :                :     }
                               1561                 :                :     /* committed before our xmin horizon. Do a normal visibility check. */
 4395 rhaas@postgresql.org     1562         [ +  + ]:          43837 :     else if (TransactionIdPrecedes(xmin, snapshot->xmin))
                               1563                 :                :     {
                               1564   [ +  +  -  + ]:          40699 :         Assert(!(HeapTupleHeaderXminCommitted(tuple) &&
                               1565                 :                :                  !TransactionIdDidCommit(xmin)));
                               1566                 :                : 
                               1567                 :                :         /* check for hint bit first, consult clog afterwards */
                               1568         [ +  + ]:          40699 :         if (!HeapTupleHeaderXminCommitted(tuple) &&
                               1569         [ -  + ]:             54 :             !TransactionIdDidCommit(xmin))
 4395 rhaas@postgresql.org     1570                 :LBC         (4) :             return false;
                               1571                 :                :         /* fall through */
                               1572                 :                :     }
                               1573                 :                :     /* beyond our xmax horizon, i.e. invisible */
 4395 rhaas@postgresql.org     1574         [ +  + ]:CBC        3138 :     else if (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
                               1575                 :                :     {
                               1576                 :            124 :         return false;
                               1577                 :                :     }
                               1578                 :                :     /* check if it's a committed transaction in [xmin, xmax) */
 4331 bruce@momjian.us         1579         [ -  + ]:           3014 :     else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
                               1580                 :                :     {
                               1581                 :                :         /* fall through */
                               1582                 :                :     }
                               1583                 :                : 
                               1584                 :                :     /*
                               1585                 :                :      * none of the above, i.e. between [xmin, xmax) but hasn't committed. I.e.
                               1586                 :                :      * invisible.
                               1587                 :                :      */
                               1588                 :                :     else
                               1589                 :                :     {
 4395 rhaas@postgresql.org     1590                 :UBC           0 :         return false;
                               1591                 :                :     }
                               1592                 :                : 
                               1593                 :                :     /* at this point we know xmin is visible, go on to check xmax */
                               1594                 :                : 
                               1595                 :                :     /* xid invalid or aborted */
 4395 rhaas@postgresql.org     1596         [ +  + ]:CBC       44153 :     if (tuple->t_infomask & HEAP_XMAX_INVALID)
                               1597                 :          36128 :         return true;
                               1598                 :                :     /* locked tuples are always visible */
                               1599         [ +  + ]:           8025 :     else if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
                               1600                 :           3791 :         return true;
                               1601                 :                : 
                               1602                 :                :     /*
                               1603                 :                :      * We can see multis here if we're looking at user tables or if somebody
                               1604                 :                :      * SELECT ... FOR SHARE/UPDATE a system table.
                               1605                 :                :      */
                               1606         [ +  + ]:           4234 :     else if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
                               1607                 :                :     {
                               1608                 :             43 :         xmax = HeapTupleGetUpdateXid(tuple);
                               1609                 :                :     }
                               1610                 :                : 
                               1611                 :                :     /* check if it's one of our txids, toplevel is also in there */
                               1612         [ +  + ]:           4234 :     if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
                               1613                 :                :     {
                               1614                 :                :         bool        resolved;
                               1615                 :                :         CommandId   cmin;
 4331 bruce@momjian.us         1616                 :            297 :         CommandId   cmax = HeapTupleHeaderGetRawCommandId(tuple);
                               1617                 :                : 
                               1618                 :                :         /* Lookup actual cmin/cmax values */
 4395 rhaas@postgresql.org     1619                 :            297 :         resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
                               1620                 :                :                                                  htup, buffer,
                               1621                 :                :                                                  &cmin, &cmax);
                               1622                 :                : 
                               1623                 :                :         /*
                               1624                 :                :          * If we haven't resolved the combo CID to cmin/cmax, that means we
                               1625                 :                :          * have not decoded the combo CID yet. That means the cmax is
                               1626                 :                :          * definitely in the future, and we're still supposed to see the
                               1627                 :                :          * tuple.
                               1628                 :                :          *
                               1629                 :                :          * XXX This only applies to decoding of in-progress transactions. In
                               1630                 :                :          * regular logical decoding we only execute this code at commit time,
                               1631                 :                :          * at which point we should have seen all relevant combo CIDs. So
                               1632                 :                :          * ideally, we should error out in this case but in practice, this
                               1633                 :                :          * won't happen. If we are too worried about this then we can add an
                               1634                 :                :          * elog inside ResolveCminCmaxDuringDecoding.
                               1635                 :                :          *
                               1636                 :                :          * XXX For the streaming case, we can track the largest combo CID
                               1637                 :                :          * assigned, and error out based on this (when unable to resolve combo
                               1638                 :                :          * CID below that observed maximum value).
                               1639                 :                :          */
 2045 akapila@postgresql.o     1640   [ +  +  -  + ]:            297 :         if (!resolved || cmax == InvalidCommandId)
                               1641                 :             11 :             return true;
                               1642                 :                : 
 4395 rhaas@postgresql.org     1643         [ +  + ]:            286 :         if (cmax >= snapshot->curcid)
 4331 bruce@momjian.us         1644                 :             85 :             return true;        /* deleted after scan started */
                               1645                 :                :         else
                               1646                 :            201 :             return false;       /* deleted before scan started */
                               1647                 :                :     }
                               1648                 :                :     /* below xmin horizon, normal transaction state is valid */
 4395 rhaas@postgresql.org     1649         [ +  + ]:           3937 :     else if (TransactionIdPrecedes(xmax, snapshot->xmin))
                               1650                 :                :     {
                               1651   [ +  +  -  + ]:           2161 :         Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED &&
                               1652                 :                :                  !TransactionIdDidCommit(xmax)));
                               1653                 :                : 
                               1654                 :                :         /* check hint bit first */
                               1655         [ +  + ]:           2161 :         if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
                               1656                 :           2084 :             return false;
                               1657                 :                : 
                               1658                 :                :         /* check clog */
                               1659                 :             77 :         return !TransactionIdDidCommit(xmax);
                               1660                 :                :     }
                               1661                 :                :     /* above xmax horizon, we cannot possibly see the deleting transaction */
                               1662         [ +  + ]:           1776 :     else if (TransactionIdFollowsOrEquals(xmax, snapshot->xmax))
                               1663                 :            303 :         return true;
                               1664                 :                :     /* xmax is between [xmin, xmax), check known committed array */
                               1665         [ +  - ]:           1473 :     else if (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt))
                               1666                 :           1473 :         return false;
                               1667                 :                :     /* xmax is between [xmin, xmax), but known not to have committed yet */
                               1668                 :                :     else
 4395 rhaas@postgresql.org     1669                 :UBC           0 :         return true;
                               1670                 :                : }
                               1671                 :                : 
                               1672                 :                : /*
                               1673                 :                :  * Perform HeaptupleSatisfiesMVCC() on each passed in tuple. This is more
                               1674                 :                :  * efficient than doing HeapTupleSatisfiesMVCC() one-by-one.
                               1675                 :                :  *
                               1676                 :                :  * To be checked tuples are passed via BatchMVCCState->tuples. Each tuple's
                               1677                 :                :  * visibility is stored in batchmvcc->visible[]. In addition,
                               1678                 :                :  * ->vistuples_dense is set to contain the offsets of visible tuples.
                               1679                 :                :  *
                               1680                 :                :  * The reason this is more efficient than HeapTupleSatisfiesMVCC() is that it
                               1681                 :                :  * avoids a cross-translation-unit function call for each tuple, allows the
                               1682                 :                :  * compiler to optimize across calls to HeapTupleSatisfiesMVCC and allows
                               1683                 :                :  * setting hint bits more efficiently (see the one BufferFinishSetHintBits()
                               1684                 :                :  * call below).
                               1685                 :                :  *
                               1686                 :                :  * Returns the number of visible tuples.
                               1687                 :                :  */
                               1688                 :                : int
   62 andres@anarazel.de       1689                 :GNC     1683898 : HeapTupleSatisfiesMVCCBatch(Snapshot snapshot, Buffer buffer,
                               1690                 :                :                             int ntups,
                               1691                 :                :                             BatchMVCCState *batchmvcc,
                               1692                 :                :                             OffsetNumber *vistuples_dense)
                               1693                 :                : {
                               1694                 :        1683898 :     int         nvis = 0;
    5                          1695                 :        1683898 :     SetHintBitsState state = SHB_INITIAL;
                               1696                 :                : 
   62                          1697         [ -  + ]:        1683898 :     Assert(IsMVCCSnapshot(snapshot));
                               1698                 :                : 
                               1699         [ +  + ]:       67662861 :     for (int i = 0; i < ntups; i++)
                               1700                 :                :     {
                               1701                 :                :         bool        valid;
                               1702                 :       65978963 :         HeapTuple   tup = &batchmvcc->tuples[i];
                               1703                 :                : 
    5                          1704                 :       65978963 :         valid = HeapTupleSatisfiesMVCC(tup, snapshot, buffer, &state);
   62                          1705                 :       65978963 :         batchmvcc->visible[i] = valid;
                               1706                 :                : 
                               1707         [ +  + ]:       65978963 :         if (likely(valid))
                               1708                 :                :         {
                               1709                 :       58346333 :             vistuples_dense[nvis] = tup->t_self.ip_posid;
                               1710                 :       58346333 :             nvis++;
                               1711                 :                :         }
                               1712                 :                :     }
                               1713                 :                : 
    5                          1714         [ +  + ]:        1683898 :     if (state == SHB_ENABLED)
                               1715                 :          98860 :         BufferFinishSetHintBits(buffer, true, true);
                               1716                 :                : 
   62                          1717                 :        1683898 :     return nvis;
                               1718                 :                : }
                               1719                 :                : 
                               1720                 :                : /*
                               1721                 :                :  * HeapTupleSatisfiesVisibility
                               1722                 :                :  *      True iff heap tuple satisfies a time qual.
                               1723                 :                :  *
                               1724                 :                :  * Notes:
                               1725                 :                :  *  Assumes heap tuple is valid, and buffer at least share locked.
                               1726                 :                :  *
                               1727                 :                :  *  Hint bits in the HeapTuple's t_infomask may be updated as a side effect;
                               1728                 :                :  *  if so, the indicated buffer is marked dirty.
                               1729                 :                :  */
                               1730                 :                : bool
 1273 pg@bowt.ie               1731                 :CBC    32697893 : HeapTupleSatisfiesVisibility(HeapTuple htup, Snapshot snapshot, Buffer buffer)
                               1732                 :                : {
 2610 andres@anarazel.de       1733   [ +  +  +  +  :       32697893 :     switch (snapshot->snapshot_type)
                                        +  +  +  - ]
                               1734                 :                :     {
                               1735                 :       17536766 :         case SNAPSHOT_MVCC:
    5 andres@anarazel.de       1736                 :GNC    17536766 :             return HeapTupleSatisfiesMVCC(htup, snapshot, buffer, NULL);
 2610 andres@anarazel.de       1737                 :CBC      402664 :         case SNAPSHOT_SELF:
 1273 pg@bowt.ie               1738                 :         402664 :             return HeapTupleSatisfiesSelf(htup, snapshot, buffer);
 2610 andres@anarazel.de       1739                 :        8327201 :         case SNAPSHOT_ANY:
 1273 pg@bowt.ie               1740                 :        8327201 :             return HeapTupleSatisfiesAny(htup, snapshot, buffer);
 2610 andres@anarazel.de       1741                 :          86023 :         case SNAPSHOT_TOAST:
 1273 pg@bowt.ie               1742                 :          86023 :             return HeapTupleSatisfiesToast(htup, snapshot, buffer);
 2610 andres@anarazel.de       1743                 :        5939378 :         case SNAPSHOT_DIRTY:
 1273 pg@bowt.ie               1744                 :        5939378 :             return HeapTupleSatisfiesDirty(htup, snapshot, buffer);
 2610 andres@anarazel.de       1745                 :          44425 :         case SNAPSHOT_HISTORIC_MVCC:
 1273 pg@bowt.ie               1746                 :          44425 :             return HeapTupleSatisfiesHistoricMVCC(htup, snapshot, buffer);
 2610 andres@anarazel.de       1747                 :         361436 :         case SNAPSHOT_NON_VACUUMABLE:
 1273 pg@bowt.ie               1748                 :         361436 :             return HeapTupleSatisfiesNonVacuumable(htup, snapshot, buffer);
                               1749                 :                :     }
                               1750                 :                : 
 2610 andres@anarazel.de       1751                 :UBC           0 :     return false;               /* keep compiler quiet */
                               1752                 :                : }
        

Generated by: LCOV version 2.4-beta