LTP GCOV extension - code coverage report
Current view: directory - access/transam - transam.c
Test: unnamed
Date: 2008-07-03 Instrumented lines: 105
Code covered: 63.8 % Executed lines: 67
Legend: not executed executed

       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * transam.c
       4                 :  *        postgres transaction log interface routines
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
       7                 :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :  *
       9                 :  *
      10                 :  * IDENTIFICATION
      11                 :  *        $PostgreSQL: pgsql/src/backend/access/transam/transam.c,v 1.72 2007/11/15 21:14:32 momjian Exp $
      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/tqual.h"
      26                 : 
      27                 : 
      28                 : static XidStatus TransactionLogFetch(TransactionId transactionId);
      29                 : static void TransactionLogUpdate(TransactionId transactionId,
      30                 :                                          XidStatus status, XLogRecPtr lsn);
      31                 : 
      32                 : /*
      33                 :  * Single-item cache for results of TransactionLogFetch.
      34                 :  */
      35                 : static TransactionId cachedFetchXid = InvalidTransactionId;
      36                 : static XidStatus cachedFetchXidStatus;
      37                 : static XLogRecPtr cachedCommitLSN;
      38                 : 
      39                 : /* Handy constant for an invalid xlog recptr */
      40                 : static const XLogRecPtr InvalidXLogRecPtr = {0, 0};
      41                 : 
      42                 : 
      43                 : /* ----------------------------------------------------------------
      44                 :  *              postgres log access method interface
      45                 :  *
      46                 :  *              TransactionLogFetch
      47                 :  *              TransactionLogUpdate
      48                 :  * ----------------------------------------------------------------
      49                 :  */
      50                 : 
      51                 : /*
      52                 :  * TransactionLogFetch --- fetch commit status of specified transaction id
      53                 :  */
      54                 : static XidStatus
      55                 : TransactionLogFetch(TransactionId transactionId)
      56          227611 : {
      57                 :         XidStatus       xidstatus;
      58                 :         XLogRecPtr      xidlsn;
      59                 : 
      60                 :         /*
      61                 :          * Before going to the commit log manager, check our single item cache to
      62                 :          * see if we didn't just check the transaction status a moment ago.
      63                 :          */
      64          227611 :         if (TransactionIdEquals(transactionId, cachedFetchXid))
      65          212195 :                 return cachedFetchXidStatus;
      66                 : 
      67                 :         /*
      68                 :          * Also, check to see if the transaction ID is a permanent one.
      69                 :          */
      70           15416 :         if (!TransactionIdIsNormal(transactionId))
      71                 :         {
      72            5110 :                 if (TransactionIdEquals(transactionId, BootstrapTransactionId))
      73            5110 :                         return TRANSACTION_STATUS_COMMITTED;
      74               0 :                 if (TransactionIdEquals(transactionId, FrozenTransactionId))
      75               0 :                         return TRANSACTION_STATUS_COMMITTED;
      76               0 :                 return TRANSACTION_STATUS_ABORTED;
      77                 :         }
      78                 : 
      79                 :         /*
      80                 :          * Get the transaction status.
      81                 :          */
      82           10306 :         xidstatus = TransactionIdGetStatus(transactionId, &xidlsn);
      83                 : 
      84                 :         /*
      85                 :          * DO NOT cache status for unfinished or sub-committed transactions! We
      86                 :          * only cache status that is guaranteed not to change.
      87                 :          */
      88           10306 :         if (xidstatus != TRANSACTION_STATUS_IN_PROGRESS &&
      89                 :                 xidstatus != TRANSACTION_STATUS_SUB_COMMITTED)
      90                 :         {
      91           10115 :                 cachedFetchXid = transactionId;
      92           10115 :                 cachedFetchXidStatus = xidstatus;
      93           10115 :                 cachedCommitLSN = xidlsn;
      94                 :         }
      95                 : 
      96           10306 :         return xidstatus;
      97                 : }
      98                 : 
      99                 : /* --------------------------------
     100                 :  *              TransactionLogUpdate
     101                 :  *
     102                 :  * Store the new status of a transaction.  The commit record LSN must be
     103                 :  * passed when recording an async commit; else it should be InvalidXLogRecPtr.
     104                 :  * --------------------------------
     105                 :  */
     106                 : static inline void
     107                 : TransactionLogUpdate(TransactionId transactionId,
     108                 :                                          XidStatus status, XLogRecPtr lsn)
     109            8679 : {
     110                 :         /*
     111                 :          * update the commit log
     112                 :          */
     113            8679 :         TransactionIdSetStatus(transactionId, status, lsn);
     114            8679 : }
     115                 : 
     116                 : /*
     117                 :  * TransactionLogMultiUpdate
     118                 :  *
     119                 :  * Update multiple transaction identifiers to a given status.
     120                 :  * Don't depend on this being atomic; it's not.
     121                 :  */
     122                 : static inline void
     123                 : TransactionLogMultiUpdate(int nxids, TransactionId *xids,
     124                 :                                                   XidStatus status, XLogRecPtr lsn)
     125              14 : {
     126                 :         int                     i;
     127                 : 
     128                 :         Assert(nxids != 0);
     129                 : 
     130              33 :         for (i = 0; i < nxids; i++)
     131              19 :                 TransactionIdSetStatus(xids[i], status, lsn);
     132              14 : }
     133                 : 
     134                 : /* ----------------------------------------------------------------
     135                 :  *                                              Interface functions
     136                 :  *
     137                 :  *              TransactionId DidCommit
     138                 :  *              TransactionId DidAbort
     139                 :  *              TransactionId IsInProgress
     140                 :  *              ========
     141                 :  *                 these functions test the transaction status of
     142                 :  *                 a specified transaction id.
     143                 :  *
     144                 :  *              TransactionId Commit
     145                 :  *              TransactionId Abort
     146                 :  *              ========
     147                 :  *                 these functions set the transaction status
     148                 :  *                 of the specified xid.
     149                 :  *
     150                 :  * ----------------------------------------------------------------
     151                 :  */
     152                 : 
     153                 : /* --------------------------------
     154                 :  *              TransactionId DidCommit
     155                 :  *              TransactionId DidAbort
     156                 :  *              TransactionId IsInProgress
     157                 :  * --------------------------------
     158                 :  */
     159                 : 
     160                 : /*
     161                 :  * TransactionIdDidCommit
     162                 :  *              True iff transaction associated with the identifier did commit.
     163                 :  *
     164                 :  * Note:
     165                 :  *              Assumes transaction identifier is valid.
     166                 :  */
     167                 : bool                                                    /* true if given transaction committed */
     168                 : TransactionIdDidCommit(TransactionId transactionId)
     169          227611 : {
     170                 :         XidStatus       xidstatus;
     171                 : 
     172          227611 :         xidstatus = TransactionLogFetch(transactionId);
     173                 : 
     174                 :         /*
     175                 :          * If it's marked committed, it's committed.
     176                 :          */
     177          227611 :         if (xidstatus == TRANSACTION_STATUS_COMMITTED)
     178          226220 :                 return true;
     179                 : 
     180                 :         /*
     181                 :          * If it's marked subcommitted, we have to check the parent recursively.
     182                 :          * However, if it's older than TransactionXmin, we can't look at
     183                 :          * pg_subtrans; instead assume that the parent crashed without cleaning up
     184                 :          * its children.
     185                 :          *
     186                 :          * Originally we Assert'ed that the result of SubTransGetParent was not
     187                 :          * zero. However with the introduction of prepared transactions, there can
     188                 :          * be a window just after database startup where we do not have complete
     189                 :          * knowledge in pg_subtrans of the transactions after TransactionXmin.
     190                 :          * StartupSUBTRANS() has ensured that any missing information will be
     191                 :          * zeroed.      Since this case should not happen under normal conditions, it
     192                 :          * seems reasonable to emit a WARNING for it.
     193                 :          */
     194            1391 :         if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
     195                 :         {
     196                 :                 TransactionId parentXid;
     197                 : 
     198               0 :                 if (TransactionIdPrecedes(transactionId, TransactionXmin))
     199               0 :                         return false;
     200               0 :                 parentXid = SubTransGetParent(transactionId);
     201               0 :                 if (!TransactionIdIsValid(parentXid))
     202                 :                 {
     203               0 :                         elog(WARNING, "no pg_subtrans entry for subcommitted XID %u",
     204                 :                                  transactionId);
     205               0 :                         return false;
     206                 :                 }
     207               0 :                 return TransactionIdDidCommit(parentXid);
     208                 :         }
     209                 : 
     210                 :         /*
     211                 :          * It's not committed.
     212                 :          */
     213            1391 :         return false;
     214                 : }
     215                 : 
     216                 : /*
     217                 :  * TransactionIdDidAbort
     218                 :  *              True iff transaction associated with the identifier did abort.
     219                 :  *
     220                 :  * Note:
     221                 :  *              Assumes transaction identifier is valid.
     222                 :  */
     223                 : bool                                                    /* true if given transaction aborted */
     224                 : TransactionIdDidAbort(TransactionId transactionId)
     225               0 : {
     226                 :         XidStatus       xidstatus;
     227                 : 
     228               0 :         xidstatus = TransactionLogFetch(transactionId);
     229                 : 
     230                 :         /*
     231                 :          * If it's marked aborted, it's aborted.
     232                 :          */
     233               0 :         if (xidstatus == TRANSACTION_STATUS_ABORTED)
     234               0 :                 return true;
     235                 : 
     236                 :         /*
     237                 :          * If it's marked subcommitted, we have to check the parent recursively.
     238                 :          * However, if it's older than TransactionXmin, we can't look at
     239                 :          * pg_subtrans; instead assume that the parent crashed without cleaning up
     240                 :          * its children.
     241                 :          */
     242               0 :         if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
     243                 :         {
     244                 :                 TransactionId parentXid;
     245                 : 
     246               0 :                 if (TransactionIdPrecedes(transactionId, TransactionXmin))
     247               0 :                         return true;
     248               0 :                 parentXid = SubTransGetParent(transactionId);
     249               0 :                 if (!TransactionIdIsValid(parentXid))
     250                 :                 {
     251                 :                         /* see notes in TransactionIdDidCommit */
     252               0 :                         elog(WARNING, "no pg_subtrans entry for subcommitted XID %u",
     253                 :                                  transactionId);
     254               0 :                         return true;
     255                 :                 }
     256               0 :                 return TransactionIdDidAbort(parentXid);
     257                 :         }
     258                 : 
     259                 :         /*
     260                 :          * It's not aborted.
     261                 :          */
     262               0 :         return false;
     263                 : }
     264                 : 
     265                 : /* --------------------------------
     266                 :  *              TransactionId Commit
     267                 :  *              TransactionId Abort
     268                 :  * --------------------------------
     269                 :  */
     270                 : 
     271                 : /*
     272                 :  * TransactionIdCommit
     273                 :  *              Commits the transaction associated with the identifier.
     274                 :  *
     275                 :  * Note:
     276                 :  *              Assumes transaction identifier is valid.
     277                 :  */
     278                 : void
     279                 : TransactionIdCommit(TransactionId transactionId)
     280            8469 : {
     281            8469 :         TransactionLogUpdate(transactionId, TRANSACTION_STATUS_COMMITTED,
     282                 :                                                  InvalidXLogRecPtr);
     283            8469 : }
     284                 : 
     285                 : /*
     286                 :  * TransactionIdAsyncCommit
     287                 :  *              Same as above, but for async commits.  The commit record LSN is needed.
     288                 :  */
     289                 : void
     290                 : TransactionIdAsyncCommit(TransactionId transactionId, XLogRecPtr lsn)
     291               0 : {
     292               0 :         TransactionLogUpdate(transactionId, TRANSACTION_STATUS_COMMITTED, lsn);
     293               0 : }
     294                 : 
     295                 : 
     296                 : /*
     297                 :  * TransactionIdAbort
     298                 :  *              Aborts the transaction associated with the identifier.
     299                 :  *
     300                 :  * Note:
     301                 :  *              Assumes transaction identifier is valid.
     302                 :  *              No async version of this is needed.
     303                 :  */
     304                 : void
     305                 : TransactionIdAbort(TransactionId transactionId)
     306             191 : {
     307             191 :         TransactionLogUpdate(transactionId, TRANSACTION_STATUS_ABORTED,
     308                 :                                                  InvalidXLogRecPtr);
     309             191 : }
     310                 : 
     311                 : /*
     312                 :  * TransactionIdSubCommit
     313                 :  *              Marks the subtransaction associated with the identifier as
     314                 :  *              sub-committed.
     315                 :  *
     316                 :  * Note:
     317                 :  *              No async version of this is needed.
     318                 :  */
     319                 : void
     320                 : TransactionIdSubCommit(TransactionId transactionId)
     321              19 : {
     322              19 :         TransactionLogUpdate(transactionId, TRANSACTION_STATUS_SUB_COMMITTED,
     323                 :                                                  InvalidXLogRecPtr);
     324              19 : }
     325                 : 
     326                 : /*
     327                 :  * TransactionIdCommitTree
     328                 :  *              Marks all the given transaction ids as committed.
     329                 :  *
     330                 :  * The caller has to be sure that this is used only to mark subcommitted
     331                 :  * subtransactions as committed, and only *after* marking the toplevel
     332                 :  * parent as committed.  Otherwise there is a race condition against
     333                 :  * TransactionIdDidCommit.
     334                 :  */
     335                 : void
     336                 : TransactionIdCommitTree(int nxids, TransactionId *xids)
     337            8469 : {
     338            8469 :         if (nxids > 0)
     339               9 :                 TransactionLogMultiUpdate(nxids, xids, TRANSACTION_STATUS_COMMITTED,
     340                 :                                                                   InvalidXLogRecPtr);
     341            8469 : }
     342                 : 
     343                 : /*
     344                 :  * TransactionIdAsyncCommitTree
     345                 :  *              Same as above, but for async commits.  The commit record LSN is needed.
     346                 :  */
     347                 : void
     348                 : TransactionIdAsyncCommitTree(int nxids, TransactionId *xids, XLogRecPtr lsn)
     349               0 : {
     350               0 :         if (nxids > 0)
     351               0 :                 TransactionLogMultiUpdate(nxids, xids, TRANSACTION_STATUS_COMMITTED,
     352                 :                                                                   lsn);
     353               0 : }
     354                 : 
     355                 : 
     356                 : /*
     357                 :  * TransactionIdAbortTree
     358                 :  *              Marks all the given transaction ids as aborted.
     359                 :  *
     360                 :  * We don't need to worry about the non-atomic behavior, since any onlookers
     361                 :  * will consider all the xacts as not-yet-committed anyway.
     362                 :  */
     363                 : void
     364                 : TransactionIdAbortTree(int nxids, TransactionId *xids)
     365             191 : {
     366             191 :         if (nxids > 0)
     367               5 :                 TransactionLogMultiUpdate(nxids, xids, TRANSACTION_STATUS_ABORTED,
     368                 :                                                                   InvalidXLogRecPtr);
     369             191 : }
     370                 : 
     371                 : /*
     372                 :  * TransactionIdPrecedes --- is id1 logically < id2?
     373                 :  */
     374                 : bool
     375                 : TransactionIdPrecedes(TransactionId id1, TransactionId id2)
     376         1557197 : {
     377                 :         /*
     378                 :          * If either ID is a permanent XID then we can just do unsigned
     379                 :          * comparison.  If both are normal, do a modulo-2^31 comparison.
     380                 :          */
     381                 :         int32           diff;
     382                 : 
     383         1557197 :         if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
     384          491940 :                 return (id1 < id2);
     385                 : 
     386         1065257 :         diff = (int32) (id1 - id2);
     387         1065257 :         return (diff < 0);
     388                 : }
     389                 : 
     390                 : /*
     391                 :  * TransactionIdPrecedesOrEquals --- is id1 logically <= id2?
     392                 :  */
     393                 : bool
     394                 : TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
     395               0 : {
     396                 :         int32           diff;
     397                 : 
     398               0 :         if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
     399               0 :                 return (id1 <= id2);
     400                 : 
     401               0 :         diff = (int32) (id1 - id2);
     402               0 :         return (diff <= 0);
     403                 : }
     404                 : 
     405                 : /*
     406                 :  * TransactionIdFollows --- is id1 logically > id2?
     407                 :  */
     408                 : bool
     409                 : TransactionIdFollows(TransactionId id1, TransactionId id2)
     410               6 : {
     411                 :         int32           diff;
     412                 : 
     413               6 :         if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
     414               0 :                 return (id1 > id2);
     415                 : 
     416               6 :         diff = (int32) (id1 - id2);
     417               6 :         return (diff > 0);
     418                 : }
     419                 : 
     420                 : /*
     421                 :  * TransactionIdFollowsOrEquals --- is id1 logically >= id2?
     422                 :  */
     423                 : bool
     424                 : TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
     425           32206 : {
     426                 :         int32           diff;
     427                 : 
     428           32206 :         if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
     429               6 :                 return (id1 >= id2);
     430                 : 
     431           32200 :         diff = (int32) (id1 - id2);
     432           32200 :         return (diff >= 0);
     433                 : }
     434                 : 
     435                 : 
     436                 : /*
     437                 :  * TransactionIdLatest --- get latest XID among a main xact and its children
     438                 :  */
     439                 : TransactionId
     440                 : TransactionIdLatest(TransactionId mainxid,
     441                 :                                         int nxids, const TransactionId *xids)
     442            8865 : {
     443                 :         TransactionId result;
     444                 : 
     445                 :         /*
     446                 :          * In practice it is highly likely that the xids[] array is sorted, and so
     447                 :          * we could save some cycles by just taking the last child XID, but this
     448                 :          * probably isn't so performance-critical that it's worth depending on
     449                 :          * that assumption.  But just to show we're not totally stupid, scan the
     450                 :          * array back-to-front to avoid useless assignments.
     451                 :          */
     452            8865 :         result = mainxid;
     453           17749 :         while (--nxids >= 0)
     454                 :         {
     455              19 :                 if (TransactionIdPrecedes(result, xids[nxids]))
     456              14 :                         result = xids[nxids];
     457                 :         }
     458            8865 :         return result;
     459                 : }
     460                 : 
     461                 : 
     462                 : /*
     463                 :  * TransactionIdGetCommitLSN
     464                 :  *
     465                 :  * This function returns an LSN that is late enough to be able
     466                 :  * to guarantee that if we flush up to the LSN returned then we
     467                 :  * will have flushed the transaction's commit record to disk.
     468                 :  *
     469                 :  * The result is not necessarily the exact LSN of the transaction's
     470                 :  * commit record!  For example, for long-past transactions (those whose
     471                 :  * clog pages already migrated to disk), we'll return InvalidXLogRecPtr.
     472                 :  * Also, because we group transactions on the same clog page to conserve
     473                 :  * storage, we might return the LSN of a later transaction that falls into
     474                 :  * the same group.
     475                 :  */
     476                 : XLogRecPtr
     477                 : TransactionIdGetCommitLSN(TransactionId xid)
     478          226176 : {
     479                 :         XLogRecPtr      result;
     480                 : 
     481                 :         /*
     482                 :          * Currently, all uses of this function are for xids that were just
     483                 :          * reported to be committed by TransactionLogFetch, so we expect that
     484                 :          * checking TransactionLogFetch's cache will usually succeed and avoid an
     485                 :          * extra trip to shared memory.
     486                 :          */
     487          226176 :         if (TransactionIdEquals(xid, cachedFetchXid))
     488          221066 :                 return cachedCommitLSN;
     489                 : 
     490                 :         /* Special XIDs are always known committed */
     491            5110 :         if (!TransactionIdIsNormal(xid))
     492            5110 :                 return InvalidXLogRecPtr;
     493                 : 
     494                 :         /*
     495                 :          * Get the transaction status.
     496                 :          */
     497               0 :         (void) TransactionIdGetStatus(xid, &result);
     498                 : 
     499               0 :         return result;
     500                 : }

Generated by: LTP GCOV extension version 1.5