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.
This commit is contained in:
parent
ba8a9a9282
commit
611b4393f2
|
@ -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?
|
||||
*/
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue