diff options
author | Tom Lane | 2008-03-11 20:20:35 +0000 |
---|---|---|
committer | Tom Lane | 2008-03-11 20:20:35 +0000 |
commit | 394e866f40cba12ed1c1e4c4f8ec6c48e00aaaaa (patch) | |
tree | 571d5e7b88f31b5f85e6d837b0510ee7ab5d28f2 | |
parent | 135ab1438ecd960dba0de5ae3469d89fc137c83e (diff) |
Make TransactionIdIsInProgress check transam.c's single-item XID status cache
before it goes groveling through the ProcArray. In situations where the same
recently-committed transaction ID is checked repeatedly by tqual.c, this saves
a lot of shared-memory searches. And it's cheap enough that it shouldn't
hurt noticeably when it doesn't help.
Concept and patch by Simon, some minor tweaking and comment-cleanup by Tom.
-rw-r--r-- | src/backend/access/transam/transam.c | 75 | ||||
-rw-r--r-- | src/backend/storage/ipc/procarray.c | 17 | ||||
-rw-r--r-- | src/include/access/transam.h | 1 |
3 files changed, 64 insertions, 29 deletions
diff --git a/src/backend/access/transam/transam.c b/src/backend/access/transam/transam.c index 1f9eed0a84..c83e4a8237 100644 --- a/src/backend/access/transam/transam.c +++ b/src/backend/access/transam/transam.c @@ -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 69bb1614d4..5927f15a6e 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -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) @@ -354,6 +357,17 @@ TransactionIdIsInProgress(TransactionId xid) } /* + * 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 ca64f84319..ba8b253101 100644 --- a/src/include/access/transam.h +++ b/src/include/access/transam.h @@ -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); |