//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldHandleMultipleConcurrentStoreCopyRequests() throws Throwable
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
        public virtual void ShouldHandleMultipleConcurrentStoreCopyRequests()
        {
            // GIVEN
            Race           race    = new Race();
            CountingAction action  = new CountingAction();
            int            threads = Runtime.Runtime.availableProcessors() * 10;

            race.AddContestants(threads, throwing(() =>
            {
                ParkARandomWhile();
                using (Resource @lock = _mutex.storeCopy(action))
                {
                    ParkARandomWhile();
                }
            }));
            race.Go();

            // THEN
            // It's hard to make predictions about what should have been seen. Most importantly is that
            // The lock doesn't hang any requests and that number of calls to the action less than number of threads
            assertThat(action.Count(), lessThan(threads));
        }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldPropagateStoreCopyActionFailureToOtherStoreCopyRequests() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
        public virtual void ShouldPropagateStoreCopyActionFailureToOtherStoreCopyRequests()
        {
            // GIVEN
            Org.Neo4j.Test.Barrier_Control barrier           = new Org.Neo4j.Test.Barrier_Control();
            IOException controlledFailure                    = new IOException("My own fault");
            AtomicReference <Future <object> > secondRequest = new AtomicReference <Future <object> >();
            ThrowingAction <IOException>       controllableAndFailingAction = () =>
            {
                // Now that we know we're first, start the second request...
                secondRequest.set(T3.execute(state => _mutex.storeCopy(_assertNotCalled)));
                // ...and wait for it to reach its destination
                barrier.AwaitUninterruptibly();
                try
                {
                    // OK, second request has made progress into the request, so we can now produce our failure
                    throw controlledFailure;
                }
                finally
                {
                    barrier.Release();
                }
            };

            Future <object> firstRequest = T2.execute(state => _mutex.storeCopy(controllableAndFailingAction));

            while (secondRequest.get() == null)
            {
                ParkARandomWhile();
            }
            T3.get().waitUntilWaiting(details => details.isAt(typeof(StoreCopyCheckPointMutex), "waitForFirstStoreCopyActionToComplete"));

            // WHEN
            barrier.Reached();

            // THEN
            try
            {
                firstRequest.get();
            }
            catch (ExecutionException e)
            {
                assertSame(controlledFailure, e.InnerException);
            }
            try
            {
                secondRequest.get().get();
            }
            catch (ExecutionException e)
            {
                Exception cooperativeActionFailure = e.InnerException;
                assertThat(cooperativeActionFailure.Message, containsString("Co-operative"));
                assertSame(controlledFailure, cooperativeActionFailure.InnerException);
            }

            // WHEN afterwards trying another store-copy
            CountingAction action = new CountingAction();

            using (Resource @lock = _mutex.storeCopy(action))
            {
                // THEN
                assertEquals(1, action.Count());
            }
        }