diff --git a/src/backend/access/transam/transam.c b/src/backend/access/transam/transam.c index 43aed75ad0..4c0cb4baf6 100644 --- a/src/backend/access/transam/transam.c +++ b/src/backend/access/transam/transam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/transam/transam.c,v 1.73 2008/01/01 19:45:48 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/transam.c,v 1.74 2008/03/11 20:20:35 tgl Exp $ * * NOTES * This file contains the high level access-method interface to the @@ -25,12 +25,11 @@ #include "utils/tqual.h" -static XidStatus TransactionLogFetch(TransactionId transactionId); -static void TransactionLogUpdate(TransactionId transactionId, - XidStatus status, XLogRecPtr lsn); - /* - * Single-item cache for results of TransactionLogFetch. + * Single-item cache for results of TransactionLogFetch. It's worth having + * such a cache because we frequently find ourselves repeatedly checking the + * same XID, for example when scanning a table just after a bulk insert, + * update, or delete. */ static TransactionId cachedFetchXid = InvalidTransactionId; static XidStatus cachedFetchXidStatus; @@ -39,9 +38,14 @@ static XLogRecPtr cachedCommitLSN; /* Handy constant for an invalid xlog recptr */ static const XLogRecPtr InvalidXLogRecPtr = {0, 0}; +/* Local functions */ +static XidStatus TransactionLogFetch(TransactionId transactionId); +static void TransactionLogUpdate(TransactionId transactionId, + XidStatus status, XLogRecPtr lsn); + /* ---------------------------------------------------------------- - * postgres log access method interface + * Postgres log access method interface * * TransactionLogFetch * TransactionLogUpdate @@ -82,8 +86,8 @@ TransactionLogFetch(TransactionId transactionId) xidstatus = TransactionIdGetStatus(transactionId, &xidlsn); /* - * DO NOT cache status for unfinished or sub-committed transactions! We - * only cache status that is guaranteed not to change. + * Cache it, but DO NOT cache status for unfinished or sub-committed + * transactions! We only cache status that is guaranteed not to change. */ if (xidstatus != TRANSACTION_STATUS_IN_PROGRESS && xidstatus != TRANSACTION_STATUS_SUB_COMMITTED) @@ -96,12 +100,11 @@ TransactionLogFetch(TransactionId transactionId) return xidstatus; } -/* -------------------------------- +/* * TransactionLogUpdate * * Store the new status of a transaction. The commit record LSN must be * passed when recording an async commit; else it should be InvalidXLogRecPtr. - * -------------------------------- */ static inline void TransactionLogUpdate(TransactionId transactionId, @@ -131,32 +134,27 @@ TransactionLogMultiUpdate(int nxids, TransactionId *xids, TransactionIdSetStatus(xids[i], status, lsn); } + /* ---------------------------------------------------------------- * Interface functions * - * TransactionId DidCommit - * TransactionId DidAbort - * TransactionId IsInProgress + * TransactionIdDidCommit + * TransactionIdDidAbort * ======== * these functions test the transaction status of * a specified transaction id. * - * TransactionId Commit - * TransactionId Abort + * TransactionIdCommit + * TransactionIdAbort * ======== * these functions set the transaction status * of the specified xid. * + * See also TransactionIdIsInProgress, which once was in this module + * but now lives in procarray.c. * ---------------------------------------------------------------- */ -/* -------------------------------- - * TransactionId DidCommit - * TransactionId DidAbort - * TransactionId IsInProgress - * -------------------------------- - */ - /* * TransactionIdDidCommit * True iff transaction associated with the identifier did commit. @@ -262,11 +260,33 @@ TransactionIdDidAbort(TransactionId transactionId) return false; } -/* -------------------------------- - * TransactionId Commit - * TransactionId Abort - * -------------------------------- +/* + * TransactionIdIsKnownCompleted + * True iff transaction associated with the identifier is currently + * known to have either committed or aborted. + * + * This does NOT look into pg_clog but merely probes our local cache + * (and so it's not named TransactionIdDidComplete, which would be the + * appropriate name for a function that worked that way). The intended + * use is just to short-circuit TransactionIdIsInProgress calls when doing + * repeated tqual.c checks for the same XID. If this isn't extremely fast + * then it will be counterproductive. + * + * Note: + * Assumes transaction identifier is valid. */ +bool +TransactionIdIsKnownCompleted(TransactionId transactionId) +{ + if (TransactionIdEquals(transactionId, cachedFetchXid)) + { + /* If it's in the cache at all, it must be completed. */ + return true; + } + + return false; +} + /* * TransactionIdCommit @@ -292,7 +312,6 @@ TransactionIdAsyncCommit(TransactionId transactionId, XLogRecPtr lsn) TransactionLogUpdate(transactionId, TRANSACTION_STATUS_COMMITTED, lsn); } - /* * TransactionIdAbort * Aborts the transaction associated with the identifier. @@ -352,7 +371,6 @@ TransactionIdAsyncCommitTree(int nxids, TransactionId *xids, XLogRecPtr lsn) lsn); } - /* * TransactionIdAbortTree * Marks all the given transaction ids as aborted. @@ -368,6 +386,7 @@ TransactionIdAbortTree(int nxids, TransactionId *xids) InvalidXLogRecPtr); } + /* * TransactionIdPrecedes --- is id1 logically < id2? */ diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 575b138c43..d7ba39bc5d 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -23,7 +23,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.40 2008/01/09 21:52:36 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.41 2008/03/11 20:20:35 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -60,6 +60,7 @@ static ProcArrayStruct *procArray; /* counters for XidCache measurement */ static long xc_by_recent_xmin = 0; +static long xc_by_known_xact = 0; static long xc_by_my_xact = 0; static long xc_by_latest_xid = 0; static long xc_by_main_xid = 0; @@ -68,6 +69,7 @@ static long xc_no_overflow = 0; static long xc_slow_answer = 0; #define xc_by_recent_xmin_inc() (xc_by_recent_xmin++) +#define xc_by_known_xact_inc() (xc_by_known_xact++) #define xc_by_my_xact_inc() (xc_by_my_xact++) #define xc_by_latest_xid_inc() (xc_by_latest_xid++) #define xc_by_main_xid_inc() (xc_by_main_xid++) @@ -79,6 +81,7 @@ static void DisplayXidCache(void); #else /* !XIDCACHE_DEBUG */ #define xc_by_recent_xmin_inc() ((void) 0) +#define xc_by_known_xact_inc() ((void) 0) #define xc_by_my_xact_inc() ((void) 0) #define xc_by_latest_xid_inc() ((void) 0) #define xc_by_main_xid_inc() ((void) 0) @@ -353,6 +356,17 @@ TransactionIdIsInProgress(TransactionId xid) return false; } + /* + * We may have just checked the status of this transaction, so if it is + * already known to be completed, we can fall out without any access to + * shared memory. + */ + if (TransactionIdIsKnownCompleted(xid)) + { + xc_by_known_xact_inc(); + return false; + } + /* * Also, we can handle our own transaction (and subtransactions) without * any access to shared memory. @@ -1335,8 +1349,9 @@ static void DisplayXidCache(void) { fprintf(stderr, - "XidCache: xmin: %ld, myxact: %ld, latest: %ld, mainxid: %ld, childxid: %ld, nooflo: %ld, slow: %ld\n", + "XidCache: xmin: %ld, known: %ld, myxact: %ld, latest: %ld, mainxid: %ld, childxid: %ld, nooflo: %ld, slow: %ld\n", xc_by_recent_xmin, + xc_by_known_xact, xc_by_my_xact, xc_by_latest_xid, xc_by_main_xid, diff --git a/src/include/access/transam.h b/src/include/access/transam.h index 1887f9d0ab..232c59cad3 100644 --- a/src/include/access/transam.h +++ b/src/include/access/transam.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/transam.h,v 1.64 2008/01/01 19:45:56 momjian Exp $ + * $PostgreSQL: pgsql/src/include/access/transam.h,v 1.65 2008/03/11 20:20:35 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -138,6 +138,7 @@ extern VariableCache ShmemVariableCache; */ extern bool TransactionIdDidCommit(TransactionId transactionId); extern bool TransactionIdDidAbort(TransactionId transactionId); +extern bool TransactionIdIsKnownCompleted(TransactionId transactionId); extern void TransactionIdCommit(TransactionId transactionId); extern void TransactionIdAsyncCommit(TransactionId transactionId, XLogRecPtr lsn); extern void TransactionIdAbort(TransactionId transactionId);