8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
48
48
/* GUC variables */
49
49
int DeadlockTimeout = 1000 ;
50
50
int StatementTimeout = 0 ;
51
+ bool log_lock_waits = false;
51
52
52
53
/* Pointer to this process's PGPROC struct, if any */
53
54
PGPROC * MyProc = NULL ;
@@ -979,6 +980,7 @@ static void
979
980
CheckDeadLock (void )
980
981
{
981
982
int i ;
983
+ DeadlockState deadlock_state = DS_DEADLOCK_NOT_FOUND ;
982
984
983
985
/*
984
986
* Acquire exclusive lock on the entire shared lock data structures. Must
@@ -1004,60 +1006,77 @@ CheckDeadLock(void)
1004
1006
* This is quicker than checking our semaphore's state, since no kernel
1005
1007
* call is needed, and it is safe because we hold the lock partition lock.
1006
1008
*/
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 )
1017
1014
{
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 )));
1035
1028
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 );
1041
1034
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
+ }
1052
1046
1053
1047
/*
1054
1048
* Release locks acquired at head of routine. Order is not critical, so
1055
1049
* do it back-to-front to avoid waking another CheckDeadLock instance
1056
1050
* before it can get all the locks.
1057
1051
*/
1058
- check_done :
1059
1052
for (i = NUM_LOCK_PARTITIONS ; -- i >= 0 ;)
1060
1053
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
+ }
1061
1080
}
1062
1081
1063
1082
0 commit comments