More deadlock code to check for escallation locks.
authorBruce Momjian
Wed, 28 Jan 1998 02:29:40 +0000 (02:29 +0000)
committerBruce Momjian
Wed, 28 Jan 1998 02:29:40 +0000 (02:29 +0000)
offsetof() addition to local socket size.

src/backend/storage/lmgr/README
src/backend/storage/lmgr/lock.c
src/backend/storage/lmgr/proc.c
src/include/libpq/pqcomm.h

index e382003f2a429e602b11dc0e46bd8d2763e79405..821f4a3745107fce03da2f132547b6576ea5df33 100644 (file)
@@ -1,4 +1,4 @@
-$Header: /cvsroot/pgsql/src/backend/storage/lmgr/README,v 1.1.1.1 1996/07/09 06:21:55 scrappy Exp $
+$Header: /cvsroot/pgsql/src/backend/storage/lmgr/README,v 1.2 1998/01/28 02:29:26 momjian Exp $
 
 This file is an attempt to save me (and future code maintainers) some
 time and a lot of headaches.  The existing lock manager code at the time
@@ -88,6 +88,12 @@ activeHolders -
     holders, summing the values of activeHolders should total to the value
     of nActive.
 
+---------------------------------------------------------------------------
 
-This is all I had the stomach for right now..... I will get back to this
-someday.   -mer 17 June 1992 12:00 am
+Locks are accessed in two ways.  Each PROC structure has a lockQueue,
+that is a circular linked list of LOCK pointers that this process holds
+or is waiting on.
+
+Second, there is a hash table that can do a lookup by combined LOCK
+address and transaction id(xid) which allows a process to see what
+type of locks it holds on that table.
index a509050704a46ec7cc60d62b4fe7a11b2c01524f..e218a4034257131a1946d6a5fe5499e9ca65bddd 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.23 1998/01/27 15:34:49 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.24 1998/01/28 02:29:27 momjian Exp $
  *
  * NOTES
  *   Outside modules can create a lock table and acquire/release
@@ -755,7 +755,7 @@ LockResolveConflicts(LOCKTAB *ltable,
    tmpMask = 2;
    for (i = 1; i <= nLockTypes; i++, tmpMask <<= 1)
    {
-       if (lock->activeHolders[i] - myHolders[i])
+       if (lock->activeHolders[i] != myHolders[i])
        {
            bitmask |= tmpMask;
        }
@@ -1429,14 +1429,38 @@ DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check)
    XIDLookupEnt *tmp = NULL;
    SHMEM_OFFSET end = MAKE_OFFSET(lockQueue);
    LOCK       *lock;
-   static PROC*    checked_procs[MaxBackendId];
-   static int  nprocs;
 
+   LOCKTAB *ltable;
+   XIDLookupEnt *result,
+               item;
+   HTAB       *xidTable;
+   bool        found;
+
+   static PROC*    checked_procs[MaxBackendId];
+   static int      nprocs;
+   static bool     MyNHolding;
+   
+   /* initialize at start of recursion */
    if (skip_check)
    {
-       /* initialize at start of recursion */
        checked_procs[0] = MyProc;
        nprocs = 1;
+
+       ltable = AllTables[1];
+       xidTable = ltable->xidHash;
+
+       MemSet(&item, 0, XID_TAGSIZE);
+       TransactionIdStore(MyProc->xid, &item.tag.xid);
+       item.tag.lock = MAKE_OFFSET(findlock);
+#if 0
+       item.tag.pid = pid;
+#endif
+   
+       if ((result = (XIDLookupEnt *)
+             hash_search(xidTable, (Pointer) &item, HASH_FIND, &found)) && found)
+           MyNHolding = result->nHolding;
+       else
+           MyNHolding = 0;
    }
    
    if (SHMQueueEmpty(lockQueue))
@@ -1469,13 +1493,7 @@ DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check)
        if (lock == findlock && !skip_check)
            return true;
 
