Interesting SQL Server Mirroring Problem

I have been trying to narrow down a SQL Server connection timeout problem, that only occurs when a database is mirrored. I have yet to be able to really figure out the cause, but here is the code that describes the problem.

[TestFixture]
public class SqlMirroringTests
{
    const string connectionString = "Data Source=some_server;Initial Catalog=some_db; User ID=*****;Password=*****;";
    private static Random rand = new Random();
 
    private ArrayList times = ArrayList.Synchronized(new ArrayList());
    private ArrayList erroredTimes = ArrayList.Synchronized(new ArrayList());
 
    private void DbScenario(int identifier)
    {
        var sleepTime = Random();
 
        WriteInfo(identifier, "Sleeping " + sleepTime + "ms");
        Thread.Sleep(sleepTime);
 
        using (var conn = new SqlConnection(connectionString))
        {
            var stopWatch = new Stopwatch();
            stopWatch.Start();
 
            bool isErrored = false;
            try
            {
                conn.Open();
            }
            catch(Exception e)
            {
                Console.WriteLine(e);
                isErrored = true;
                throw e;
            }
            finally
            {
                var timespan = stopWatch.Elapsed;
                WriteInfo(identifier, "Open time: " + timespan);
 
                times.Add(timespan);
 
                if (isErrored)
                {
                    erroredTimes.Add(timespan);
                }
            }
 
            //We have to actually query for something to get the error, and it needs to be a decent chunk of data
            var command = conn.CreateCommand();
            command.CommandText = "select * from <Insert any table here with some data>";
            command.ExecuteReader();
 
            conn.Close();
        }
        WriteInfo(identifier, "DONE");
    }
 
    [Test]
    public void SlamDatabase()
    {
        var exceptions = new List<Exception>();
        var action = new Action<int>(DbScenario);
 
        var results = Enumerable.Range(0, 250)
            .Select(i => action.BeginInvoke(i, null, null))
            .ToList();
 
        results.ForEach(ar => {
            try
            {
                action.EndInvoke(ar);
            }
            catch (Exception e)
            {
                exceptions.Add(e);
            }
        });
 
        Console.WriteLine("Number of Exceptions: " + exceptions.Count);
        WriteTimeResults("All times - ", times);
        WriteTimeResults("Error times - ", erroredTimes);
    }
 
    private void WriteTimeResults(string prefix, ArrayList results)
    {
        Console.WriteLine(prefix + "Max Open time: " + results.Cast<TimeSpan>().Max());
        Console.WriteLine(prefix + "Avg Open time: " + results.Cast<TimeSpan>().Average(t => t.TotalSeconds));
    }
 
    private int Random()
    {
        return rand.Next(1000);
    }
 
    private void WriteInfo(object state, string message)
    {
        Console.WriteLine("Thread " + state.ToString() + " - " + message);
    }
}

It throws two possible errors:

System.Data.SqlClient.SqlException: Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
   at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
   at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()
   at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject)
   at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject)
   at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
   at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()

And …

System.Data.SqlClient.SqlException: Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
   at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
   at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()

The odd thing is. Here are the results:

Number of Exceptions: 118
All times - Max Open time: 00:00:02.7301659
All times - Avg Open time: 0.0934956888
Error times - Max Open time: 00:00:02.7301659
Error times - Avg Open time: 0.0855163728813559

118 errors out of 250! After one happens, a ton of others happen. I am guessing the pool get’s jacked up and starts looking at the mirror to login temporarily or something, but I can’t figure out why. Increasing the Connect Timeout resolves the problem, but I HATE increasing timeouts. The funny thing is, according to my results, the average timed out connection is .08s. That 625x less than the connect timeout.

Finally, to make matters even more confusing, if you look at my connection string, I didn’t setup the connection for failover. Although I believe that failover still works, except on the initial connection.

Any ideas would be greatly appreciated.

Shipping Software – A response to Joel Spolsky

Joel recently posted The Duct Tape Programmer which has received an enormous amount of buzz, both positive and negative. At work, I received emails telling me that the article is a must read, while receiving different emails flaming Joel. If you haven’t read it, I highly encourage you to do so. In short, it is about shipping software above all else.

I have spent the evening catching up on blogs, many of which are just responses to Joel’s, so I felt I should jump on the bandwagon. Instead of writing only my own sentiments, I have included a couple other thoughts from different bloggers to help clarify everything.

Uncle Bob really helped clarify the sentiments of developers.

Now don’t get me wrong. I’m the “Clean Code” guy. I want your code clean. I don’t want you making a mess. On the other hand, I want you to ship. I don’t want you gilding the lilly. I don’t want you wrapped up in endless polishing.

I want you to ship, but I don’t want you to ship shit.

If you think I’m contradicting myself, you’re wrong. There is no contradiction in the notion that you must ship, and that you must be proud of what you ship.

The programmer who spends weeks building the perfect structure does just as much harm to the project as the programmer who hacks a bunch of crap together. Neither have struck the balance that’s required.

In short, it’s bad to use too much duct tape. But I’d be suspicious if I didn’t see some duct tape!

While Casey Charlton explains the disconnect between the business and the developer.

Developers and business owners are not aligned in their goals – we prioritise the three factors [time, scope, quality] very differently, and for different reasons.

Only two things can happen here, your developers need to align with their business objectives, or the business needs to align with the developers – or they can both compromise.

Agile is all about the compromise, making both sides aware of the issues involved, and then coming to an agreement, but fundamentally – it is STILL A BUSINESS DECISION.

While it is the responsibility of a professional developer to explain all the problems they see with low quality code, and to make their boss aware of all the potential future issues this may cause, it is also their professional responsibility to go with the decision their boss makes.

As for what I think, it is pretty simple. Shipping software and shipping quality software should be synonymous. It boils down to having great developers capable of great things. Writing tests that speed the team up, not down. Developing architectures that make sense now, not in 30 years. And finally, capable of releasing great software by the deadline.

Why you should use NHibernate.Linq, not Criteria or HQL

What’s wrong with the following?

return s.CreateQuery("from CodeCamp c where c.Name = :name order by c.Name")
    .SetParameter("name", "test")
    .List<CodeCamp>();
return s.CreateCriteria<CodeCamp>()
    .Add(Expression.Eq("Name", "test"))
    .AddOrder(Order.Asc("Name"))
    .List<CodeCamp>();

There are string references to .NET properties. That is a no-no. If there is a typo, you get runtime errors and not compile time errors. Now, good tests would catch it, but if you want the absolute fastest way to catch typos, NHibernate.Linq is the way to go.

return (from camp in s.Linq<CodeCamp>()
          where camp.Name == "test"
          orderby camp.Name
          select camp).ToList();

With Linq, you get that compile time checking that is going to help you move a little bit faster and make your code more robust. Combine this with Fluent NHibernate and you have a solid solution. Your mappings still have to be correct of course, but these projects take two variables out of the equation and use the compiler as a safety blanket.

Powershell script to Register Visual Studio Schemas

I always have to Google how to add an XML schema to Visual Studio because I forget the directory (even though it is super easy). Never again will I forget.

function register-vsschemas()
{
	begin
	{
		$schema_folders = gci $env:ProgramFiles -Filter "Microsoft Visual Studio*" | 
							gci -Filter "Xml" | 
							gci -Filter "Schemas"
	}
 
	process
	{
		if(!$_ -or !(Test-Path $_))
		{
			Write-Error "File '$_' not found"
			break;
		}
		if((gi $_).Extension -ine ".xsd")
		{
			Write-Warning "File $_ does not end in an .xsd extension"
		}
 
		foreach($folder in $schema_folders){
			#It is very interesting I had to use .FullName...
			cp $_ $folder.FullName -Verbose
		}
	}
}

Call it as follows:

gi .\lib\NHibernate\*.xsd | register-vsschemas

Visual Studio Tip: Show All Files

I discovered a Visual Studio feature that I probably should have noticed years ago. It is pretty awesome, and right in front of your face. Show All Files

9-13-2009 8-36-34 PM

Just click the icon in the Solution Window highlighted in the above screenshot.

9-13-2009 8-40-15 PM

Bam, all files in the directories get shown, even if they aren’t part of the project. Pretty awesome, especially because of the Include in Project functionality. Much quicker to add items to a project than Add Existing Items.