//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldRecoverFromCrashBeforeFirstCheckpoint() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
        public virtual void ShouldRecoverFromCrashBeforeFirstCheckpoint()
        {
            // GIVEN
            // a tree with only small amount of data that has not yet seen checkpoint from outside
            KEY   key   = key(1L);
            VALUE value = value(10L);
            File  file  = _directory.file("index");

            {
                using (PageCache pageCache = CreatePageCache(), GBPTree <KEY, VALUE> index = CreateIndex(pageCache, file), Writer <KEY, VALUE> writer = index.Writer())
                {
                    writer.Put(key, value);
                    pageCache.FlushAndForce();
                    // No checkpoint
                }
            }

            // WHEN
            using (PageCache pageCache = CreatePageCache(), GBPTree <KEY, VALUE> index = CreateIndex(pageCache, file))
            {
                using (Writer <KEY, VALUE> writer = index.Writer())
                {
                    writer.Put(key, value);
                }

                // THEN
                // we should end up with a consistent index
                index.ConsistencyCheck();

                // ... containing all the stuff load says
                using (RawCursor <Hit <KEY, VALUE>, IOException> cursor = index.Seek(key(long.MinValue), key(long.MaxValue)))
                {
                    assertTrue(cursor.Next());
                    Hit <KEY, VALUE> hit = cursor.get();
                    AssertEqualsKey(key, hit.Key());
                    AssertEqualsValue(value, hit.Value());
                }
            }
        }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: public void flushAndForce() throws java.io.IOException
        public override void FlushAndForce()
        {
            _adversary.injectFailure(typeof(FileNotFoundException), typeof(IOException), typeof(SecurityException));
            @delegate.FlushAndForce();
        }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: public void flushAndForce(IOLimiter limiter) throws java.io.IOException
        public override void FlushAndForce(IOLimiter limiter)
        {
            @delegate.FlushAndForce(limiter);
        }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: private void doShouldRecoverFromAnything(boolean replayRecoveryExactlyFromCheckpoint) throws Exception
        private void DoShouldRecoverFromAnything(bool replayRecoveryExactlyFromCheckpoint)
        {
            AssertInitialized();
            // GIVEN
            // a tree which has had random updates and checkpoints in it, load generated with specific seed
            File           file                = _directory.file("index");
            IList <Action> load                = GenerateLoad();
            IList <Action> shuffledLoad        = RandomCausalAwareShuffle(load);
            int            lastCheckPointIndex = IndexOfLastCheckpoint(load);

            {
                // _,_,_,_,_,_,_,c,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,c,_,_,_,_,_,_,_,_,_,_,_
                //                                                 ^             ^
                //                                                 |             |------------ crash flush index
                //                                                 |-------------------------- last checkpoint index
                //

                PageCache            pageCache = CreatePageCache();
                GBPTree <KEY, VALUE> index     = CreateIndex(pageCache, file);
                // Execute all actions up to and including last checkpoint ...
                Execute(shuffledLoad.subList(0, lastCheckPointIndex + 1), index);
                // ... a random amount of the remaining "unsafe" actions ...
                int numberOfRemainingActions = shuffledLoad.Count - lastCheckPointIndex - 1;
                int crashFlushIndex          = lastCheckPointIndex + _random.Next(numberOfRemainingActions) + 1;
                Execute(shuffledLoad.subList(lastCheckPointIndex + 1, crashFlushIndex), index);
                // ... flush ...
                pageCache.FlushAndForce();
                // ... execute the remaining actions
                Execute(shuffledLoad.subList(crashFlushIndex, shuffledLoad.Count), index);
                // ... and finally crash
                _fs.snapshot(throwing(() =>
                {
                    index.Dispose();
                    pageCache.Close();
                }));
            }

            // WHEN doing recovery
            IList <Action> recoveryActions;

            if (replayRecoveryExactlyFromCheckpoint)
            {
                recoveryActions = recoveryActions(load, lastCheckPointIndex + 1);
            }
            else
            {
                recoveryActions = recoveryActions(load, _random.Next(lastCheckPointIndex + 1));
            }

            // first crashing during recovery
            int numberOfCrashesDuringRecovery = _random.intBetween(0, 3);

            for (int i = 0; i < numberOfCrashesDuringRecovery; i++)
            {
                using (PageCache pageCache = CreatePageCache(), GBPTree <KEY, VALUE> index = CreateIndex(pageCache, file))
                {
                    int numberOfActionsToRecoverBeforeCrashing = _random.intBetween(1, recoveryActions.Count);
                    Recover(recoveryActions.subList(0, numberOfActionsToRecoverBeforeCrashing), index);
                    // ... crash
                }
            }

            // to finally apply all actions after last checkpoint and verify tree
            using (PageCache pageCache = CreatePageCache(), GBPTree <KEY, VALUE> index = CreateIndex(pageCache, file))
            {
                Recover(recoveryActions, index);

                // THEN
                // we should end up with a consistent index containing all the stuff load says
                index.ConsistencyCheck();
                long[] aggregate = ExpectedSortedAggregatedDataFromGeneratedLoad(load);
                using (RawCursor <Hit <KEY, VALUE>, IOException> cursor = index.Seek(Key(long.MinValue), Key(long.MaxValue)))
                {
                    for (int i = 0; i < aggregate.Length;)
                    {
                        assertTrue(cursor.Next());
                        Hit <KEY, VALUE> hit = cursor.get();
                        AssertEqualsKey(Key(aggregate[i++]), hit.Key());
                        AssertEqualsValue(Value(aggregate[i++]), hit.Value());
                    }
                    assertFalse(cursor.Next());
                }
            }
        }