Skip to content

Commit

Permalink
Added concurrency test for multiplexing
Browse files Browse the repository at this point in the history
  • Loading branch information
madelson committed Feb 3, 2017
1 parent 864697d commit 92ec83b
Showing 1 changed file with 42 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
Expand Down Expand Up @@ -50,6 +51,47 @@ private WeakReference TestCleanupHelper(IDistributedLock lock1, IDistributedLock

return new WeakReference(handle);
}

/// <summary>
/// This method demonstrates how <see cref="SqlDistributedLockConnectionStrategy.OptimisticConnectionMultiplexing"/>
/// can be used to hold many locks concurrently on one underlying connection.
///
/// Note: I would like this test to actually leverage multiple threads, but this runs into issues because the current
/// implementation of optimistic multiplexing only makes one attempt to use a shared lock before opening a new connection.
/// This runs into problems because the attempt to use a shared lock can fail if, for example, a lock is being released on
/// that connection which means that the mutex for the connection can't be acquired without waiting. Once something like
/// this happens, we try to open a new connection which times out due to pool size limits
/// </summary>
[TestMethod]
public void TestHighConcurrencyWithSmallPool()
{
var connectionString = new SqlConnectionStringBuilder(SqlDistributedLockTest.ConnectionString) { MaxPoolSize = 1 }.ConnectionString;

Func<Task> test = async () =>
{
var random = new Random(Guid.NewGuid().GetHashCode());
var heldLocks = new Dictionary<string, IDisposable>();
for (var i = 0; i < 1000; ++i)
{
var lockName = $"{nameof(TestHighConcurrencyWithSmallPool)}_{random.Next(20)}";
IDisposable existingHandle;
if (heldLocks.TryGetValue(lockName, out existingHandle))
{
existingHandle.Dispose();
heldLocks.Remove(lockName);
}
else
{
var @lock = new SqlDistributedLock(lockName, connectionString, SqlDistributedLockConnectionStrategy.OptimisticConnectionMultiplexing);
var handle = await @lock.TryAcquireAsync();
if (handle != null) { heldLocks.Add(lockName, handle); }
}
}
};

Task.Run(test).Wait(TimeSpan.FromSeconds(10)).ShouldEqual(true);
}

internal override IDistributedLock CreateLock(string name)
=> new SqlDistributedLock(name, SqlDistributedLockTest.ConnectionString, SqlDistributedLockConnectionStrategy.OptimisticConnectionMultiplexing);
Expand Down

0 comments on commit 92ec83b

Please sign in to comment.