Commit 611b4393 authored by Tom Lane's avatar Tom Lane

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.
parent ba8a9a92
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* This file contains the high level access-method interface to the * This file contains the high level access-method interface to the
...@@ -25,12 +25,11 @@ ...@@ -25,12 +25,11 @@
#include "utils/tqual.h" #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 TransactionId cachedFetchXid = InvalidTransactionId;
static XidStatus cachedFetchXidStatus; static XidStatus cachedFetchXidStatus;
...@@ -39,9 +38,14 @@ static XLogRecPtr cachedCommitLSN; ...@@ -39,9 +38,14 @@ static XLogRecPtr cachedCommitLSN;
/* Handy constant for an invalid xlog recptr */ /* Handy constant for an invalid xlog recptr */
static const XLogRecPtr InvalidXLogRecPtr = {0, 0}; 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 * TransactionLogFetch
* TransactionLogUpdate * TransactionLogUpdate
...@@ -82,8 +86,8 @@ TransactionLogFetch(TransactionId transactionId) ...@@ -82,8 +86,8 @@ TransactionLogFetch(TransactionId transactionId)
xidstatus = TransactionIdGetStatus(transactionId, &xidlsn); xidstatus = TransactionIdGetStatus(transactionId, &xidlsn);
/* /*
* DO NOT cache status for unfinished or sub-committed transactions! We * Cache it, but DO NOT cache status for unfinished or sub-committed
* only cache status that is guaranteed not to change. * transactions! We only cache status that is guaranteed not to change.
*/ */
if (xidstatus != TRANSACTION_STATUS_IN_PROGRESS && if (xidstatus != TRANSACTION_STATUS_IN_PROGRESS &&
xidstatus != TRANSACTION_STATUS_SUB_COMMITTED) xidstatus != TRANSACTION_STATUS_SUB_COMMITTED)
...@@ -96,12 +100,11 @@ TransactionLogFetch(TransactionId transactionId) ...@@ -96,12 +100,11 @@ TransactionLogFetch(TransactionId transactionId)
return xidstatus; return xidstatus;
} }
/* -------------------------------- /*
* TransactionLogUpdate * TransactionLogUpdate
* *
* Store the new status of a transaction. The commit record LSN must be * Store the new status of a transaction. The commit record LSN must be
* passed when recording an async commit; else it should be InvalidXLogRecPtr. * passed when recording an async commit; else it should be InvalidXLogRecPtr.
* --------------------------------
*/ */
static inline void static inline void
TransactionLogUpdate(TransactionId transactionId, TransactionLogUpdate(TransactionId transactionId,
...@@ -131,32 +134,27 @@ TransactionLogMultiUpdate(int nxids, TransactionId *xids, ...@@ -131,32 +134,27 @@ TransactionLogMultiUpdate(int nxids, TransactionId *xids,
TransactionIdSetStatus(xids[i], status, lsn); TransactionIdSetStatus(xids[i], status, lsn);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* Interface functions * Interface functions
* *
* TransactionId DidCommit * TransactionIdDidCommit
* TransactionId DidAbort * TransactionIdDidAbort
* TransactionId IsInProgress
* ======== * ========
* these functions test the transaction status of * these functions test the transaction status of
* a specified transaction id. * a specified transaction id.
* *
* TransactionId Commit * TransactionIdCommit
* TransactionId Abort * TransactionIdAbort
* ======== * ========
* these functions set the transaction status * these functions set the transaction status
* of the specified xid. * 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 * TransactionIdDidCommit
* True iff transaction associated with the identifier did commit. * True iff transaction associated with the identifier did commit.
...@@ -262,11 +260,33 @@ TransactionIdDidAbort(TransactionId transactionId) ...@@ -262,11 +260,33 @@ TransactionIdDidAbort(TransactionId transactionId)
return false; return false;
} }
/* -------------------------------- /*
* TransactionId Commit * TransactionIdIsKnownCompleted
* TransactionId Abort * 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 * TransactionIdCommit
...@@ -292,7 +312,6 @@ TransactionIdAsyncCommit(TransactionId transactionId, XLogRecPtr lsn) ...@@ -292,7 +312,6 @@ TransactionIdAsyncCommit(TransactionId transactionId, XLogRecPtr lsn)
TransactionLogUpdate(transactionId, TRANSACTION_STATUS_COMMITTED, lsn); TransactionLogUpdate(transactionId, TRANSACTION_STATUS_COMMITTED, lsn);
} }
/* /*
* TransactionIdAbort * TransactionIdAbort
* Aborts the transaction associated with the identifier. * Aborts the transaction associated with the identifier.
...@@ -352,7 +371,6 @@ TransactionIdAsyncCommitTree(int nxids, TransactionId *xids, XLogRecPtr lsn) ...@@ -352,7 +371,6 @@ TransactionIdAsyncCommitTree(int nxids, TransactionId *xids, XLogRecPtr lsn)
lsn); lsn);
} }
/* /*
* TransactionIdAbortTree * TransactionIdAbortTree
* Marks all the given transaction ids as aborted. * Marks all the given transaction ids as aborted.
...@@ -368,6 +386,7 @@ TransactionIdAbortTree(int nxids, TransactionId *xids) ...@@ -368,6 +386,7 @@ TransactionIdAbortTree(int nxids, TransactionId *xids)
InvalidXLogRecPtr); InvalidXLogRecPtr);
} }
/* /*
* TransactionIdPrecedes --- is id1 logically < id2? * TransactionIdPrecedes --- is id1 logically < id2?
*/ */
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
* *
* *
* IDENTIFICATION * 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; ...@@ -60,6 +60,7 @@ static ProcArrayStruct *procArray;
/* counters for XidCache measurement */ /* counters for XidCache measurement */
static long xc_by_recent_xmin = 0; 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_my_xact = 0;
static long xc_by_latest_xid = 0; static long xc_by_latest_xid = 0;
static long xc_by_main_xid = 0; static long xc_by_main_xid = 0;
...@@ -68,6 +69,7 @@ static long xc_no_overflow = 0; ...@@ -68,6 +69,7 @@ static long xc_no_overflow = 0;
static long xc_slow_answer = 0; static long xc_slow_answer = 0;
#define xc_by_recent_xmin_inc() (xc_by_recent_xmin++) #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_my_xact_inc() (xc_by_my_xact++)
#define xc_by_latest_xid_inc() (xc_by_latest_xid++) #define xc_by_latest_xid_inc() (xc_by_latest_xid++)
#define xc_by_main_xid_inc() (xc_by_main_xid++) #define xc_by_main_xid_inc() (xc_by_main_xid++)
...@@ -79,6 +81,7 @@ static void DisplayXidCache(void); ...@@ -79,6 +81,7 @@ static void DisplayXidCache(void);
#else /* !XIDCACHE_DEBUG */ #else /* !XIDCACHE_DEBUG */
#define xc_by_recent_xmin_inc() ((void) 0) #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_my_xact_inc() ((void) 0)
#define xc_by_latest_xid_inc() ((void) 0) #define xc_by_latest_xid_inc() ((void) 0)
#define xc_by_main_xid_inc() ((void) 0) #define xc_by_main_xid_inc() ((void) 0)
...@@ -353,6 +356,17 @@ TransactionIdIsInProgress(TransactionId xid) ...@@ -353,6 +356,17 @@ TransactionIdIsInProgress(TransactionId xid)
return false; 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 * Also, we can handle our own transaction (and subtransactions) without
* any access to shared memory. * any access to shared memory.
...@@ -1335,8 +1349,9 @@ static void ...@@ -1335,8 +1349,9 @@ static void
DisplayXidCache(void) DisplayXidCache(void)
{ {
fprintf(stderr, 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_recent_xmin,
xc_by_known_xact,
xc_by_my_xact, xc_by_my_xact,
xc_by_latest_xid, xc_by_latest_xid,
xc_by_main_xid, xc_by_main_xid,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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; ...@@ -138,6 +138,7 @@ extern VariableCache ShmemVariableCache;
*/ */
extern bool TransactionIdDidCommit(TransactionId transactionId); extern bool TransactionIdDidCommit(TransactionId transactionId);
extern bool TransactionIdDidAbort(TransactionId transactionId); extern bool TransactionIdDidAbort(TransactionId transactionId);
extern bool TransactionIdIsKnownCompleted(TransactionId transactionId);
extern void TransactionIdCommit(TransactionId transactionId); extern void TransactionIdCommit(TransactionId transactionId);
extern void TransactionIdAsyncCommit(TransactionId transactionId, XLogRecPtr lsn); extern void TransactionIdAsyncCommit(TransactionId transactionId, XLogRecPtr lsn);
extern void TransactionIdAbort(TransactionId transactionId); extern void TransactionIdAbort(TransactionId transactionId);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment