diff options
Diffstat (limited to 'src/backend/storage/lmgr/proc.c')
-rw-r--r-- | src/backend/storage/lmgr/proc.c | 107 |
1 files changed, 63 insertions, 44 deletions
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index d32ae45c6be..b8831f68c40 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.184 2007/02/15 23:23:23 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.185 2007/03/03 18:46:40 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -48,6 +48,7 @@ /* GUC variables */ int DeadlockTimeout = 1000; int StatementTimeout = 0; +bool log_lock_waits = false; /* Pointer to this process's PGPROC struct, if any */ PGPROC *MyProc = NULL; @@ -979,6 +980,7 @@ static void CheckDeadLock(void) { int i; + DeadlockState deadlock_state = DS_DEADLOCK_NOT_FOUND; /* * Acquire exclusive lock on the entire shared lock data structures. Must @@ -1004,60 +1006,77 @@ CheckDeadLock(void) * This is quicker than checking our semaphore's state, since no kernel * call is needed, and it is safe because we hold the lock partition lock. */ - if (MyProc->links.prev == INVALID_OFFSET || - MyProc->links.next == INVALID_OFFSET) - goto check_done; - -#ifdef LOCK_DEBUG - if (Debug_deadlocks) - DumpAllLocks(); -#endif - - if (!DeadLockCheck(MyProc)) + if (MyProc->links.prev != INVALID_OFFSET && + MyProc->links.next != INVALID_OFFSET) + deadlock_state = DeadLockCheck(MyProc); + + if (deadlock_state == DS_HARD_DEADLOCK) { - /* No deadlock, so keep waiting */ - goto check_done; - } - - /* - * Oops. We have a deadlock. - * - * Get this process out of wait state. (Note: we could do this more - * efficiently by relying on lockAwaited, but use this coding to preserve - * the flexibility to kill some other transaction than the one detecting - * the deadlock.) - * - * RemoveFromWaitQueue sets MyProc->waitStatus to STATUS_ERROR, so - * ProcSleep will report an error after we return from the signal handler. - */ - Assert(MyProc->waitLock != NULL); - RemoveFromWaitQueue(MyProc, LockTagHashCode(&(MyProc->waitLock->tag))); + /* + * Oops. We have a deadlock. + * + * Get this process out of wait state. (Note: we could do this more + * efficiently by relying on lockAwaited, but use this coding to preserve + * the flexibility to kill some other transaction than the one detecting + * the deadlock.) + * + * RemoveFromWaitQueue sets MyProc->waitStatus to STATUS_ERROR, so + * ProcSleep will report an error after we return from the signal handler. + */ + Assert(MyProc->waitLock != NULL); + RemoveFromWaitQueue(MyProc, LockTagHashCode(&(MyProc->waitLock->tag))); - /* - * Unlock my semaphore so that the interrupted ProcSleep() call can - * finish. - */ - PGSemaphoreUnlock(&MyProc->sem); + /* + * Unlock my semaphore so that the interrupted ProcSleep() call can + * finish. + */ + PGSemaphoreUnlock(&MyProc->sem); - /* - * We're done here. Transaction abort caused by the error that ProcSleep - * will raise will cause any other locks we hold to be released, thus - * allowing other processes to wake up; we don't need to do that here. - * NOTE: an exception is that releasing locks we hold doesn't consider the - * possibility of waiters that were blocked behind us on the lock we just - * failed to get, and might now be wakable because we're not in front of - * them anymore. However, RemoveFromWaitQueue took care of waking up any - * such processes. - */ + /* + * We're done here. Transaction abort caused by the error that ProcSleep + * will raise will cause any other locks we hold to be released, thus + * allowing other processes to wake up; we don't need to do that here. + * NOTE: an exception is that releasing locks we hold doesn't consider the + * possibility of waiters that were blocked behind us on the lock we just + * failed to get, and might now be wakable because we're not in front of + * them anymore. However, RemoveFromWaitQueue took care of waking up any + * such processes. + */ + } /* * Release locks acquired at head of routine. Order is not critical, so * do it back-to-front to avoid waking another CheckDeadLock instance * before it can get all the locks. */ -check_done: for (i = NUM_LOCK_PARTITIONS; --i >= 0;) LWLockRelease(FirstLockMgrLock + i); + + /* + * Issue any log messages requested. + * + * Deadlock ERROR messages are issued as part of transaction abort, so + * these messages should not raise error states intentionally. + */ + if (log_lock_waits) + { + switch (deadlock_state) + { + case DS_SOFT_DEADLOCK: + ereport(LOG, + (errmsg("deadlock avoided by rearranging lock order"))); + break; + case DS_DEADLOCK_NOT_FOUND: + ereport(LOG, + (errmsg("statement waiting for lock for at least %d ms", + DeadlockTimeout))); + break; + case DS_HARD_DEADLOCK: + break; /* ERROR message handled during abort */ + default: + break; + } + } } |