コード例 #1
0
        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);
        }
コード例 #2
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;
            }
        }
コード例 #3
0
        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;
            }
        }
コード例 #4
0
            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;
                }
            }
コード例 #5
0
        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);
            }
        }
コード例 #6
0
        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);
                }
            }
        }
コード例 #7
0
        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));
            }
        }
コード例 #9
0
        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());
                    }
                }
            }
        }
コード例 #10
0
        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);
            }
        }
コード例 #11
0
        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());
                }
            }
        }
コード例 #12
0
 internal override string GetSafeLockName(string name) => SqlDistributedReaderWriterLock.GetSafeLockName(name);
コード例 #13
0
 public SqlReaderWriterLockDistributedLock(SqlDistributedReaderWriterLock @lock, bool useUpgradeLock)
 {
     this.@lock          = @lock;
     this.useUpgradeLock = useUpgradeLock;
 }
コード例 #14
0
        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);
        }
コード例 #15
0
 public SqlReaderWriterLockDistributedLock(SqlDistributedReaderWriterLockTestBase test, string name)
 {
     this.@lock = test.CreateReaderWriterLock(name);
     this.test  = test;
 }
コード例 #16
0
 private static string UniqueSafeLockName(string baseName) =>
 SqlDistributedReaderWriterLock.GetSafeLockName($"{baseName}_{TestHelper.FrameworkName}");
コード例 #17
0
 public override string GetSafeName(string name) => SqlDistributedReaderWriterLock.GetSafeName(name);
コード例 #18
0
 public InternalUpgradeableHandle(SqlDistributedReaderWriterLock @lock, IDisposable baseHandle)
 {
     this.@lock      = @lock;
     this.baseHandle = baseHandle;
 }