Skip to content

Instantly share code, notes, and snippets.

@EtherZa
Created May 23, 2017 14:04
Show Gist options
  • Save EtherZa/6cfccfc54d4983cc8d8f2f007b5231b5 to your computer and use it in GitHub Desktop.
Save EtherZa/6cfccfc54d4983cc8d8f2f007b5231b5 to your computer and use it in GitHub Desktop.
/*
This script helps simulate deadlocks. Run the entire script in a SQL query window. It will continue running until stopped.
In the target script, insert a call to sp_simulatedeadlock where you want the deadlock to occur.
This stored procedure, also created below, causes the deadlock.
When you are done, stop the execution of this window and run the code in the cleanup section at the bottom.
*/
SET NOCOUNT ON
IF OBJECT_ID('DeadlockTest') IS NOT NULL
DROP TABLE DeadlockTest
CREATE TABLE DeadlockTest
(
Deadlock_Key INT PRIMARY KEY CLUSTERED ,
Deadlock_Count INT
)
GO
IF EXISTS ( SELECT *
FROM sys.sysobjects
WHERE id = OBJECT_ID(N'sp_simulatedeadlock')
AND OBJECTPROPERTY(id, N'IsProcedure') = 1
)
DROP PROCEDURE sp_simulatedeadlock
GO
CREATE PROCEDURE sp_simulatedeadlock
(
@MaxDeadlocks INT = -1 -- specify the number of deadlocks you want; -1 = constant deadlocking
)
AS
BEGIN
SET NOCOUNT ON
IF OBJECT_ID('DeadlockTest') IS NULL
RETURN
-- Volunteer to be a deadlock victim.
SET DEADLOCK_PRIORITY LOW
DECLARE @DeadlockCount INT
SELECT @DeadlockCount = Deadlock_Count -- this starts at 0
FROM DeadlockTest
WHERE Deadlock_Key = 2
-- Trace the start of each deadlock event.
-- To listen to the trace event, setup a SQL Server Profiler trace with event class "UserConfigurable:0".
-- Note that the user running this proc must have ALTER TRACE permission.
-- Also note that there are only 128 characters allowed in the trace text.
DECLARE @trace NVARCHAR(128)
IF @MaxDeadlocks > 0
AND @DeadlockCount > @MaxDeadlocks
BEGIN
SET @trace = N'Deadlock Test @MaxDeadlocks: '
+ CAST(@MaxDeadlocks AS NVARCHAR)
+ N' @DeadlockCount: '
+ CAST(@DeadlockCount AS NVARCHAR)
+ N' Resetting deadlock count. Will not cause deadlock.'
EXEC sys.sp_trace_generateevent @eventid = 82 , -- 82 = UserConfigurable:0 through 91 = UserConfigurable:9
@userinfo = @trace
-- Reset the number of deadlocks.
-- Hopefully if there is an outer transaction, it will complete and persist this change.
UPDATE DeadlockTest
SET Deadlock_Count = 0
WHERE Deadlock_Key = 2
RETURN
END
SET @trace = N'Deadlock Test @MaxDeadlocks: '
+ CAST(@MaxDeadlocks AS NVARCHAR) + N' @DeadlockCount: '
+ CAST(@DeadlockCount AS NVARCHAR)
+ N' Simulating deadlock.'
EXEC sys.sp_trace_generateevent @eventid = 82 , -- 82 = UserConfigurable:0 through 91 = UserConfigurable:9
@userinfo = @trace
DECLARE @StartedTransaction BIT
SET @StartedTransaction = 0
IF @@trancount = 0
BEGIN
SET @StartedTransaction = 1
BEGIN TRANSACTION
END
-- lock 2nd record
UPDATE DeadlockTest
SET Deadlock_Count = Deadlock_Count
FROM DeadlockTest
WHERE Deadlock_Key = 2
-- lock 1st record to cause deadlock
UPDATE DeadlockTest
SET Deadlock_Count = Deadlock_Count
FROM DeadlockTest
WHERE Deadlock_Key = 1
IF @StartedTransaction = 1
ROLLBACK
END
GO
INSERT INTO DeadlockTest ( Deadlock_Key ,
Deadlock_Count
)
SELECT 1 ,
0
UNION
SELECT 2 ,
0
-- Force other processes to be the deadlock victim.
SET DEADLOCK_PRIORITY HIGH
BEGIN TRANSACTION
WHILE 1 = 1
BEGIN
BEGIN TRY
BEGIN TRANSACTION
-- lock 1st record
UPDATE DeadlockTest
SET Deadlock_Count = Deadlock_Count
FROM DeadlockTest
WHERE Deadlock_Key = 1
WAITFOR DELAY '00:00:10'
-- lock 2nd record (which will be locked when the target proc calls sp_simulatedeadlock)
UPDATE DeadlockTest
SET Deadlock_Count = Deadlock_Count
FROM DeadlockTest
WHERE Deadlock_Key = 2
ROLLBACK
END TRY
BEGIN CATCH
PRINT 'Error ' + CONVERT(VARCHAR(20), ERROR_NUMBER()) + ': '
+ ERROR_MESSAGE()
GOTO cleanup
END CATCH
END
cleanup:
IF @@trancount > 0
ROLLBACK
DROP PROCEDURE sp_simulatedeadlock
DROP TABLE DeadlockTest
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment