From da072ab2ab538bf1811abe5a1df131c0c9a8e6e4 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 21 Sep 2007 17:36:53 +0000 Subject: [PATCH] Make some simple performance improvements in TransactionIdIsInProgress(). For XIDs of our own transaction and subtransactions, it's cheaper to ask TransactionIdIsCurrentTransactionId() than to look in shared memory. Also, the xids[] work array is always the same size within any given process, so malloc it just once instead of doing a palloc/pfree on every call; aside from being faster this lets us get rid of some goto's, since we no longer have any end-of-function pfree to do. Both ideas by Heikki. --- src/backend/storage/ipc/procarray.c | 75 ++++++++++++++++++----------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 0565510c31..dbac4a8fd0 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.33 2007/09/08 20:31:15 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.34 2007/09/21 17:36:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -60,11 +60,13 @@ static ProcArrayStruct *procArray; /* counters for XidCache measurement */ static long xc_by_recent_xmin = 0; +static long xc_by_my_xact = 0; static long xc_by_main_xid = 0; static long xc_by_child_xid = 0; static long xc_slow_answer = 0; #define xc_by_recent_xmin_inc() (xc_by_recent_xmin++) +#define xc_by_my_xact_inc() (xc_by_my_xact++) #define xc_by_main_xid_inc() (xc_by_main_xid++) #define xc_by_child_xid_inc() (xc_by_child_xid++) #define xc_slow_answer_inc() (xc_slow_answer++) @@ -73,6 +75,7 @@ static void DisplayXidCache(void); #else /* !XIDCACHE_DEBUG */ #define xc_by_recent_xmin_inc() ((void) 0) +#define xc_by_my_xact_inc() ((void) 0) #define xc_by_main_xid_inc() ((void) 0) #define xc_by_child_xid_inc() ((void) 0) #define xc_slow_answer_inc() ((void) 0) @@ -320,14 +323,12 @@ ProcArrayClearTransaction(PGPROC *proc) bool TransactionIdIsInProgress(TransactionId xid) { - bool result = false; + static TransactionId *xids = NULL; + int nxids = 0; ProcArrayStruct *arrayP = procArray; + TransactionId topxid; int i, j; - int nxids = 0; - TransactionId *xids; - TransactionId topxid; - bool locked; /* * Don't bother checking a transaction older than RecentXmin; it could not @@ -341,18 +342,43 @@ TransactionIdIsInProgress(TransactionId xid) return false; } - /* Get workspace to remember main XIDs in */ - xids = (TransactionId *) palloc(sizeof(TransactionId) * arrayP->maxProcs); + /* + * Also, we can handle our own transaction (and subtransactions) without + * any access to shared memory. + */ + if (TransactionIdIsCurrentTransactionId(xid)) + { + xc_by_my_xact_inc(); + return true; + } + + /* + * If not first time through, get workspace to remember main XIDs in. + * We malloc it permanently to avoid repeated palloc/pfree overhead. + */ + if (xids == NULL) + { + xids = (TransactionId *) + malloc(arrayP->maxProcs * sizeof(TransactionId)); + if (xids == NULL) + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + } LWLockAcquire(ProcArrayLock, LW_SHARED); - locked = true; for (i = 0; i < arrayP->numProcs; i++) { volatile PGPROC *proc = arrayP->procs[i]; + TransactionId pxid; + + /* Ignore my own proc --- dealt with it above */ + if (proc == MyProc) + continue; /* Fetch xid just once - see GetNewTransactionId */ - TransactionId pxid = proc->xid; + pxid = proc->xid; if (!TransactionIdIsValid(pxid)) continue; @@ -362,9 +388,9 @@ TransactionIdIsInProgress(TransactionId xid) */ if (TransactionIdEquals(pxid, xid)) { + LWLockRelease(ProcArrayLock); xc_by_main_xid_inc(); - result = true; - goto result_known; + return true; } /* @@ -384,9 +410,9 @@ TransactionIdIsInProgress(TransactionId xid) if (TransactionIdEquals(cxid, xid)) { + LWLockRelease(ProcArrayLock); xc_by_child_xid_inc(); - result = true; - goto result_known; + return true; } } @@ -402,14 +428,13 @@ TransactionIdIsInProgress(TransactionId xid) } LWLockRelease(ProcArrayLock); - locked = false; /* * If none of the relevant caches overflowed, we know the Xid is not * running without looking at pg_subtrans. */ if (nxids == 0) - goto result_known; + return false; /* * Step 3: have to check pg_subtrans. @@ -422,7 +447,7 @@ TransactionIdIsInProgress(TransactionId xid) xc_slow_answer_inc(); if (TransactionIdDidAbort(xid)) - goto result_known; + return false; /* * It isn't aborted, so check whether the transaction tree it belongs to @@ -436,20 +461,11 @@ TransactionIdIsInProgress(TransactionId xid) for (i = 0; i < nxids; i++) { if (TransactionIdEquals(xids[i], topxid)) - { - result = true; - break; - } + return true; } } -result_known: - if (locked) - LWLockRelease(ProcArrayLock); - - pfree(xids); - - return result; + return false; } /* @@ -1284,8 +1300,9 @@ static void DisplayXidCache(void) { fprintf(stderr, - "XidCache: xmin: %ld, mainxid: %ld, childxid: %ld, slow: %ld\n", + "XidCache: xmin: %ld, myxact: %ld, mainxid: %ld, childxid: %ld, slow: %ld\n", xc_by_recent_xmin, + xc_by_my_xact, xc_by_main_xid, xc_by_child_xid, xc_slow_answer);