diff --git a/src/backend/storage/lmgr/README b/src/backend/storage/lmgr/README index e382003f2a..821f4a3745 100644 --- a/src/backend/storage/lmgr/README +++ b/src/backend/storage/lmgr/README @@ -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. diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index a509050704..e218a40342 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -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 */ { - 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 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) + { + 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); } diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 893ea41833..1ab096ac52 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -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; /* ---------------- diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h index b3b67f8b73..0145f26270 100644 --- a/src/include/libpq/pqcomm.h +++ b/src/include/libpq/pqcomm.h @@ -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 */