-
Notifications
You must be signed in to change notification settings - Fork 200
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from madelson/deadlock-exception
Address #11 by throwing a specific exception type (DeadlockException)…
- Loading branch information
Showing
11 changed files
with
166 additions
and
5 deletions.
There are no files selected for viewing
64 changes: 64 additions & 0 deletions
64
DistributedLock.Tests/AbstractTestCases/ExternalConnectionOrTransactionStrategyTestCases.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
using Medallion.Threading.Sql; | ||
using Medallion.Threading.Tests.Sql; | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Data.SqlClient; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace Medallion.Threading.Tests | ||
{ | ||
[TestClass] | ||
public abstract class ExternalConnectionOrTransactionStrategyTestCases<TEngineFactory, TConnectionManagementProvider> : TestBase | ||
where TEngineFactory : ITestingSqlDistributedLockEngineFactory, new() | ||
where TConnectionManagementProvider : TestingSqlConnectionManagementProvider, IExternalConnectionOrTransactionTestingSqlConnectionManagementProvider, new() | ||
{ | ||
[TestMethod] | ||
public void TestDeadlockDetection() | ||
{ | ||
var timeout = TimeSpan.FromSeconds(30); | ||
|
||
using (var engine = this.CreateEngine()) | ||
using (var provider = new TConnectionManagementProvider()) | ||
using (var barrier = new Barrier(participantCount: 2)) | ||
{ | ||
const string LockName1 = nameof(TestDeadlockDetection) + "_1", | ||
LockName2 = nameof(TestDeadlockDetection) + "_2"; | ||
|
||
Task RunDeadlock(bool isFirst) | ||
{ | ||
var connectionInfo = provider.GetConnectionInfo(); | ||
IDistributedLock lock1, lock2; | ||
using (connectionInfo.Transaction != null ? TransactionProvider.UseTransaction(connectionInfo.Transaction) : ConnectionProvider.UseConnection(connectionInfo.Connection)) | ||
{ | ||
lock1 = engine.CreateLock(isFirst ? LockName1 : LockName2); | ||
lock2 = engine.CreateLock(isFirst ? LockName2 : LockName1); | ||
} | ||
return Task.Run(async () => | ||
{ | ||
using (await lock1.AcquireAsync(timeout)) | ||
{ | ||
barrier.SignalAndWait(); | ||
(await lock2.AcquireAsync(timeout)).Dispose(); | ||
} | ||
}); | ||
} | ||
|
||
var tasks = new[] { RunDeadlock(isFirst: true), RunDeadlock(isFirst: false) }; | ||
|
||
Task.WhenAll(tasks).ContinueWith(_ => { }).Wait(TimeSpan.FromSeconds(10)).ShouldEqual(true, this.GetType().Name); | ||
|
||
var deadlockVictim = tasks.Single(t => t.IsFaulted); | ||
Assert.IsInstanceOfType(deadlockVictim.Exception.GetBaseException(), typeof(InvalidOperationException)); // backwards compat check | ||
Assert.IsInstanceOfType(deadlockVictim.Exception.GetBaseException(), typeof(DeadlockException)); | ||
|
||
tasks.Count(t => t.Status == TaskStatus.RanToCompletion).ShouldEqual(1); | ||
} | ||
} | ||
|
||
private TestingDistributedLockEngine CreateEngine() => new TEngineFactory().Create<TConnectionManagementProvider>(); | ||
} | ||
} |
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Runtime.Serialization.Formatters.Binary; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Medallion.Threading.Tests.Tests | ||
{ | ||
[TestClass] | ||
public class DeadlockExceptionTest : TestBase | ||
{ | ||
[TestMethod] | ||
public void TestDeadlockExceptionSerialization() | ||
{ | ||
void ThrowDeadlockException() => throw new DeadlockException(nameof(TestDeadlockExceptionSerialization), new InvalidOperationException("foo")); | ||
|
||
DeadlockException deadlockException = null; | ||
try { ThrowDeadlockException(); } | ||
catch (DeadlockException ex) { deadlockException = ex; } | ||
|
||
var formatter = new BinaryFormatter(); | ||
var stream = new MemoryStream(); | ||
formatter.Serialize(stream, deadlockException); | ||
|
||
stream.Position = 0; | ||
var deserialized = (DeadlockException)formatter.Deserialize(stream); | ||
deserialized.Message.ShouldEqual(deadlockException.Message); | ||
deserialized.StackTrace.ShouldEqual(deadlockException.StackTrace); | ||
deserialized.InnerException.Message.ShouldEqual(deadlockException.InnerException.Message); | ||
} | ||
} | ||
} |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
|
||
namespace Medallion.Threading | ||
{ | ||
/// <summary> | ||
/// An exception that SOME distributed locks will throw under SOME deadlock conditions. Note that even locks | ||
/// that throw this exception under some circumstances cannot detect ALL deadlock conditions | ||
/// </summary> | ||
#if !NETSTANDARD_1_3 | ||
[Serializable] | ||
#endif | ||
public sealed class DeadlockException | ||
// for backwards compat | ||
: InvalidOperationException | ||
{ | ||
/// <summary> | ||
/// Constructs a new instance of <see cref="DeadlockException"/> with a default message | ||
/// </summary> | ||
public DeadlockException() : this("A deadlock occurred") { } | ||
|
||
/// <summary> | ||
/// Constructs an instance of <see cref="DeadlockException"/> with the given <paramref name="message"/> | ||
/// </summary> | ||
public DeadlockException(string message) : base(message) { } | ||
|
||
/// <summary> | ||
/// Constructs an instance of <see cref="DeadlockException"/> with the given <paramref name="message"/> and <paramref name="innerException"/> | ||
/// </summary> | ||
public DeadlockException(string message, Exception innerException) : base(message, innerException) { } | ||
|
||
#if !NETSTANDARD_1_3 | ||
private DeadlockException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { } | ||
#endif | ||
} | ||
} |
This file contains 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
This file contains 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
This file contains 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
This file contains 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