static int Main(string[] args) { var type = args[0]; var name = args[1]; IDisposable handle = null; switch (type) { case "sql": handle = new SqlDistributedLock(name, ConnectionString).Acquire(); break; case "sqlreaderwriterlock": handle = new SqlDistributedReaderWriterLock(name, ConnectionString).AcquireWriteLock(); break; case "system": handle = new SystemDistributedLock(name).Acquire(); break; default: return(123); } if (Console.ReadLine() != "abandon") { handle.Dispose(); } return(0); }
public void TestAzureStrategyProtectsFromIdleSessionKillerAfterFailedUpgrade() { var originalInterval = KeepaliveHelper.Interval; try { KeepaliveHelper.Interval = TimeSpan.FromSeconds(.1); var @lock = new SqlDistributedReaderWriterLock( nameof(TestAzureStrategyProtectsFromIdleSessionKillerAfterFailedUpgrade), ConnectionStringProvider.ConnectionString, SqlDistributedLockConnectionStrategy.Azure ); using (new IdleSessionKiller(ConnectionStringProvider.ConnectionString, idleTimeout: TimeSpan.FromSeconds(.25))) using (@lock.AcquireReadLock()) { var handle = @lock.AcquireUpgradeableReadLock(); handle.TryUpgradeToWriteLock().ShouldEqual(false); handle.TryUpgradeToWriteLockAsync().Result.ShouldEqual(false); Thread.Sleep(TimeSpan.FromSeconds(1)); TestHelper.AssertDoesNotThrow(() => handle.Dispose()); } } finally { KeepaliveHelper.Interval = originalInterval; } }
public void ThreadSafetyExerciseWithLockUpgrade() { var originalInterval = KeepaliveHelper.Interval; try { KeepaliveHelper.Interval = TimeSpan.FromMilliseconds(1); TestHelper.AssertDoesNotThrow(() => { var @lock = new SqlDistributedReaderWriterLock( nameof(ThreadSafetyExerciseWithLockUpgrade), ConnectionStringProvider.ConnectionString, SqlDistributedLockConnectionStrategy.Azure ); for (var i = 0; i < 30; ++i) { using (var handle = @lock.AcquireUpgradeableReadLockAsync().Result) { Thread.Sleep(1); handle.UpgradeToWriteLock(); Thread.Sleep(1); } } }); } finally { KeepaliveHelper.Interval = originalInterval; } }
public override void Dispose() { // NOTE that despite the use of Interlocked here, this class is not thread-safe var innerHandle = Interlocked.Exchange(ref this.baseHandle, null); if (innerHandle != null) { // sp_getapplock must be exited for each time it is entered this.upgradedHandle?.Dispose(); innerHandle.Dispose(); this.@lock = null; } }
public void TestLockOnClosedTransaction() { using (var connection = new SqlConnection(SqlDistributedLockTest.ConnectionString)) { connection.Open(); IDisposable handle; using (var transaction = connection.BeginTransaction()) { handle = new SqlDistributedReaderWriterLock("b", transaction).AcquireWriteLock(); SqlTransactionScopedDistributedLockTest.IsHeld("b").ShouldEqual(true); } TestHelper.AssertDoesNotThrow(handle.Dispose); SqlTransactionScopedDistributedLockTest.IsHeld("b").ShouldEqual(false); } }
public void TestIsNotScopedToTransaction() { using (var connection = new SqlConnection(SqlDistributedLockTest.ConnectionString)) { connection.Open(); using (var handle = new SqlDistributedReaderWriterLock("a", connection).AcquireWriteLock()) { using (var transaction = connection.BeginTransaction()) { transaction.Rollback(); } SqlTransactionScopedDistributedLockTest.IsHeld("a").ShouldEqual(true); } } }
public static int Main(string[] args) { var type = args[0]; var name = args[1]; IDisposable?handle; switch (type) { case "SqlDistributedLock": handle = new SqlDistributedLock(name, ConnectionString).Acquire(); break; case "SqlReaderWriterLockDistributedLock": handle = new SqlDistributedReaderWriterLock(name, ConnectionString).AcquireWriteLock(); break; case "SqlSemaphoreDistributedLock": handle = new SqlDistributedSemaphore(name, maxCount: 1, connectionString: ConnectionString).Acquire(); break; case "SqlSemaphoreDistributedLock5": handle = new SqlDistributedSemaphore(name, maxCount: 5, connectionString: ConnectionString).Acquire(); break; case "SystemDistributedLock": handle = new SystemDistributedLock(name).Acquire(); break; default: return(123); } Console.WriteLine("Acquired"); Console.Out.Flush(); if (Console.ReadLine() != "abandon") { handle.Dispose(); } return(0); }
public void TestGetSafeLockNameCompat() { SqlDistributedReaderWriterLock.MaxNameLength.ShouldEqual(SqlDistributedLock.MaxNameLength); var cases = new[] { string.Empty, "abc", "\\", new string('a', SqlDistributedLock.MaxNameLength), new string('\\', SqlDistributedLock.MaxNameLength), new string('x', SqlDistributedLock.MaxNameLength + 1) }; foreach (var lockName in cases) { // should be compatible with SqlDistributedLock SqlDistributedReaderWriterLock.GetSafeName(lockName).ShouldEqual(SqlDistributedLock.GetSafeName(lockName)); } }
public void TestScopedToTransactionOnly() { using (var connection = new SqlConnection(SqlDistributedLockTest.ConnectionString)) { connection.Open(); using (var transaction = connection.BeginTransaction()) { using (new SqlDistributedReaderWriterLock("t", transaction).AcquireWriteLock()) { using (var handle = new SqlDistributedReaderWriterLock("t", transaction).TryAcquireWriteLock()) { Assert.IsNotNull(handle, "reentrant"); } TestHelper.AssertThrows <InvalidOperationException>(() => new SqlDistributedReaderWriterLock("t", connection).TryAcquireWriteLock()); } } } }
public void TestCloseLockOnClosedConnection() { using (var connection = new SqlConnection(SqlDistributedLockTest.ConnectionString)) { TestHelper.AssertThrows <InvalidOperationException>(() => new SqlDistributedReaderWriterLock("a", connection).AcquireWriteLock()); connection.Open(); var @lock = new SqlDistributedReaderWriterLock("a", connection); var handle = @lock.AcquireWriteLock(); SqlTransactionScopedDistributedLockTest.IsHeld("a").ShouldEqual(true); connection.Dispose(); TestHelper.AssertDoesNotThrow(handle.Dispose); // lock can be re-acquired SqlTransactionScopedDistributedLockTest.IsHeld("a").ShouldEqual(false); } }
public void TestLockOnCommittedBackTransaction() { using (var connection = new SqlConnection(SqlDistributedLockTest.ConnectionString)) { connection.Open(); using (var transaction = connection.BeginTransaction()) { var handle = new SqlDistributedReaderWriterLock("d", transaction).AcquireWriteLock(); SqlTransactionScopedDistributedLockTest.IsHeld("d").ShouldEqual(true); transaction.Commit(); TestHelper.AssertDoesNotThrow(handle.Dispose); SqlTransactionScopedDistributedLockTest.IsHeld("d").ShouldEqual(false); TestHelper.AssertThrows <InvalidOperationException>(() => new SqlDistributedReaderWriterLock("d", transaction).AcquireWriteLock()); } } }
internal override string GetSafeLockName(string name) => SqlDistributedReaderWriterLock.GetSafeLockName(name);
public SqlReaderWriterLockDistributedLock(SqlDistributedReaderWriterLock @lock, bool useUpgradeLock) { this.@lock = @lock; this.useUpgradeLock = useUpgradeLock; }
public static int Main(string[] args) { var type = args[0]; var name = args[1]; IDisposable?handle; switch (type) { case nameof(SqlDistributedLock): handle = new SqlDistributedLock(name, SqlServerCredentials.ConnectionString).Acquire(); break; case "Write" + nameof(SqlDistributedReaderWriterLock): handle = new SqlDistributedReaderWriterLock(name, SqlServerCredentials.ConnectionString).AcquireWriteLock(); break; case nameof(SqlDistributedSemaphore) + "1AsMutex": handle = new SqlDistributedSemaphore(name, maxCount: 1, connectionString: SqlServerCredentials.ConnectionString).Acquire(); break; case nameof(SqlDistributedSemaphore) + "5AsMutex": handle = new SqlDistributedSemaphore(name, maxCount: 5, connectionString: SqlServerCredentials.ConnectionString).Acquire(); break; case nameof(PostgresDistributedLock): handle = new PostgresDistributedLock(new PostgresAdvisoryLockKey(name), PostgresCredentials.GetConnectionString(Environment.CurrentDirectory)).Acquire(); break; case "Write" + nameof(PostgresDistributedReaderWriterLock): handle = new PostgresDistributedReaderWriterLock(new PostgresAdvisoryLockKey(name), PostgresCredentials.GetConnectionString(Environment.CurrentDirectory)).AcquireWriteLock(); break; case nameof(EventWaitHandleDistributedLock): handle = new EventWaitHandleDistributedLock(name).Acquire(); break; case nameof(WaitHandleDistributedSemaphore) + "1AsMutex": handle = new WaitHandleDistributedSemaphore(name, maxCount: 1).Acquire(); break; case nameof(WaitHandleDistributedSemaphore) + "5AsMutex": handle = new WaitHandleDistributedSemaphore(name, maxCount: 5).Acquire(); break; case nameof(AzureBlobLeaseDistributedLock): handle = new AzureBlobLeaseDistributedLock( new BlobClient(AzureCredentials.ConnectionString, AzureCredentials.DefaultBlobContainerName, name), o => o.Duration(TimeSpan.FromSeconds(15)) ) .Acquire(); break; case nameof(FileDistributedLock): handle = new FileDistributedLock(new FileInfo(name)).Acquire(); break; case nameof(RedisDistributedLock) + "1": handle = AcquireRedisLock(name, serverCount: 1); break; case nameof(RedisDistributedLock) + "3": handle = AcquireRedisLock(name, serverCount: 3); break; case nameof(RedisDistributedLock) + "2x1": handle = AcquireRedisLock(name, serverCount: 2); // we know the last will fail; don't bother (we also don't know its port) break; case nameof(RedisDistributedLock) + "1WithPrefix": handle = AcquireRedisLock("distributed_locks:" + name, serverCount: 1); break; case "Write" + nameof(RedisDistributedReaderWriterLock) + "1": handle = AcquireRedisWriteLock(name, serverCount: 1); break; case "Write" + nameof(RedisDistributedReaderWriterLock) + "3": handle = AcquireRedisWriteLock(name, serverCount: 3); break; case "Write" + nameof(RedisDistributedReaderWriterLock) + "2x1": handle = AcquireRedisWriteLock(name, serverCount: 2); // we know the last will fail; don't bother (we also don't know its port) break; case "Write" + nameof(RedisDistributedReaderWriterLock) + "1WithPrefix": handle = AcquireRedisWriteLock("distributed_locks:" + name, serverCount: 1); break; case string _ when type.StartsWith(nameof(RedisDistributedSemaphore)): { var maxCount = type.EndsWith("1AsMutex") ? 1 : type.EndsWith("5AsMutex") ? 5 : throw new ArgumentException(type); handle = new RedisDistributedSemaphore( name, maxCount, GetRedisDatabases(serverCount: 1).Single(), // in order to see abandonment work in a reasonable timeframe, use very short expiry options => options.Expiry(TimeSpan.FromSeconds(1)) .BusyWaitSleepTime(TimeSpan.FromSeconds(.1), TimeSpan.FromSeconds(.3)) ).Acquire(); break; } default: Console.Error.WriteLine($"type: {type}"); return(123); } Console.WriteLine("Acquired"); Console.Out.Flush(); if (Console.ReadLine() != "abandon") { handle.Dispose(); } return(0); }
public SqlReaderWriterLockDistributedLock(SqlDistributedReaderWriterLockTestBase test, string name) { this.@lock = test.CreateReaderWriterLock(name); this.test = test; }
private static string UniqueSafeLockName(string baseName) => SqlDistributedReaderWriterLock.GetSafeLockName($"{baseName}_{TestHelper.FrameworkName}");
public override string GetSafeName(string name) => SqlDistributedReaderWriterLock.GetSafeName(name);
public InternalUpgradeableHandle(SqlDistributedReaderWriterLock @lock, IDisposable baseHandle) { this.@lock = @lock; this.baseHandle = baseHandle; }