public void NoDeadLockTest() { if (BaseTestDatabase.IsSqlite()) { Assert.Ignore("This test doesn't work with Microsoft.Data.Sqlite - SELECT * FROM sys.dm_tran_locks;"); return; } Exception e1 = null, e2 = null; AutoResetEvent ev1 = new AutoResetEvent(false), ev2 = new AutoResetEvent(false); // testing: // two threads will each obtain exclusive write lock over two // different lock objects without blocking each other var thread1 = new Thread(() => NoDeadLockTestThread(1, ev1, ev2, ref e1)); var thread2 = new Thread(() => NoDeadLockTestThread(2, ev2, ev1, ref e1)); // ensure that current scope does not leak into starting threads using (ExecutionContext.SuppressFlow()) { thread1.Start(); thread2.Start(); } ev2.Set(); thread1.Join(); thread2.Join(); Assert.IsNull(e1); Assert.IsNull(e2); }
public void DeadLockTest() { if (BaseTestDatabase.IsSqlite()) { Assert.Ignore("This test doesn't work with Microsoft.Data.Sqlite - SELECT * FROM sys.dm_tran_locks;"); return; } Exception e1 = null, e2 = null; AutoResetEvent ev1 = new AutoResetEvent(false), ev2 = new AutoResetEvent(false); // testing: // two threads will each obtain exclusive write locks over two // identical lock objects deadlock each other var thread1 = new Thread(() => DeadLockTestThread(1, 2, ev1, ev2, ref e1)); var thread2 = new Thread(() => DeadLockTestThread(2, 1, ev2, ev1, ref e2)); // ensure that current scope does not leak into starting threads using (ExecutionContext.SuppressFlow()) { thread1.Start(); thread2.Start(); } ev2.Set(); thread1.Join(); thread2.Join(); //Assert.IsNotNull(e1); if (e1 != null) { AssertIsDistributedLockingTimeoutException(e1); } // the assertion below depends on timing conditions - on a fast enough environment, // thread1 dies (deadlock) and frees thread2, which succeeds - however on a slow // environment (CI) both threads can end up dying due to deadlock - so, cannot test // that e2 is null - but if it's not, can test that it's a timeout // //Assert.IsNull(e2); if (e2 != null) { AssertIsDistributedLockingTimeoutException(e2); } }
public void CreateKeysAndIndexes() { if (BaseTestDatabase.IsSqlite()) { // TODO: Think about this for future migrations. Assert.Ignore("Can't add / drop keys in SQLite."); return; } IMigrationBuilder builder = Mock.Of <IMigrationBuilder>(); Mock.Get(builder) .Setup(x => x.Build(It.IsAny <Type>(), It.IsAny <IMigrationContext>())) .Returns <Type, IMigrationContext>((t, c) => { switch (t.Name) { case "CreateTableOfTDtoMigration": return(new CreateTableOfTDtoMigration(c)); case "DeleteKeysAndIndexesMigration": return(new DeleteKeysAndIndexesMigration(c)); case "CreateKeysAndIndexesMigration": return(new CreateKeysAndIndexesMigration(c)); default: throw new NotSupportedException(); } }); using (IScope scope = ScopeProvider.CreateScope()) { var upgrader = new Upgrader( new MigrationPlan("test") .From(string.Empty) .To <CreateTableOfTDtoMigration>("a") .To <DeleteKeysAndIndexesMigration>("b") .To <CreateKeysAndIndexesMigration>("done")); upgrader.Execute(MigrationPlanExecutor, ScopeProvider, Mock.Of <IKeyValueService>()); scope.Complete(); } }
public void Throws_When_Lock_Timeout_Is_Exceeded_Read() { if (BaseTestDatabase.IsSqlite()) { // Reader reads snapshot, isolated from the writer. Assert.Ignore("Doesn't apply to SQLite with journal_mode=wal"); } using (ExecutionContext.SuppressFlow()) { var t1 = Task.Run(() => { using (var scope = ScopeProvider.CreateScope()) { Console.WriteLine("Write lock A"); // This will acquire right away scope.EagerWriteLock(TimeSpan.FromMilliseconds(2000), Constants.Locks.ContentTree); Thread.Sleep(6000); // Wait longer than the Read Lock B timeout scope.Complete(); Console.WriteLine("Finished Write lock A"); } }); Thread.Sleep(500); // 100% sure task 1 starts first var t2 = Task.Run(() => { using (var scope = ScopeProvider.CreateScope()) { Console.WriteLine("Read lock B"); // This will wait for the write lock to release but it isn't going to wait long // enough so an exception will be thrown. Assert.Throws <DistributedReadLockTimeoutException>(() => scope.EagerReadLock(TimeSpan.FromMilliseconds(3000), Constants.Locks.ContentTree)); scope.Complete(); Console.WriteLine("Finished Read lock B"); } }); Task.WaitAll(t1, t2); } }
public void Read_Lock_Waits_For_Write_Lock() { if (BaseTestDatabase.IsSqlite()) { // Reader reads snapshot, isolated from the writer. Assert.Ignore("Doesn't apply to SQLite with journal_mode=wal"); } var locksCompleted = 0; using (ExecutionContext.SuppressFlow()) { var t1 = Task.Run(() => { using (var scope = ScopeProvider.CreateScope()) { Console.WriteLine("Write lock A"); // This will acquire right away scope.EagerWriteLock(TimeSpan.FromMilliseconds(2000), Constants.Locks.ContentTree); Thread.Sleep(4000); // Wait less than the Read Lock B timeout scope.Complete(); Interlocked.Increment(ref locksCompleted); Console.WriteLine("Finished Write lock A"); } }); Thread.Sleep(500); // 100% sure task 1 starts first var t2 = Task.Run(() => { using (var scope = ScopeProvider.CreateScope()) { Console.WriteLine("Read lock B"); // This will wait for the write lock to release Assert.DoesNotThrow(() => scope.EagerReadLock(TimeSpan.FromMilliseconds(6000), Constants.Locks.ContentTree)); Assert.GreaterOrEqual(locksCompleted, 1); scope.Complete(); Interlocked.Increment(ref locksCompleted); Console.WriteLine("Finished Read lock B"); } }); var t3 = Task.Run(() => { using (var scope = ScopeProvider.CreateScope()) { Console.WriteLine("Read lock C"); // This will wait for the write lock to release Assert.DoesNotThrow(() => scope.EagerReadLock(TimeSpan.FromMilliseconds(6000), Constants.Locks.ContentTree)); Assert.GreaterOrEqual(locksCompleted, 1); scope.Complete(); Interlocked.Increment(ref locksCompleted); Console.WriteLine("Finished Read lock C"); } }); Task.WaitAll(t1, t2, t3); } Assert.AreEqual(3, locksCompleted); }