Commit 8abd4243 authored by Bruce Momjian's avatar Bruce Momjian

More deadlock code to check for escallation locks.

offsetof() addition to local socket size.
parent 54399bb2
$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 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 time and a lot of headaches. The existing lock manager code at the time
...@@ -88,6 +88,12 @@ activeHolders - ...@@ -88,6 +88,12 @@ activeHolders -
holders, summing the values of activeHolders should total to the value holders, summing the values of activeHolders should total to the value
of nActive. of nActive.
---------------------------------------------------------------------------
This is all I had the stomach for right now..... I will get back to this Locks are accessed in two ways. Each PROC structure has a lockQueue,
someday. -mer 17 June 1992 12:00 am 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.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Outside modules can create a lock table and acquire/release * Outside modules can create a lock table and acquire/release
...@@ -755,7 +755,7 @@ LockResolveConflicts(LOCKTAB *ltable, ...@@ -755,7 +755,7 @@ LockResolveConflicts(LOCKTAB *ltable,
tmpMask = 2; tmpMask = 2;
for (i = 1; i <= nLockTypes; i++, tmpMask <<= 1) for (i = 1; i <= nLockTypes; i++, tmpMask <<= 1)
{ {
if (lock->activeHolders[i] - myHolders[i]) if (lock->activeHolders[i] != myHolders[i])
{ {
bitmask |= tmpMask; bitmask |= tmpMask;
} }
...@@ -1429,14 +1429,38 @@ DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check) ...@@ -1429,14 +1429,38 @@ DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check)
XIDLookupEnt *tmp = NULL; XIDLookupEnt *tmp = NULL;
SHMEM_OFFSET end = MAKE_OFFSET(lockQueue); SHMEM_OFFSET end = MAKE_OFFSET(lockQueue);
LOCK *lock; 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) if (skip_check)
{ {
/* initialize at start of recursion */
checked_procs[0] = MyProc; checked_procs[0] = MyProc;
nprocs = 1; 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)) if (SHMQueueEmpty(lockQueue))
...@@ -1469,13 +1493,7 @@ DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check) ...@@ -1469,13 +1493,7 @@ DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check)
if (lock == findlock && !skip_check) if (lock == findlock && !skip_check)
return true; 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_QUEUE *waitQueue = &(lock->waitProcs);
PROC *proc; PROC *proc;
int i; int i;
...@@ -1484,16 +1502,70 @@ DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check) ...@@ -1484,16 +1502,70 @@ DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check)
proc = (PROC *) MAKE_PTR(waitQueue->links.prev); proc = (PROC *) MAKE_PTR(waitQueue->links.prev);
for (i = 0; i < waitQueue->size; i++) for (i = 0; i < waitQueue->size; i++)
{ {
for (j = 0; j < nprocs; j++) if (proc != MyProc &&
if (checked_procs[j] == proc) lock == findlock && /* skip_check also true */
break; MyNHolding) /* I already hold some lock on it */
if (j >= nprocs) {
/*
* 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; for (j = 0; j < nprocs; j++)
Assert(nprocs <= MaxBackendId); if (checked_procs[j] == proc)
/* If we found a deadlock, we can stop right now */ break;
if (DeadLockCheck(&(proc->lockQueue), findlock, false)) if (j >= nprocs && lock != findlock)
return true; {
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); proc = (PROC *) MAKE_PTR(proc->links.prev);
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -46,7 +46,7 @@
* This is so that we can support more backends. (system-wide semaphore * This is so that we can support more backends. (system-wide semaphore
* sets run out pretty fast.) -ay 4/95 * 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 <sys/time.h>
#include <unistd.h> #include <unistd.h>
...@@ -249,7 +249,10 @@ InitProcess(IPCKey key) ...@@ -249,7 +249,10 @@ InitProcess(IPCKey key)
*/ */
SpinRelease(ProcStructLock); SpinRelease(ProcStructLock);
MyProc->pid = 0;
#if 0
MyProc->pid = MyProcPid; MyProc->pid = MyProcPid;
#endif
MyProc->xid = InvalidTransactionId; MyProc->xid = InvalidTransactionId;
/* ---------------- /* ----------------
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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 { ...@@ -35,10 +35,10 @@ typedef union SockAddr {
#define UNIXSOCK_PATH(sun,port) \ #define UNIXSOCK_PATH(sun,port) \
(sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (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 do this because sun_len is in BSD's struct, while others don't.
* We never actually set sun_len, and I can't think of a * 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 * platform-safe way of doing it, but the code still works. bjm
*/ */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment