Header And Logo

PostgreSQL
| The world's most advanced open source database.

transam.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * transam.c
00004  *    postgres transaction log interface routines
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/access/transam/transam.c
00012  *
00013  * NOTES
00014  *    This file contains the high level access-method interface to the
00015  *    transaction system.
00016  *
00017  *-------------------------------------------------------------------------
00018  */
00019 
00020 #include "postgres.h"
00021 
00022 #include "access/clog.h"
00023 #include "access/subtrans.h"
00024 #include "access/transam.h"
00025 #include "utils/snapmgr.h"
00026 
00027 /*
00028  * Single-item cache for results of TransactionLogFetch.  It's worth having
00029  * such a cache because we frequently find ourselves repeatedly checking the
00030  * same XID, for example when scanning a table just after a bulk insert,
00031  * update, or delete.
00032  */
00033 static TransactionId cachedFetchXid = InvalidTransactionId;
00034 static XidStatus cachedFetchXidStatus;
00035 static XLogRecPtr cachedCommitLSN;
00036 
00037 /* Local functions */
00038 static XidStatus TransactionLogFetch(TransactionId transactionId);
00039 
00040 
00041 /* ----------------------------------------------------------------
00042  *      Postgres log access method interface
00043  *
00044  *      TransactionLogFetch
00045  * ----------------------------------------------------------------
00046  */
00047 
00048 /*
00049  * TransactionLogFetch --- fetch commit status of specified transaction id
00050  */
00051 static XidStatus
00052 TransactionLogFetch(TransactionId transactionId)
00053 {
00054     XidStatus   xidstatus;
00055     XLogRecPtr  xidlsn;
00056 
00057     /*
00058      * Before going to the commit log manager, check our single item cache to
00059      * see if we didn't just check the transaction status a moment ago.
00060      */
00061     if (TransactionIdEquals(transactionId, cachedFetchXid))
00062         return cachedFetchXidStatus;
00063 
00064     /*
00065      * Also, check to see if the transaction ID is a permanent one.
00066      */
00067     if (!TransactionIdIsNormal(transactionId))
00068     {
00069         if (TransactionIdEquals(transactionId, BootstrapTransactionId))
00070             return TRANSACTION_STATUS_COMMITTED;
00071         if (TransactionIdEquals(transactionId, FrozenTransactionId))
00072             return TRANSACTION_STATUS_COMMITTED;
00073         return TRANSACTION_STATUS_ABORTED;
00074     }
00075 
00076     /*
00077      * Get the transaction status.
00078      */
00079     xidstatus = TransactionIdGetStatus(transactionId, &xidlsn);
00080 
00081     /*
00082      * Cache it, but DO NOT cache status for unfinished or sub-committed
00083      * transactions!  We only cache status that is guaranteed not to change.
00084      */
00085     if (xidstatus != TRANSACTION_STATUS_IN_PROGRESS &&
00086         xidstatus != TRANSACTION_STATUS_SUB_COMMITTED)
00087     {
00088         cachedFetchXid = transactionId;
00089         cachedFetchXidStatus = xidstatus;
00090         cachedCommitLSN = xidlsn;
00091     }
00092 
00093     return xidstatus;
00094 }
00095 
00096 /* ----------------------------------------------------------------
00097  *                      Interface functions
00098  *
00099  *      TransactionIdDidCommit
00100  *      TransactionIdDidAbort
00101  *      ========
00102  *         these functions test the transaction status of
00103  *         a specified transaction id.
00104  *
00105  *      TransactionIdCommitTree
00106  *      TransactionIdAsyncCommitTree
00107  *      TransactionIdAbortTree
00108  *      ========
00109  *         these functions set the transaction status of the specified
00110  *         transaction tree.
00111  *
00112  * See also TransactionIdIsInProgress, which once was in this module
00113  * but now lives in procarray.c.
00114  * ----------------------------------------------------------------
00115  */
00116 
00117 /*
00118  * TransactionIdDidCommit
00119  *      True iff transaction associated with the identifier did commit.
00120  *
00121  * Note:
00122  *      Assumes transaction identifier is valid.
00123  */
00124 bool                            /* true if given transaction committed */
00125 TransactionIdDidCommit(TransactionId transactionId)
00126 {
00127     XidStatus   xidstatus;
00128 
00129     xidstatus = TransactionLogFetch(transactionId);
00130 
00131     /*
00132      * If it's marked committed, it's committed.
00133      */
00134     if (xidstatus == TRANSACTION_STATUS_COMMITTED)
00135         return true;
00136 
00137     /*
00138      * If it's marked subcommitted, we have to check the parent recursively.
00139      * However, if it's older than TransactionXmin, we can't look at
00140      * pg_subtrans; instead assume that the parent crashed without cleaning up
00141      * its children.
00142      *
00143      * Originally we Assert'ed that the result of SubTransGetParent was not
00144      * zero. However with the introduction of prepared transactions, there can
00145      * be a window just after database startup where we do not have complete
00146      * knowledge in pg_subtrans of the transactions after TransactionXmin.
00147      * StartupSUBTRANS() has ensured that any missing information will be
00148      * zeroed.  Since this case should not happen under normal conditions, it
00149      * seems reasonable to emit a WARNING for it.
00150      */
00151     if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
00152     {
00153         TransactionId parentXid;
00154 
00155         if (TransactionIdPrecedes(transactionId, TransactionXmin))
00156             return false;
00157         parentXid = SubTransGetParent(transactionId);
00158         if (!TransactionIdIsValid(parentXid))
00159         {
00160             elog(WARNING, "no pg_subtrans entry for subcommitted XID %u",
00161                  transactionId);
00162             return false;
00163         }
00164         return TransactionIdDidCommit(parentXid);
00165     }
00166 
00167     /*
00168      * It's not committed.
00169      */
00170     return false;
00171 }
00172 
00173 /*
00174  * TransactionIdDidAbort
00175  *      True iff transaction associated with the identifier did abort.
00176  *
00177  * Note:
00178  *      Assumes transaction identifier is valid.
00179  */
00180 bool                            /* true if given transaction aborted */
00181 TransactionIdDidAbort(TransactionId transactionId)
00182 {
00183     XidStatus   xidstatus;
00184 
00185     xidstatus = TransactionLogFetch(transactionId);
00186 
00187     /*
00188      * If it's marked aborted, it's aborted.
00189      */
00190     if (xidstatus == TRANSACTION_STATUS_ABORTED)
00191         return true;
00192 
00193     /*
00194      * If it's marked subcommitted, we have to check the parent recursively.
00195      * However, if it's older than TransactionXmin, we can't look at
00196      * pg_subtrans; instead assume that the parent crashed without cleaning up
00197      * its children.
00198      */
00199     if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
00200     {
00201         TransactionId parentXid;
00202 
00203         if (TransactionIdPrecedes(transactionId, TransactionXmin))
00204             return true;
00205         parentXid = SubTransGetParent(transactionId);
00206         if (!TransactionIdIsValid(parentXid))
00207         {
00208             /* see notes in TransactionIdDidCommit */
00209             elog(WARNING, "no pg_subtrans entry for subcommitted XID %u",
00210                  transactionId);
00211             return true;
00212         }
00213         return TransactionIdDidAbort(parentXid);
00214     }
00215 
00216     /*
00217      * It's not aborted.
00218      */
00219     return false;
00220 }
00221 
00222 /*
00223  * TransactionIdIsKnownCompleted
00224  *      True iff transaction associated with the identifier is currently
00225  *      known to have either committed or aborted.
00226  *
00227  * This does NOT look into pg_clog but merely probes our local cache
00228  * (and so it's not named TransactionIdDidComplete, which would be the
00229  * appropriate name for a function that worked that way).  The intended
00230  * use is just to short-circuit TransactionIdIsInProgress calls when doing
00231  * repeated tqual.c checks for the same XID.  If this isn't extremely fast
00232  * then it will be counterproductive.
00233  *
00234  * Note:
00235  *      Assumes transaction identifier is valid.
00236  */
00237 bool
00238 TransactionIdIsKnownCompleted(TransactionId transactionId)
00239 {
00240     if (TransactionIdEquals(transactionId, cachedFetchXid))
00241     {
00242         /* If it's in the cache at all, it must be completed. */
00243         return true;
00244     }
00245 
00246     return false;
00247 }
00248 
00249 /*
00250  * TransactionIdCommitTree
00251  *      Marks the given transaction and children as committed
00252  *
00253  * "xid" is a toplevel transaction commit, and the xids array contains its
00254  * committed subtransactions.
00255  *
00256  * This commit operation is not guaranteed to be atomic, but if not, subxids
00257  * are correctly marked subcommit first.
00258  */
00259 void
00260 TransactionIdCommitTree(TransactionId xid, int nxids, TransactionId *xids)
00261 {
00262     TransactionIdSetTreeStatus(xid, nxids, xids,
00263                                TRANSACTION_STATUS_COMMITTED,
00264                                InvalidXLogRecPtr);
00265 }
00266 
00267 /*
00268  * TransactionIdAsyncCommitTree
00269  *      Same as above, but for async commits.  The commit record LSN is needed.
00270  */
00271 void
00272 TransactionIdAsyncCommitTree(TransactionId xid, int nxids, TransactionId *xids,
00273                              XLogRecPtr lsn)
00274 {
00275     TransactionIdSetTreeStatus(xid, nxids, xids,
00276                                TRANSACTION_STATUS_COMMITTED, lsn);
00277 }
00278 
00279 /*
00280  * TransactionIdAbortTree
00281  *      Marks the given transaction and children as aborted.
00282  *
00283  * "xid" is a toplevel transaction commit, and the xids array contains its
00284  * committed subtransactions.
00285  *
00286  * We don't need to worry about the non-atomic behavior, since any onlookers
00287  * will consider all the xacts as not-yet-committed anyway.
00288  */
00289 void
00290 TransactionIdAbortTree(TransactionId xid, int nxids, TransactionId *xids)
00291 {
00292     TransactionIdSetTreeStatus(xid, nxids, xids,
00293                                TRANSACTION_STATUS_ABORTED, InvalidXLogRecPtr);
00294 }
00295 
00296 /*
00297  * TransactionIdPrecedes --- is id1 logically < id2?
00298  */
00299 bool
00300 TransactionIdPrecedes(TransactionId id1, TransactionId id2)
00301 {
00302     /*
00303      * If either ID is a permanent XID then we can just do unsigned
00304      * comparison.  If both are normal, do a modulo-2^31 comparison.
00305      */
00306     int32       diff;
00307 
00308     if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
00309         return (id1 < id2);
00310 
00311     diff = (int32) (id1 - id2);
00312     return (diff < 0);
00313 }
00314 
00315 /*
00316  * TransactionIdPrecedesOrEquals --- is id1 logically <= id2?
00317  */
00318 bool
00319 TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
00320 {
00321     int32       diff;
00322 
00323     if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
00324         return (id1 <= id2);
00325 
00326     diff = (int32) (id1 - id2);
00327     return (diff <= 0);
00328 }
00329 
00330 /*
00331  * TransactionIdFollows --- is id1 logically > id2?
00332  */
00333 bool
00334 TransactionIdFollows(TransactionId id1, TransactionId id2)
00335 {
00336     int32       diff;
00337 
00338     if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
00339         return (id1 > id2);
00340 
00341     diff = (int32) (id1 - id2);
00342     return (diff > 0);
00343 }
00344 
00345 /*
00346  * TransactionIdFollowsOrEquals --- is id1 logically >= id2?
00347  */
00348 bool
00349 TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
00350 {
00351     int32       diff;
00352 
00353     if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
00354         return (id1 >= id2);
00355 
00356     diff = (int32) (id1 - id2);
00357     return (diff >= 0);
00358 }
00359 
00360 
00361 /*
00362  * TransactionIdLatest --- get latest XID among a main xact and its children
00363  */
00364 TransactionId
00365 TransactionIdLatest(TransactionId mainxid,
00366                     int nxids, const TransactionId *xids)
00367 {
00368     TransactionId result;
00369 
00370     /*
00371      * In practice it is highly likely that the xids[] array is sorted, and so
00372      * we could save some cycles by just taking the last child XID, but this
00373      * probably isn't so performance-critical that it's worth depending on
00374      * that assumption.  But just to show we're not totally stupid, scan the
00375      * array back-to-front to avoid useless assignments.
00376      */
00377     result = mainxid;
00378     while (--nxids >= 0)
00379     {
00380         if (TransactionIdPrecedes(result, xids[nxids]))
00381             result = xids[nxids];
00382     }
00383     return result;
00384 }
00385 
00386 
00387 /*
00388  * TransactionIdGetCommitLSN
00389  *
00390  * This function returns an LSN that is late enough to be able
00391  * to guarantee that if we flush up to the LSN returned then we
00392  * will have flushed the transaction's commit record to disk.
00393  *
00394  * The result is not necessarily the exact LSN of the transaction's
00395  * commit record!  For example, for long-past transactions (those whose
00396  * clog pages already migrated to disk), we'll return InvalidXLogRecPtr.
00397  * Also, because we group transactions on the same clog page to conserve
00398  * storage, we might return the LSN of a later transaction that falls into
00399  * the same group.
00400  */
00401 XLogRecPtr
00402 TransactionIdGetCommitLSN(TransactionId xid)
00403 {
00404     XLogRecPtr  result;
00405 
00406     /*
00407      * Currently, all uses of this function are for xids that were just
00408      * reported to be committed by TransactionLogFetch, so we expect that
00409      * checking TransactionLogFetch's cache will usually succeed and avoid an
00410      * extra trip to shared memory.
00411      */
00412     if (TransactionIdEquals(xid, cachedFetchXid))
00413         return cachedCommitLSN;
00414 
00415     /* Special XIDs are always known committed */
00416     if (!TransactionIdIsNormal(xid))
00417         return InvalidXLogRecPtr;
00418 
00419     /*
00420      * Get the transaction status.
00421      */
00422     (void) TransactionIdGetStatus(xid, &result);
00423 
00424     return result;
00425 }