LCOV - code coverage report
Current view: top level - src/backend/access/transam - transam.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 71 87 81.6 %
Date: 2019-11-13 22:07:24 Functions: 13 13 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * transam.c
       4             :  *    postgres transaction (commit) log interface routines
       5             :  *
       6             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/access/transam/transam.c
      12             :  *
      13             :  * NOTES
      14             :  *    This file contains the high level access-method interface to the
      15             :  *    transaction system.
      16             :  *
      17             :  *-------------------------------------------------------------------------
      18             :  */
      19             : 
      20             : #include "postgres.h"
      21             : 
      22             : #include "access/clog.h"
      23             : #include "access/subtrans.h"
      24             : #include "access/transam.h"
      25             : #include "utils/snapmgr.h"
      26             : 
      27             : /*
      28             :  * Single-item cache for results of TransactionLogFetch.  It's worth having
      29             :  * such a cache because we frequently find ourselves repeatedly checking the
      30             :  * same XID, for example when scanning a table just after a bulk insert,
      31             :  * update, or delete.
      32             :  */
      33             : static TransactionId cachedFetchXid = InvalidTransactionId;
      34             : static XidStatus cachedFetchXidStatus;
      35             : static XLogRecPtr cachedCommitLSN;
      36             : 
      37             : /* Local functions */
      38             : static XidStatus TransactionLogFetch(TransactionId transactionId);
      39             : 
      40             : 
      41             : /* ----------------------------------------------------------------
      42             :  *      Postgres log access method interface
      43             :  *
      44             :  *      TransactionLogFetch
      45             :  * ----------------------------------------------------------------
      46             :  */
      47             : 
      48             : /*
      49             :  * TransactionLogFetch --- fetch commit status of specified transaction id
      50             :  */
      51             : static XidStatus
      52    22571014 : TransactionLogFetch(TransactionId transactionId)
      53             : {
      54             :     XidStatus   xidstatus;
      55             :     XLogRecPtr  xidlsn;
      56             : 
      57             :     /*
      58             :      * Before going to the commit log manager, check our single item cache to
      59             :      * see if we didn't just check the transaction status a moment ago.
      60             :      */
      61    22571014 :     if (TransactionIdEquals(transactionId, cachedFetchXid))
      62    18965734 :         return cachedFetchXidStatus;
      63             : 
      64             :     /*
      65             :      * Also, check to see if the transaction ID is a permanent one.
      66             :      */
      67     3605280 :     if (!TransactionIdIsNormal(transactionId))
      68             :     {
      69     2535118 :         if (TransactionIdEquals(transactionId, BootstrapTransactionId))
      70     2535110 :             return TRANSACTION_STATUS_COMMITTED;
      71           8 :         if (TransactionIdEquals(transactionId, FrozenTransactionId))
      72           4 :             return TRANSACTION_STATUS_COMMITTED;
      73           4 :         return TRANSACTION_STATUS_ABORTED;
      74             :     }
      75             : 
      76             :     /*
      77             :      * Get the transaction status.
      78             :      */
      79     1070162 :     xidstatus = TransactionIdGetStatus(transactionId, &xidlsn);
      80             : 
      81             :     /*
      82             :      * Cache it, but DO NOT cache status for unfinished or sub-committed
      83             :      * transactions!  We only cache status that is guaranteed not to change.
      84             :      */
      85     1070162 :     if (xidstatus != TRANSACTION_STATUS_IN_PROGRESS &&
      86             :         xidstatus != TRANSACTION_STATUS_SUB_COMMITTED)
      87             :     {
      88     1063836 :         cachedFetchXid = transactionId;
      89     1063836 :         cachedFetchXidStatus = xidstatus;
      90     1063836 :         cachedCommitLSN = xidlsn;
      91             :     }
      92             : 
      93     1070162 :     return xidstatus;
      94             : }
      95             : 
      96             : /* ----------------------------------------------------------------
      97             :  *                      Interface functions
      98             :  *
      99             :  *      TransactionIdDidCommit
     100             :  *      TransactionIdDidAbort
     101             :  *      ========
     102             :  *         these functions test the transaction status of
     103             :  *         a specified transaction id.
     104             :  *
     105             :  *      TransactionIdCommitTree
     106             :  *      TransactionIdAsyncCommitTree
     107             :  *      TransactionIdAbortTree
     108             :  *      ========
     109             :  *         these functions set the transaction status of the specified
     110             :  *         transaction tree.
     111             :  *
     112             :  * See also TransactionIdIsInProgress, which once was in this module
     113             :  * but now lives in procarray.c.
     114             :  * ----------------------------------------------------------------
     115             :  */
     116             : 
     117             : /*
     118             :  * TransactionIdDidCommit
     119             :  *      True iff transaction associated with the identifier did commit.
     120             :  *
     121             :  * Note:
     122             :  *      Assumes transaction identifier is valid and exists in clog.
     123             :  */
     124             : bool                            /* true if given transaction committed */
     125    22570258 : TransactionIdDidCommit(TransactionId transactionId)
     126             : {
     127             :     XidStatus   xidstatus;
     128             : 
     129    22570258 :     xidstatus = TransactionLogFetch(transactionId);
     130             : 
     131             :     /*
     132             :      * If it's marked committed, it's committed.
     133             :      */
     134    22570258 :     if (xidstatus == TRANSACTION_STATUS_COMMITTED)
     135    22532308 :         return true;
     136             : 
     137             :     /*
     138             :      * If it's marked subcommitted, we have to check the parent recursively.
     139             :      * However, if it's older than TransactionXmin, we can't look at
     140             :      * pg_subtrans; instead assume that the parent crashed without cleaning up
     141             :      * its children.
     142             :      *
     143             :      * Originally we Assert'ed that the result of SubTransGetParent was not
     144             :      * zero. However with the introduction of prepared transactions, there can
     145             :      * be a window just after database startup where we do not have complete
     146             :      * knowledge in pg_subtrans of the transactions after TransactionXmin.
     147             :      * StartupSUBTRANS() has ensured that any missing information will be
     148             :      * zeroed.  Since this case should not happen under normal conditions, it
     149             :      * seems reasonable to emit a WARNING for it.
     150             :      */
     151       37950 :     if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
     152             :     {
     153             :         TransactionId parentXid;
     154             : 
     155           0 :         if (TransactionIdPrecedes(transactionId, TransactionXmin))
     156           0 :             return false;
     157           0 :         parentXid = SubTransGetParent(transactionId);
     158           0 :         if (!TransactionIdIsValid(parentXid))
     159             :         {
     160           0 :             elog(WARNING, "no pg_subtrans entry for subcommitted XID %u",
     161             :                  transactionId);
     162           0 :             return false;
     163             :         }
     164           0 :         return TransactionIdDidCommit(parentXid);
     165             :     }
     166             : 
     167             :     /*
     168             :      * It's not committed.
     169             :      */
     170       37950 :     return false;
     171             : }
     172             : 
     173             : /*
     174             :  * TransactionIdDidAbort
     175             :  *      True iff transaction associated with the identifier did abort.
     176             :  *
     177             :  * Note:
     178             :  *      Assumes transaction identifier is valid and exists in clog.
     179             :  */
     180             : bool                            /* true if given transaction aborted */
     181         756 : TransactionIdDidAbort(TransactionId transactionId)
     182             : {
     183             :     XidStatus   xidstatus;
     184             : 
     185         756 :     xidstatus = TransactionLogFetch(transactionId);
     186             : 
     187             :     /*
     188             :      * If it's marked aborted, it's aborted.
     189             :      */
     190         756 :     if (xidstatus == TRANSACTION_STATUS_ABORTED)
     191          38 :         return true;
     192             : 
     193             :     /*
     194             :      * If it's marked subcommitted, we have to check the parent recursively.
     195             :      * However, if it's older than TransactionXmin, we can't look at
     196             :      * pg_subtrans; instead assume that the parent crashed without cleaning up
     197             :      * its children.
     198             :      */
     199         718 :     if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
     200             :     {
     201             :         TransactionId parentXid;
     202             : 
     203           0 :         if (TransactionIdPrecedes(transactionId, TransactionXmin))
     204           0 :             return true;
     205           0 :         parentXid = SubTransGetParent(transactionId);
     206           0 :         if (!TransactionIdIsValid(parentXid))
     207             :         {
     208             :             /* see notes in TransactionIdDidCommit */
     209           0 :             elog(WARNING, "no pg_subtrans entry for subcommitted XID %u",
     210             :                  transactionId);
     211           0 :             return true;
     212             :         }
     213           0 :         return TransactionIdDidAbort(parentXid);
     214             :     }
     215             : 
     216             :     /*
     217             :      * It's not aborted.
     218             :      */
     219         718 :     return false;
     220             : }
     221             : 
     222             : /*
     223             :  * TransactionIdIsKnownCompleted
     224             :  *      True iff transaction associated with the identifier is currently
     225             :  *      known to have either committed or aborted.
     226             :  *
     227             :  * This does NOT look into pg_xact but merely probes our local cache
     228             :  * (and so it's not named TransactionIdDidComplete, which would be the
     229             :  * appropriate name for a function that worked that way).  The intended
     230             :  * use is just to short-circuit TransactionIdIsInProgress calls when doing
     231             :  * repeated heapam_visibility.c checks for the same XID.  If this isn't
     232             :  * extremely fast then it will be counterproductive.
     233             :  *
     234             :  * Note:
     235             :  *      Assumes transaction identifier is valid.
     236             :  */
     237             : bool
     238      574060 : TransactionIdIsKnownCompleted(TransactionId transactionId)
     239             : {
     240      574060 :     if (TransactionIdEquals(transactionId, cachedFetchXid))
     241             :     {
     242             :         /* If it's in the cache at all, it must be completed. */
     243      530788 :         return true;
     244             :     }
     245             : 
     246       43272 :     return false;
     247             : }
     248             : 
     249             : /*
     250             :  * TransactionIdCommitTree
     251             :  *      Marks the given transaction and children as committed
     252             :  *
     253             :  * "xid" is a toplevel transaction commit, and the xids array contains its
     254             :  * committed subtransactions.
     255             :  *
     256             :  * This commit operation is not guaranteed to be atomic, but if not, subxids
     257             :  * are correctly marked subcommit first.
     258             :  */
     259             : void
     260      239122 : TransactionIdCommitTree(TransactionId xid, int nxids, TransactionId *xids)
     261             : {
     262      239122 :     TransactionIdSetTreeStatus(xid, nxids, xids,
     263             :                                TRANSACTION_STATUS_COMMITTED,
     264             :                                InvalidXLogRecPtr);
     265      239122 : }
     266             : 
     267             : /*
     268             :  * TransactionIdAsyncCommitTree
     269             :  *      Same as above, but for async commits.  The commit record LSN is needed.
     270             :  */
     271             : void
     272       11502 : TransactionIdAsyncCommitTree(TransactionId xid, int nxids, TransactionId *xids,
     273             :                              XLogRecPtr lsn)
     274             : {
     275       11502 :     TransactionIdSetTreeStatus(xid, nxids, xids,
     276             :                                TRANSACTION_STATUS_COMMITTED, lsn);
     277       11502 : }
     278             : 
     279             : /*
     280             :  * TransactionIdAbortTree
     281             :  *      Marks the given transaction and children as aborted.
     282             :  *
     283             :  * "xid" is a toplevel transaction commit, and the xids array contains its
     284             :  * committed subtransactions.
     285             :  *
     286             :  * We don't need to worry about the non-atomic behavior, since any onlookers
     287             :  * will consider all the xacts as not-yet-committed anyway.
     288             :  */
     289             : void
     290        5564 : TransactionIdAbortTree(TransactionId xid, int nxids, TransactionId *xids)
     291             : {
     292        5564 :     TransactionIdSetTreeStatus(xid, nxids, xids,
     293             :                                TRANSACTION_STATUS_ABORTED, InvalidXLogRecPtr);
     294        5564 : }
     295             : 
     296             : /*
     297             :  * TransactionIdPrecedes --- is id1 logically < id2?
     298             :  */
     299             : bool
     300   231864904 : TransactionIdPrecedes(TransactionId id1, TransactionId id2)
     301             : {
     302             :     /*
     303             :      * If either ID is a permanent XID then we can just do unsigned
     304             :      * comparison.  If both are normal, do a modulo-2^32 comparison.
     305             :      */
     306             :     int32       diff;
     307             : 
     308   231864904 :     if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
     309   148072990 :         return (id1 < id2);
     310             : 
     311    83791914 :     diff = (int32) (id1 - id2);
     312    83791914 :     return (diff < 0);
     313             : }
     314             : 
     315             : /*
     316             :  * TransactionIdPrecedesOrEquals --- is id1 logically <= id2?
     317             :  */
     318             : bool
     319       42828 : TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
     320             : {
     321             :     int32       diff;
     322             : 
     323       42828 :     if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
     324         986 :         return (id1 <= id2);
     325             : 
     326       41842 :     diff = (int32) (id1 - id2);
     327       41842 :     return (diff <= 0);
     328             : }
     329             : 
     330             : /*
     331             :  * TransactionIdFollows --- is id1 logically > id2?
     332             :  */
     333             : bool
     334    19948134 : TransactionIdFollows(TransactionId id1, TransactionId id2)
     335             : {
     336             :     int32       diff;
     337             : 
     338    19948134 :     if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
     339     3245358 :         return (id1 > id2);
     340             : 
     341    16702776 :     diff = (int32) (id1 - id2);
     342    16702776 :     return (diff > 0);
     343             : }
     344             : 
     345             : /*
     346             :  * TransactionIdFollowsOrEquals --- is id1 logically >= id2?
     347             :  */
     348             : bool
     349     2016542 : TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
     350             : {
     351             :     int32       diff;
     352             : 
     353     2016542 :     if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
     354        1646 :         return (id1 >= id2);
     355             : 
     356     2014896 :     diff = (int32) (id1 - id2);
     357     2014896 :     return (diff >= 0);
     358             : }
     359             : 
     360             : 
     361             : /*
     362             :  * TransactionIdLatest --- get latest XID among a main xact and its children
     363             :  */
     364             : TransactionId
     365      297022 : TransactionIdLatest(TransactionId mainxid,
     366             :                     int nxids, const TransactionId *xids)
     367             : {
     368             :     TransactionId result;
     369             : 
     370             :     /*
     371             :      * In practice it is highly likely that the xids[] array is sorted, and so
     372             :      * we could save some cycles by just taking the last child XID, but this
     373             :      * probably isn't so performance-critical that it's worth depending on
     374             :      * that assumption.  But just to show we're not totally stupid, scan the
     375             :      * array back-to-front to avoid useless assignments.
     376             :      */
     377      297022 :     result = mainxid;
     378      598908 :     while (--nxids >= 0)
     379             :     {
     380        4864 :         if (TransactionIdPrecedes(result, xids[nxids]))
     381         548 :             result = xids[nxids];
     382             :     }
     383      297022 :     return result;
     384             : }
     385             : 
     386             : 
     387             : /*
     388             :  * TransactionIdGetCommitLSN
     389             :  *
     390             :  * This function returns an LSN that is late enough to be able
     391             :  * to guarantee that if we flush up to the LSN returned then we
     392             :  * will have flushed the transaction's commit record to disk.
     393             :  *
     394             :  * The result is not necessarily the exact LSN of the transaction's
     395             :  * commit record!  For example, for long-past transactions (those whose
     396             :  * clog pages already migrated to disk), we'll return InvalidXLogRecPtr.
     397             :  * Also, because we group transactions on the same clog page to conserve
     398             :  * storage, we might return the LSN of a later transaction that falls into
     399             :  * the same group.
     400             :  */
     401             : XLogRecPtr
     402    17258052 : TransactionIdGetCommitLSN(TransactionId xid)
     403             : {
     404             :     XLogRecPtr  result;
     405             : 
     406             :     /*
     407             :      * Currently, all uses of this function are for xids that were just
     408             :      * reported to be committed by TransactionLogFetch, so we expect that
     409             :      * checking TransactionLogFetch's cache will usually succeed and avoid an
     410             :      * extra trip to shared memory.
     411             :      */
     412    17258052 :     if (TransactionIdEquals(xid, cachedFetchXid))
     413    14722946 :         return cachedCommitLSN;
     414             : 
     415             :     /* Special XIDs are always known committed */
     416     2535106 :     if (!TransactionIdIsNormal(xid))
     417     2535106 :         return InvalidXLogRecPtr;
     418             : 
     419             :     /*
     420             :      * Get the transaction status.
     421             :      */
     422           0 :     (void) TransactionIdGetStatus(xid, &result);
     423             : 
     424           0 :     return result;
     425             : }

Generated by: LCOV version 1.13