Created
June 16, 2015 09:12
-
-
Save AlastairTaft/d28b79e6523fe817be82 to your computer and use it in GitHub Desktop.
A console application to break safe threads with bad threads using SqlConnection objects
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Data.SqlClient; | |
using System.Linq; | |
using System.Text; | |
using System.Threading; | |
namespace ThreadCorruptionTest | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
int threadCount = 100; | |
for (int i = 1; i <= threadCount; i++) | |
{ | |
new Thread(new ThreadStart(Program.WorkerThread)).Start(); | |
} | |
} | |
static int tidCounter = 0; | |
static UInt32 value = 0; | |
static SqlConnection globalConn = null; | |
static SqlConnection GetConn(string connect, bool useGlobalConn) | |
{ | |
SqlConnection connLocal = null; | |
if (useGlobalConn) | |
{ | |
connLocal = globalConn; | |
if (null == connLocal) | |
{ | |
connLocal = new SqlConnection(connect); | |
connLocal.Open(); | |
globalConn = connLocal; | |
return connLocal; | |
} | |
else | |
{ | |
return connLocal; | |
} | |
} | |
else | |
{ | |
connLocal = new SqlConnection(connect); | |
connLocal.Open(); | |
return connLocal; | |
} | |
} | |
static object consoleLock = new object(); | |
static void WorkerThread() | |
{ | |
int tid = Interlocked.Increment(ref tidCounter); | |
string select = string.Format("select {0} as [f{1}]", tid, tid); | |
string fieldName = string.Format("f{0}", tid); | |
string connect = "server=(local);user id=XXXXX;password=XXXXX;"; | |
int readCount = 0; | |
bool useGlobalConnThread = (0 == (tid % 5)); | |
SqlConnection conn = null; | |
SqlCommand cmd = null; | |
SqlDataReader dr = null; | |
for (; ; ) | |
{ | |
try | |
{ | |
conn = GetConn(connect, useGlobalConnThread); | |
cmd = conn.CreateCommand(); | |
cmd.CommandText = select; | |
cmd.CommandTimeout = 5; | |
dr = cmd.ExecuteReader(); | |
dr.Read(); | |
int fieldValue = (int)dr[fieldName]; | |
System.Diagnostics.Debug.Assert(fieldValue == tid); | |
readCount++; | |
if (0 == (readCount % 2500)) | |
{ | |
Console.WriteLine("Thread{0} reads{1}", tid, readCount); | |
} | |
} | |
catch (IndexOutOfRangeException iorEx) | |
{ | |
lock (consoleLock) | |
{ | |
Console.WriteLine("Caught targeted exception IndexOutOfRangeException:"); | |
Console.WriteLine("expected -> {0}", fieldName); | |
Console.WriteLine("actual -> {0}", dr.GetName(0)); | |
if (useGlobalConnThread) | |
{ | |
Console.WriteLine("Ok, I'm a bad thread and I'm sharing SqlConnections, I know this is going to happen."); | |
} | |
else | |
{ | |
Console.WriteLine("Hey, I'm a safe thread and just a victim!"); | |
System.Diagnostics.Debug.Assert(false); | |
} | |
} | |
} | |
catch (Exception ex) | |
{ | |
lock (consoleLock) | |
{ | |
Console.WriteLine(ex.Message); | |
if (useGlobalConnThread) | |
{ | |
Console.WriteLine("Ok, I'm a bad thread and I'm sharing SqlConnections, I know this is going to happen."); | |
} | |
else | |
{ | |
Console.WriteLine("Hey, I'm a safe thread and just a victim!"); | |
} | |
// Reset globalConn on failure. | |
SqlConnection connLocal = GetConn(connect, false); | |
SqlConnection connToClose = globalConn; | |
globalConn = connLocal; | |
try { connToClose.Close(); } | |
catch (Exception) { }; | |
} | |
} | |
finally | |
{ | |
if (!useGlobalConnThread) | |
{ | |
if (null != conn) conn.Close(); | |
} | |
if (null != cmd) cmd.Dispose(); | |
if (null != dr) dr.Close(); | |
conn = null; | |
cmd = null; | |
dr = null; | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment