LCOV - differential code coverage report
Current view: top level - src/backend/access/transam - transam.c (source / functions) Coverage Total Hit LBC UIC UBC GIC CBC EUB ECB
Current: Differential Code Coverage HEAD vs 15 Lines: 80.7 % 83 67 2 9 5 44 23 11 42
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 12 12 11 1 11
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 80.7 % 83 67 2 9 5 44 23 9 42
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 52.2 % 23 12 11 1 11

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * transam.c
                                  4                 :  *    postgres transaction (commit) log interface routines
                                  5                 :  *
                                  6                 :  * Portions Copyright (c) 1996-2023, 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
 6856 tgl                        52 CBC    19064836 : 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        19064836 :     if (TransactionIdEquals(transactionId, cachedFetchXid))
                                 62        13428106 :         return cachedFetchXidStatus;
                                 63                 : 
                                 64                 :     /*
                                 65                 :      * Also, check to see if the transaction ID is a permanent one.
                                 66                 :      */
 7836 bruce                      67         5636730 :     if (!TransactionIdIsNormal(transactionId))
                                 68                 :     {
 7897 tgl                        69         3836731 :         if (TransactionIdEquals(transactionId, BootstrapTransactionId))
 6856                            70         3832941 :             return TRANSACTION_STATUS_COMMITTED;
 7897                            71            3790 :         if (TransactionIdEquals(transactionId, FrozenTransactionId))
 6856                            72            3786 :             return TRANSACTION_STATUS_COMMITTED;
                                 73               4 :         return TRANSACTION_STATUS_ABORTED;
                                 74                 :     }
                                 75                 : 
                                 76                 :     /*
                                 77                 :      * Get the transaction status.
                                 78                 :      */
 5730                            79         1799999 :     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                 :      */
 6856                            85         1799999 :     if (xidstatus != TRANSACTION_STATUS_IN_PROGRESS &&
                                 86                 :         xidstatus != TRANSACTION_STATUS_SUB_COMMITTED)
                                 87                 :     {
 5730                            88         1756052 :         cachedFetchXid = transactionId;
 6856                            89         1756052 :         cachedFetchXidStatus = xidstatus;
 5730                            90         1756052 :         cachedCommitLSN = xidlsn;
                                 91                 :     }
                                 92                 : 
 6856                            93         1799999 :     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, as well as comments at the top of
                                114                 :  * heapam_visibility.c that explain how everything fits together.
                                115                 :  * ----------------------------------------------------------------
                                116                 :  */
                                117                 : 
                                118                 : /*
                                119                 :  * TransactionIdDidCommit
                                120                 :  *      True iff transaction associated with the identifier did commit.
                                121                 :  *
                                122                 :  * Note:
                                123                 :  *      Assumes transaction identifier is valid and exists in clog.
                                124                 :  */
                                125                 : bool                            /* true if given transaction committed */
 9770 scrappy                   126 GIC    19045219 : TransactionIdDidCommit(TransactionId transactionId)
 9770 scrappy                   127 ECB             : {
                                128                 :     XidStatus   xidstatus;
                                129                 : 
 6856 tgl                       130 GIC    19045219 :     xidstatus = TransactionLogFetch(transactionId);
 6856 tgl                       131 ECB             : 
                                132                 :     /*
                                133                 :      * If it's marked committed, it's committed.
                                134                 :      */
 6856 tgl                       135 GIC    19045219 :     if (xidstatus == TRANSACTION_STATUS_COMMITTED)
 6856 tgl                       136 CBC    18948944 :         return true;
 6856 tgl                       137 ECB             : 
                                138                 :     /*
                                139                 :      * If it's marked subcommitted, we have to check the parent recursively.
                                140                 :      * However, if it's older than TransactionXmin, we can't look at
                                141                 :      * pg_subtrans; instead assume that the parent crashed without cleaning up
                                142                 :      * its children.
                                143                 :      *
                                144                 :      * Originally we Assert'ed that the result of SubTransGetParent was not
                                145                 :      * zero. However with the introduction of prepared transactions, there can
                                146                 :      * be a window just after database startup where we do not have complete
                                147                 :      * knowledge in pg_subtrans of the transactions after TransactionXmin.
                                148                 :      * StartupSUBTRANS() has ensured that any missing information will be
                                149                 :      * zeroed.  Since this case should not happen under normal conditions, it
                                150                 :      * seems reasonable to emit a WARNING for it.
                                151                 :      */
 6856 tgl                       152 GIC       96275 :     if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
 6856 tgl                       153 ECB             :     {
                                154                 :         TransactionId parentXid;
                                155                 : 
 6779 tgl                       156 UIC           0 :         if (TransactionIdPrecedes(transactionId, TransactionXmin))
 6804 tgl                       157 UBC           0 :             return false;
 6856                           158               0 :         parentXid = SubTransGetParent(transactionId);
 6505                           159               0 :         if (!TransactionIdIsValid(parentXid))
 6505 tgl                       160 EUB             :         {
 6505 tgl                       161 UIC           0 :             elog(WARNING, "no pg_subtrans entry for subcommitted XID %u",
 6505 tgl                       162 EUB             :                  transactionId);
 6505 tgl                       163 UIC           0 :             return false;
 6505 tgl                       164 EUB             :         }
 6856 tgl                       165 UIC           0 :         return TransactionIdDidCommit(parentXid);
 6856 tgl                       166 EUB             :     }
                                167                 : 
                                168                 :     /*
                                169                 :      * It's not committed.
                                170                 :      */
 6856 tgl                       171 GIC       96275 :     return false;
 9770 scrappy                   172 ECB             : }
                                173                 : 
                                174                 : /*
                                175                 :  * TransactionIdDidAbort
                                176                 :  *      True iff transaction associated with the identifier did abort.
                                177                 :  *
                                178                 :  * Note:
                                179                 :  *      Assumes transaction identifier is valid and exists in clog.
                                180                 :  *
                                181                 :  *      Returns true only for explicitly aborted transactions, as transactions
                                182                 :  *      implicitly aborted due to a crash will commonly still appear to be
                                183                 :  *      in-progress in the clog.  Most of the time TransactionIdDidCommit(),
                                184                 :  *      with a preceding TransactionIdIsInProgress() check, should be used
                                185                 :  *      instead of TransactionIdDidAbort().
                                186                 :  */
                                187                 : bool                            /* true if given transaction aborted */
 9770 scrappy                   188 GIC       19617 : TransactionIdDidAbort(TransactionId transactionId)
                                189                 : {
                                190                 :     XidStatus   xidstatus;
                                191                 : 
 6856 tgl                       192           19617 :     xidstatus = TransactionLogFetch(transactionId);
                                193                 : 
                                194                 :     /*
 6856 tgl                       195 ECB             :      * If it's marked aborted, it's aborted.
                                196                 :      */
 6856 tgl                       197 GIC       19617 :     if (xidstatus == TRANSACTION_STATUS_ABORTED)
                                198              18 :         return true;
 6856 tgl                       199 ECB             : 
                                200                 :     /*
                                201                 :      * If it's marked subcommitted, we have to check the parent recursively.
                                202                 :      * However, if it's older than TransactionXmin, we can't look at
                                203                 :      * pg_subtrans; instead assume that the parent crashed without cleaning up
 6385 bruce                     204                 :      * its children.
 6856 tgl                       205                 :      */
 6856 tgl                       206 GIC       19599 :     if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
                                207                 :     {
                                208                 :         TransactionId parentXid;
                                209                 : 
 6779 tgl                       210 UIC           0 :         if (TransactionIdPrecedes(transactionId, TransactionXmin))
 6804                           211               0 :             return true;
                                212               0 :         parentXid = SubTransGetParent(transactionId);
 6505 tgl                       213 LBC           0 :         if (!TransactionIdIsValid(parentXid))
                                214                 :         {
                                215                 :             /* see notes in TransactionIdDidCommit */
 6505 tgl                       216 UIC           0 :             elog(WARNING, "no pg_subtrans entry for subcommitted XID %u",
 6505 tgl                       217 EUB             :                  transactionId);
 6505 tgl                       218 UBC           0 :             return true;
 6505 tgl                       219 EUB             :         }
 6804 tgl                       220 UBC           0 :         return TransactionIdDidAbort(parentXid);
                                221                 :     }
                                222                 : 
 6856 tgl                       223 EUB             :     /*
                                224                 :      * It's not aborted.
                                225                 :      */
 6856 tgl                       226 GIC       19599 :     return false;
 9770 scrappy                   227 EUB             : }
                                228                 : 
                                229                 : /*
                                230                 :  * TransactionIdCommitTree
                                231                 :  *      Marks the given transaction and children as committed
                                232                 :  *
 5284 alvherre                  233 ECB             :  * "xid" is a toplevel transaction commit, and the xids array contains its
                                234                 :  * committed subtransactions.
                                235                 :  *
                                236                 :  * This commit operation is not guaranteed to be atomic, but if not, subxids
                                237                 :  * are correctly marked subcommit first.
                                238                 :  */
                                239                 : void
 5284 alvherre                  240 GIC      289010 : TransactionIdCommitTree(TransactionId xid, int nxids, TransactionId *xids)
                                241                 : {
                                242          289010 :     TransactionIdSetTreeStatus(xid, nxids, xids,
                                243                 :                                TRANSACTION_STATUS_COMMITTED,
                                244                 :                                InvalidXLogRecPtr);
 6856 tgl                       245          289010 : }
                                246                 : 
 5730 tgl                       247 ECB             : /*
                                248                 :  * TransactionIdAsyncCommitTree
                                249                 :  *      Same as above, but for async commits.  The commit record LSN is needed.
                                250                 :  */
                                251                 : void
 5284 alvherre                  252 CBC       23735 : TransactionIdAsyncCommitTree(TransactionId xid, int nxids, TransactionId *xids,
                                253                 :                              XLogRecPtr lsn)
                                254                 : {
 5284 alvherre                  255 GIC       23735 :     TransactionIdSetTreeStatus(xid, nxids, xids,
                                256                 :                                TRANSACTION_STATUS_COMMITTED, lsn);
 5730 tgl                       257           23735 : }
                                258                 : 
 6856 tgl                       259 ECB             : /*
                                260                 :  * TransactionIdAbortTree
                                261                 :  *      Marks the given transaction and children as aborted.
 5284 alvherre                  262                 :  *
                                263                 :  * "xid" is a toplevel transaction commit, and the xids array contains its
                                264                 :  * committed subtransactions.
                                265                 :  *
                                266                 :  * We don't need to worry about the non-atomic behavior, since any onlookers
                                267                 :  * will consider all the xacts as not-yet-committed anyway.
                                268                 :  */
                                269                 : void
 5284 alvherre                  270 GIC        6247 : TransactionIdAbortTree(TransactionId xid, int nxids, TransactionId *xids)
                                271                 : {
                                272            6247 :     TransactionIdSetTreeStatus(xid, nxids, xids,
                                273                 :                                TRANSACTION_STATUS_ABORTED, InvalidXLogRecPtr);
 6856 tgl                       274            6247 : }
                                275                 : 
                                276                 : /*
 7896 tgl                       277 ECB             :  * TransactionIdPrecedes --- is id1 logically < id2?
                                278                 :  */
                                279                 : bool
 7896 tgl                       280 GIC   251095624 : TransactionIdPrecedes(TransactionId id1, TransactionId id2)
 7896 tgl                       281 ECB             : {
                                282                 :     /*
                                283                 :      * If either ID is a permanent XID then we can just do unsigned
                                284                 :      * comparison.  If both are normal, do a modulo-2^32 comparison.
                                285                 :      */
                                286                 :     int32       diff;
                                287                 : 
 7896 tgl                       288 GIC   251095624 :     if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
                                289       172994981 :         return (id1 < id2);
                                290                 : 
                                291        78100643 :     diff = (int32) (id1 - id2);
                                292        78100643 :     return (diff < 0);
                                293                 : }
                                294                 : 
 7896 tgl                       295 ECB             : /*
                                296                 :  * TransactionIdPrecedesOrEquals --- is id1 logically <= id2?
                                297                 :  */
                                298                 : bool
 7896 tgl                       299 CBC     6819928 : TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
                                300                 : {
                                301                 :     int32       diff;
                                302                 : 
 7896 tgl                       303 GIC     6819928 :     if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
                                304             797 :         return (id1 <= id2);
                                305                 : 
 7896 tgl                       306 CBC     6819131 :     diff = (int32) (id1 - id2);
 7896 tgl                       307 GIC     6819131 :     return (diff <= 0);
                                308                 : }
                                309                 : 
 7896 tgl                       310 ECB             : /*
                                311                 :  * TransactionIdFollows --- is id1 logically > id2?
                                312                 :  */
                                313                 : bool
 7896 tgl                       314 CBC    29262100 : TransactionIdFollows(TransactionId id1, TransactionId id2)
                                315                 : {
                                316                 :     int32       diff;
                                317                 : 
 7896 tgl                       318 GIC    29262100 :     if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
                                319        11190110 :         return (id1 > id2);
                                320                 : 
 7896 tgl                       321 CBC    18071990 :     diff = (int32) (id1 - id2);
 7896 tgl                       322 GIC    18071990 :     return (diff > 0);
                                323                 : }
                                324                 : 
 7896 tgl                       325 ECB             : /*
                                326                 :  * TransactionIdFollowsOrEquals --- is id1 logically >= id2?
                                327                 :  */
                                328                 : bool
 7896 tgl                       329 CBC    20064602 : TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
                                330                 : {
                                331                 :     int32       diff;
                                332                 : 
 7896 tgl                       333 GIC    20064602 :     if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
                                334           40303 :         return (id1 >= id2);
                                335                 : 
 7896 tgl                       336 CBC    20024299 :     diff = (int32) (id1 - id2);
 7896 tgl                       337 GIC    20024299 :     return (diff >= 0);
                                338                 : }
                                339                 : 
 5692 tgl                       340 ECB             : 
                                341                 : /*
                                342                 :  * TransactionIdLatest --- get latest XID among a main xact and its children
                                343                 :  */
                                344                 : TransactionId
 5692 tgl                       345 GIC      366668 : TransactionIdLatest(TransactionId mainxid,
                                346                 :                     int nxids, const TransactionId *xids)
                                347                 : {
                                348                 :     TransactionId result;
                                349                 : 
                                350                 :     /*
                                351                 :      * In practice it is highly likely that the xids[] array is sorted, and so
 5624 bruce                     352 ECB             :      * we could save some cycles by just taking the last child XID, but this
                                353                 :      * probably isn't so performance-critical that it's worth depending on
                                354                 :      * that assumption.  But just to show we're not totally stupid, scan the
                                355                 :      * array back-to-front to avoid useless assignments.
                                356                 :      */
 5692 tgl                       357 GIC      366668 :     result = mainxid;
                                358          372154 :     while (--nxids >= 0)
                                359                 :     {
                                360            5486 :         if (TransactionIdPrecedes(result, xids[nxids]))
                                361             722 :             result = xids[nxids];
                                362                 :     }
                                363          366668 :     return result;
 5692 tgl                       364 ECB             : }
                                365                 : 
                                366                 : 
 5730                           367                 : /*
                                368                 :  * TransactionIdGetCommitLSN
                                369                 :  *
                                370                 :  * This function returns an LSN that is late enough to be able
                                371                 :  * to guarantee that if we flush up to the LSN returned then we
                                372                 :  * will have flushed the transaction's commit record to disk.
                                373                 :  *
                                374                 :  * The result is not necessarily the exact LSN of the transaction's
                                375                 :  * commit record!  For example, for long-past transactions (those whose
                                376                 :  * clog pages already migrated to disk), we'll return InvalidXLogRecPtr.
                                377                 :  * Also, because we group transactions on the same clog page to conserve
                                378                 :  * storage, we might return the LSN of a later transaction that falls into
                                379                 :  * the same group.
                                380                 :  */
                                381                 : XLogRecPtr
 5730 tgl                       382 GIC    15755108 : TransactionIdGetCommitLSN(TransactionId xid)
                                383                 : {
                                384                 :     XLogRecPtr  result;
                                385                 : 
                                386                 :     /*
                                387                 :      * Currently, all uses of this function are for xids that were just
                                388                 :      * reported to be committed by TransactionLogFetch, so we expect that
 5730 tgl                       389 ECB             :      * checking TransactionLogFetch's cache will usually succeed and avoid an
                                390                 :      * extra trip to shared memory.
                                391                 :      */
 5730 tgl                       392 GIC    15755108 :     if (TransactionIdEquals(xid, cachedFetchXid))
                                393        11937728 :         return cachedCommitLSN;
                                394                 : 
                                395                 :     /* Special XIDs are always known committed */
                                396         3817380 :     if (!TransactionIdIsNormal(xid))
                                397         3817380 :         return InvalidXLogRecPtr;
                                398                 : 
 5730 tgl                       399 ECB             :     /*
                                400                 :      * Get the transaction status.
                                401                 :      */
 5730 tgl                       402 UIC           0 :     (void) TransactionIdGetStatus(xid, &result);
 5730 tgl                       403 ECB             : 
 5730 tgl                       404 LBC           0 :     return result;
                                405                 : }
        

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