Make some simple performance improvements in TransactionIdIsInProgress().
authorTom Lane
Fri, 21 Sep 2007 17:36:53 +0000 (17:36 +0000)
committerTom Lane
Fri, 21 Sep 2007 17:36:53 +0000 (17:36 +0000)
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

index 0565510c31b8676a9d8018b5fe45e1595e6ab859..dbac4a8fd05de662eda005deb1a8bffc98253c3c 100644 (file)
@@ -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);