summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2008-03-11 20:20:35 +0000
committerTom Lane2008-03-11 20:20:35 +0000
commit394e866f40cba12ed1c1e4c4f8ec6c48e00aaaaa (patch)
tree571d5e7b88f31b5f85e6d837b0510ee7ab5d28f2
parent135ab1438ecd960dba0de5ae3469d89fc137c83e (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.c75
-rw-r--r--src/backend/storage/ipc/procarray.c17
-rw-r--r--src/include/access/transam.h1
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);