]> granicus.if.org Git - postgresql/commitdiff
More deadlock code to check for escallation locks.
authorBruce Momjian <bruce@momjian.us>
Wed, 28 Jan 1998 02:29:40 +0000 (02:29 +0000)
committerBruce Momjian <bruce@momjian.us>
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 <sys/time.h>
 #include <unistd.h>
@@ -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
  */