88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.184 2007/02/15 23:23:23 alvherre Exp $
11+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.185 2007/03/03 18:46:40 momjian Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
4848/* GUC variables */
4949int DeadlockTimeout = 1000 ;
5050int StatementTimeout = 0 ;
51+ bool log_lock_waits = false;
5152
5253/* Pointer to this process's PGPROC struct, if any */
5354PGPROC * MyProc = NULL ;
@@ -979,6 +980,7 @@ static void
979980CheckDeadLock (void )
980981{
981982 int i ;
983+ DeadlockState deadlock_state = DS_DEADLOCK_NOT_FOUND ;
982984
983985 /*
984986 * Acquire exclusive lock on the entire shared lock data structures. Must
@@ -1004,60 +1006,77 @@ CheckDeadLock(void)
10041006 * This is quicker than checking our semaphore's state, since no kernel
10051007 * call is needed, and it is safe because we hold the lock partition lock.
10061008 */
1007- if (MyProc -> links .prev == INVALID_OFFSET ||
1008- MyProc -> links .next == INVALID_OFFSET )
1009- goto check_done ;
1010-
1011- #ifdef LOCK_DEBUG
1012- if (Debug_deadlocks )
1013- DumpAllLocks ();
1014- #endif
1015-
1016- if (!DeadLockCheck (MyProc ))
1009+ if (MyProc -> links .prev != INVALID_OFFSET &&
1010+ MyProc -> links .next != INVALID_OFFSET )
1011+ deadlock_state = DeadLockCheck (MyProc );
1012+
1013+ if (deadlock_state == DS_HARD_DEADLOCK )
10171014 {
1018- /* No deadlock, so keep waiting */
1019- goto check_done ;
1020- }
1021-
1022- /*
1023- * Oops. We have a deadlock.
1024- *
1025- * Get this process out of wait state. (Note: we could do this more
1026- * efficiently by relying on lockAwaited, but use this coding to preserve
1027- * the flexibility to kill some other transaction than the one detecting
1028- * the deadlock.)
1029- *
1030- * RemoveFromWaitQueue sets MyProc->waitStatus to STATUS_ERROR, so
1031- * ProcSleep will report an error after we return from the signal handler.
1032- */
1033- Assert (MyProc -> waitLock != NULL );
1034- RemoveFromWaitQueue (MyProc , LockTagHashCode (& (MyProc -> waitLock -> tag )));
1015+ /*
1016+ * Oops. We have a deadlock.
1017+ *
1018+ * Get this process out of wait state. (Note: we could do this more
1019+ * efficiently by relying on lockAwaited, but use this coding to preserve
1020+ * the flexibility to kill some other transaction than the one detecting
1021+ * the deadlock.)
1022+ *
1023+ * RemoveFromWaitQueue sets MyProc->waitStatus to STATUS_ERROR, so
1024+ * ProcSleep will report an error after we return from the signal handler.
1025+ */
1026+ Assert (MyProc -> waitLock != NULL );
1027+ RemoveFromWaitQueue (MyProc , LockTagHashCode (& (MyProc -> waitLock -> tag )));
10351028
1036- /*
1037- * Unlock my semaphore so that the interrupted ProcSleep() call can
1038- * finish.
1039- */
1040- PGSemaphoreUnlock (& MyProc -> sem );
1029+ /*
1030+ * Unlock my semaphore so that the interrupted ProcSleep() call can
1031+ * finish.
1032+ */
1033+ PGSemaphoreUnlock (& MyProc -> sem );
10411034
1042- /*
1043- * We're done here. Transaction abort caused by the error that ProcSleep
1044- * will raise will cause any other locks we hold to be released, thus
1045- * allowing other processes to wake up; we don't need to do that here.
1046- * NOTE: an exception is that releasing locks we hold doesn't consider the
1047- * possibility of waiters that were blocked behind us on the lock we just
1048- * failed to get, and might now be wakable because we're not in front of
1049- * them anymore. However, RemoveFromWaitQueue took care of waking up any
1050- * such processes.
1051- */
1035+ /*
1036+ * We're done here. Transaction abort caused by the error that ProcSleep
1037+ * will raise will cause any other locks we hold to be released, thus
1038+ * allowing other processes to wake up; we don't need to do that here.
1039+ * NOTE: an exception is that releasing locks we hold doesn't consider the
1040+ * possibility of waiters that were blocked behind us on the lock we just
1041+ * failed to get, and might now be wakable because we're not in front of
1042+ * them anymore. However, RemoveFromWaitQueue took care of waking up any
1043+ * such processes.
1044+ */
1045+ }
10521046
10531047 /*
10541048 * Release locks acquired at head of routine. Order is not critical, so
10551049 * do it back-to-front to avoid waking another CheckDeadLock instance
10561050 * before it can get all the locks.
10571051 */
1058- check_done :
10591052 for (i = NUM_LOCK_PARTITIONS ; -- i >= 0 ;)
10601053 LWLockRelease (FirstLockMgrLock + i );
1054+
1055+ /*
1056+ * Issue any log messages requested.
1057+ *
1058+ * Deadlock ERROR messages are issued as part of transaction abort, so
1059+ * these messages should not raise error states intentionally.
1060+ */
1061+ if (log_lock_waits )
1062+ {
1063+ switch (deadlock_state )
1064+ {
1065+ case DS_SOFT_DEADLOCK :
1066+ ereport (LOG ,
1067+ (errmsg ("deadlock avoided by rearranging lock order" )));
1068+ break ;
1069+ case DS_DEADLOCK_NOT_FOUND :
1070+ ereport (LOG ,
1071+ (errmsg ("statement waiting for lock for at least %d ms" ,
1072+ DeadlockTimeout )));
1073+ break ;
1074+ case DS_HARD_DEADLOCK :
1075+ break ; /* ERROR message handled during abort */
1076+ default :
1077+ break ;
1078+ }
1079+ }
10611080}
10621081
10631082
0 commit comments