-       /*
-        *  No sense in looking at the wait queue of the lock we are
-        *  looking for as it is MyProc's lock entry.
-        *  If lock == findlock, and I got here, skip_check must be true.
-        */
-       if (lock != findlock)
-       {
+        {
            PROC_QUEUE  *waitQueue = &(lock->waitProcs);
            PROC        *proc;
            int         i;
@@ -1484,16 +1502,70 @@ DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check)
            proc = (PROC *) MAKE_PTR(waitQueue->links.prev);
            for (i = 0; i < waitQueue->size; i++)
            {
-               for (j = 0; j < nprocs; j++)
-                   if (checked_procs[j] == proc)
-                       break;
-               if (j >= nprocs)
+               if (proc != MyProc &&
+                   lock == findlock && /* skip_check also true */
+                   MyNHolding) /* I already hold some lock on it */
+               {
+                   /*
+                    *  For findlock's wait queue, we are interested in
+                    *  procs who are blocked waiting for a write-lock on the
+                    *  table we are waiting on, and already hold a lock on it.
+                    *  We first check to see if there is an escalation
+                    *  deadlock, where we hold a readlock and want a
+                    *  writelock, and someone else holds readlock on
+                    *  the same table, and wants a writelock.
+                    *
+                    *  Basically, the test is, "Do we both hold some lock
+                    *  on findlock, and we are both waiting in the lock
+                    *  queue?"
+                    */
+
+                   Assert(skip_check);
+                   Assert(MyProc->prio == 2);
+                   
+                   ltable = AllTables[1];
+                   xidTable = ltable->xidHash;
+
+                   MemSet(&item, 0, XID_TAGSIZE);
+                   TransactionIdStore(proc->xid, &item.tag.xid);
+                   item.tag.lock = MAKE_OFFSET(findlock);
+#if 0
+                   item.tag.pid = pid;
+#endif
+               
+                   if ((result = (XIDLookupEnt *)
+                         hash_search(xidTable, (Pointer) &item, HASH_FIND, &found)) && found)
+                   {
+                       if (result->nHolding)
+                               return true;
+                   }
+               }
+               /*
+                *  No sense in looking at the wait queue of the lock we are
+                *  looking for.
+                *  If lock == findlock, and I got here, skip_check must be
+                *  true too.
+                */
+               if (lock != findlock)
                {
-                   checked_procs[nprocs++] = proc;
-                   Assert(nprocs <= MaxBackendId);
-                   /* If we found a deadlock, we can stop right now */
-                   if (DeadLockCheck(&(proc->lockQueue), findlock, false))
-                       return true;
+                   for (j = 0; j < nprocs; j++)
+                       if (checked_procs[j] == proc)
+                           break;
+                   if (j >= nprocs && lock != findlock)
+                   {
+                       checked_procs[nprocs++] = proc;
+                       Assert(nprocs <= MaxBackendId);
+                       /*
+                        *  For non-MyProc entries, we are looking only waiters,
+                        *  not necessarily people who already hold locks and are
+                        *  waiting.
+                        *  Now we check for cases where we have two or more
+                        *  tables in a deadlock.  We do this by continuing
+                        *  to search for someone holding a lock
+                        */
+                       if (DeadLockCheck(&(proc->lockQueue), findlock, false))
+                           return true;
+                   }
                }
                proc = (PROC *) MAKE_PTR(proc->links.prev);
            }
index 893ea41833d95b56db22ca68e15fede97a011838..1ab096ac527b4b07a31fcffd82839f24f8408d43 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.29 1998/01/27 03:00:29 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.30 1998/01/28 02:29:29 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,7 +46,7 @@
  *     This is so that we can support more backends. (system-wide semaphore
  *     sets run out pretty fast.)                -ay 4/95
  *
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.29 1998/01/27 03:00:29 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.30 1998/01/28 02:29:29 momjian Exp $
  */
 #include 
 #include 
@@ -249,7 +249,10 @@ InitProcess(IPCKey key)
     */
    SpinRelease(ProcStructLock);
 
+   MyProc->pid = 0;
+#if 0
    MyProc->pid = MyProcPid;
+#endif
    MyProc->xid = InvalidTransactionId;
 
    /* ----------------
index b3b67f8b73b10462d120936df20e10e983316540..0145f262702380578e5e15250de89ee510c67ed0 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pqcomm.h,v 1.21 1998/01/27 15:35:22 momjian Exp $
+ * $Id: pqcomm.h,v 1.22 1998/01/28 02:29:40 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,10 +35,10 @@ typedef union SockAddr {
 
 #define    UNIXSOCK_PATH(sun,port) \
    (sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)) + \
-       + 1 + sizeof ((sun).sun_family))
+       offsetof(struct sockaddr_un, sun_path))
 /*
- *     + 1 is for BSD-specific sizeof((sun).sun_len)
- *     We never actually set sun_len, and I can't think of a
+ *     We do this because sun_len is in BSD's struct, while others don't.
+ *     We never actually set BSD's sun_len, and I can't think of a
  *     platform-safe way of doing it, but the code still works. bjm
  */