public void No_deadlock_and_no_race_condition_on_resources_using_sessions()
        {
            var mgr = new LockManager();

            var watch = new Stopwatch();

            watch.Start();

            int iterations = 10_000;

            Parallel.For(0, iterations, i =>
            {
                Parallel.Invoke(
                    () =>
                {
                    var session = Guid.NewGuid();
                    mgr.AcquireLock(session, false, "a", "b", "c");
                    ReadAbc();
                    mgr.CloseSession(session);
                },
                    () =>
                {
                    var session = Guid.NewGuid();
                    mgr.AcquireLock(session, false, "a");
                    ReadA();
                    mgr.CloseSession(session);
                },
                    () =>
                {
                    var session = Guid.NewGuid();
                    mgr.AcquireLock(session, true, "a", "b", "c");
                    WriteAbc();
                    mgr.CloseSession(session);
                },
                    () =>
                {
                    var session = Guid.NewGuid();
                    mgr.AcquireLock(session, true, "a");
                    WriteA();
                    mgr.CloseSession(session);
                });
            });

            watch.Stop();

            Console.WriteLine($"{iterations} iterations took {watch.ElapsedMilliseconds} ms");
            Console.WriteLine($"retries = {mgr.Retries}");
            Console.WriteLine($"a = {_resourceA.Count} b = {_resourceB.Count} c = {_resourceC.Count}");


            int locks = mgr.GetCurrentlyHoldLocks();

            Assert.AreEqual(0, locks);
        }
        public void Consistent_read_sessions()
        {
            ILockManager lockManager = new LockManager(null);

            var session = Guid.NewGuid();

            lockManager.AcquireLock(session, false, "x", "y", "z");


            bool success = lockManager.CheckLock(session, false, "x");

            Assert.IsTrue(success);


            // try with a new session (should not work)
            success = lockManager.CheckLock(Guid.NewGuid(), false, "x");
            Assert.IsFalse(success);

            // read-only lock so it should not work
            success = lockManager.CheckLock(session, true, "x");
            Assert.IsFalse(success);

            // different resource so it should not work
            success = lockManager.CheckLock(session, true, "nope");
            Assert.IsFalse(success);


            // trying to close an inactive session throws an exception
            Assert.Throws <NotSupportedException>(() => lockManager.CloseSession(Guid.NewGuid()));
        }
        public void Managing_pending_locks()
        {
            var log = A.Fake <IEventsLog>();


            ILockManager lockManager = new LockManager(log);

            var sessionId = Guid.NewGuid();

            lockManager.AcquireLock(sessionId, false, "x", "y", "z");

            Assert.AreEqual(3, lockManager.GetCurrentlyHoldLocks());

            Assert.IsTrue(lockManager.CheckLock(sessionId, false, "x", "y", "z"));

            // false because it is a read-only lock
            Assert.False(lockManager.CheckLock(sessionId, true, "x", "y", "z"));

            lockManager.CloseSession(sessionId);

            Assert.AreEqual(0, lockManager.GetCurrentlyHoldLocks());

            // session no longer active
            Assert.IsFalse(lockManager.CheckLock(sessionId, false, "x", "y", "z"));


            lockManager.AcquireLock(sessionId, true, "tony", "tara");
            Assert.AreEqual(2, lockManager.GetCurrentlyHoldLocks());


            Thread.Sleep(500);

            Assert.AreEqual(2, lockManager.GetCurrentlyHoldLocks(100));

            var locks = lockManager.ForceRemoveAllLocks(100);

            A.CallTo(() => log.LogEvent(EventType.LockRemoved, null, 0)).MustHaveHappened();

            Assert.AreEqual(2, locks);

            Assert.AreEqual(0, lockManager.GetCurrentlyHoldLocks());
        }
        public void Mixed_use_of_sessions_and_simple_accesses_simulating_both_transactional_and_non_transactional_clients()
        {
            var mgr = new LockManager();

            var watch = new Stopwatch();

            watch.Start();



            int iterations = 100;

            Parallel.For(0, iterations, i =>
            {
                Parallel.Invoke(
                    () =>
                {
                    for (int i = 0; i < iterations; i++)
                    {
                        var session = Guid.NewGuid();
                        mgr.AcquireLock(session, false, "a", "b", "c");
                        ReadAbc();
                        mgr.CloseSession(session);
                    }
                },
                    () =>
                {
                    for (int i = 0; i < iterations; i++)
                    {
                        var session = Guid.NewGuid();
                        mgr.AcquireLock(session, false, "a");
                        ReadA();
                        mgr.CloseSession(session);
                    }
                },
                    () =>
                {
                    for (int i = 0; i < iterations; i++)
                    {
                        var session = Guid.NewGuid();
                        mgr.AcquireLock(session, true, "a", "b", "c");
                        WriteAbc();
                        mgr.CloseSession(session);
                    }
                },
                    () =>
                {
                    for (int i = 0; i < iterations; i++)
                    {
                        var session = Guid.NewGuid();
                        mgr.AcquireLock(session, true, "a");
                        WriteA();
                        mgr.CloseSession(session);
                    }
                },
                    () =>
                {
                    for (int i = 0; i < 100; i++)
                    {
                        mgr.DoWithReadLock(ReadAbc, "a", "b", "c");
                    }
                },
                    () =>
                {
                    for (int i = 0; i < 100; i++)
                    {
                        mgr.DoWithReadLock(ReadA, "a");
                    }
                },
                    () =>
                {
                    for (int i = 0; i < 100; i++)
                    {
                        mgr.DoWithWriteLock(WriteAbc, "a", "b", "c");
                    }
                },
                    () =>
                {
                    for (int i = 0; i < 100; i++)
                    {
                        mgr.DoWithWriteLock(WriteA, "a");
                    }
                });
            });

            watch.Stop();

            Console.WriteLine($"{iterations} iterations took {watch.ElapsedMilliseconds} ms");
            Console.WriteLine($"retries = {mgr.Retries}");
            Console.WriteLine($"a = {_resourceA.Count} b = {_resourceB.Count} c = {_resourceC.Count}");


            int locks = mgr.GetCurrentlyHoldLocks();

            Assert.AreEqual(0, locks);
        }