예제 #1
0
        public void Test_Subspace_Partitioning_With_Binary_Suffix()
        {
            // start from a parent subspace
            var parent = KeySubspace.CreateDynamic(Slice.Empty);

            Assert.That(parent.GetPrefix().ToString(), Is.EqualTo("<empty>"));

            // create a child subspace using a tuple
            var child = parent.Partition[FdbKey.Directory];

            Assert.That(child, Is.Not.Null);
            Assert.That(child.GetPrefix().ToString(), Is.EqualTo("<FE>"));

            // create a key from this child subspace
            var key = child[Slice.FromFixed32(0x01020304)];

            Assert.That(key.ToString(), Is.EqualTo("<FE><04><03><02><01>"));

            // create another child
            var grandChild = child.Partition[Slice.FromStringAscii("hello")];

            Assert.That(grandChild, Is.Not.Null);
            Assert.That(grandChild.GetPrefix().ToString(), Is.EqualTo("<FE>hello"));

            key = grandChild[Slice.FromFixed32(0x01020304)];
            Assert.That(key.ToString(), Is.EqualTo("<FE>hello<04><03><02><01>"));

            // cornercase
            Assert.That(child.Partition[Slice.Empty].GetPrefix(), Is.EqualTo(child.GetPrefix()));
        }
예제 #2
0
        public void Test_TypedKeySpace_T1()
        {
            var location = KeySubspace.CreateTyped <string>(Slice.FromString("PREFIX"));

            Assert.That(location.KeyEncoder, Is.Not.Null, "Should have a Key Encoder");
            Assert.That(location.KeyEncoder.Encoding, Is.SameAs(TuPack.Encoding), "Encoder should use Tuple type system");

            // shortcuts
            Assert.That(location[Slice.FromString("SUFFIX")].ToString(), Is.EqualTo("PREFIXSUFFIX"));
            Assert.That(location.Keys["hello"].ToString(), Is.EqualTo("PREFIX<02>hello<00>"));
            Assert.That(location.Keys[ValueTuple.Create("hello")].ToString(), Is.EqualTo("PREFIX<02>hello<00>"));

            // Encode<T...>(...)
            Assert.That(location.Keys.Encode("hello").ToString(), Is.EqualTo("PREFIX<02>hello<00>"));

            // Pack(ITuple)
            Assert.That(location.Keys.Pack((IVarTuple)STuple.Create("hello")).ToString(), Is.EqualTo("PREFIX<02>hello<00>"));

            // Pack(ValueTuple)
            Assert.That(location.Keys.Pack(ValueTuple.Create("hello")).ToString(), Is.EqualTo("PREFIX<02>hello<00>"));

            // STuple<T...> Decode(...)
            Assert.That(location.Keys.Decode(Slice.Unescape("PREFIX<02>hello<00>")), Is.EqualTo("hello"));

            // Decode(..., out T)
            location.Keys.Decode(Slice.Unescape("PREFIX<02>hello<00>"), out string x);
            Assert.That(x, Is.EqualTo("hello"));
        }
예제 #3
0
        public void Test_Subspace_With_Tuple_Prefix()
        {
            var subspace = KeySubspace.CreateDynamic(TuPack.EncodeKey("hello"));

            Assert.That(subspace.GetPrefix().ToString(), Is.EqualTo("<02>hello<00>"));
            Assert.That(subspace.Copy(), Is.Not.SameAs(subspace));
            Assert.That(subspace.Copy().GetPrefix(), Is.EqualTo(subspace.GetPrefix()));

            // concat(Slice) should append the slice to the tuple prefix directly
            Assert.That(subspace[Slice.FromInt32(0x01020304)].ToString(), Is.EqualTo("<02>hello<00><04><03><02><01>"));
            Assert.That(subspace[Slice.FromStringAscii("world")].ToString(), Is.EqualTo("<02>hello<00>world"));

            // pack(...) should use tuple serialization
            Assert.That(subspace.Keys.Encode(123).ToString(), Is.EqualTo("<02>hello<00><15>{"));
            Assert.That(subspace.Keys.Encode("world").ToString(), Is.EqualTo("<02>hello<00><02>world<00>"));

            // even though the subspace prefix is a tuple, appending to it will only return the new items
            var k = subspace.Keys.Pack(("world", 123, false));

            Assert.That(k.ToString(), Is.EqualTo("<02>hello<00><02>world<00><15>{<14>"));

            // if we unpack the key with the binary prefix, we should get a valid tuple
            var t2 = subspace.Keys.Unpack(k);

            Assert.That(t2, Is.Not.Null);
            Assert.That(t2.Count, Is.EqualTo(3));
            Assert.That(t2.Get <string>(0), Is.EqualTo("world"));
            Assert.That(t2.Get <int>(1), Is.EqualTo(123));
            Assert.That(t2.Get <bool>(2), Is.False);
        }
예제 #4
0
        public void Test_Empty_Subspace_Is_Empty()
        {
            var subspace = KeySubspace.FromKey(Slice.Empty);

            Assert.That(subspace, Is.Not.Null, "FdbSubspace.Empty should not return null");
            Assert.That(subspace.GetPrefix(), Is.EqualTo(Slice.Empty), "FdbSubspace.Empty.Key should be equal to Slice.Empty");
            Assert.That(subspace.Copy(), Is.Not.SameAs(subspace));
        }
예제 #5
0
        public void Test_TypedKeySpace_T2()
        {
            var location = KeySubspace.CreateTyped <string, int>(Slice.FromString("PREFIX"));

            // shortcuts
            Assert.That(location[Slice.FromString("SUFFIX")].ToString(), Is.EqualTo("PREFIXSUFFIX"));
            Assert.That(location.Keys["hello", 123].ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{"));
            Assert.That(location.Keys[("hello", 123)].ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{"));
예제 #6
0
 public void Test_Cannot_Create_Or_Partition_Subspace_With_Slice_Nil()
 {
     Assert.That(() => new KeySubspace(Slice.Nil), Throws.ArgumentException);
     Assert.That(() => KeySubspace.FromKey(Slice.Nil), Throws.ArgumentException);
     //FIXME: typed subspaces refactoring !
     //Assert.That(() => FdbSubspace.Empty.Partition[Slice.Nil], Throws.ArgumentException);
     //Assert.That(() => FdbSubspace.Create(FdbKey.Directory).Partition[Slice.Nil], Throws.ArgumentException);
 }
예제 #7
0
        //TODO: move these methods to FdbTest ?

        /// <summary>Connect to the local test database</summary>
        public static Task <IFdbDatabase> OpenTestDatabaseAsync(CancellationToken ct)
        {
            var options = new FdbConnectionOptions
            {
                ClusterFile    = TestClusterFile,
                DbName         = TestDbName,
                GlobalSpace    = KeySubspace.FromKey(TestGlobalPrefix),
                DefaultTimeout = TimeSpan.FromMilliseconds(DefaultTimeout),
            };

            return(Fdb.OpenAsync(options, ct));
        }
예제 #8
0
        public void Test_Subspace_Copy_Does_Not_Share_Key_Buffer()
        {
            var original = KeySubspace.FromKey(Slice.FromString("Hello"));
            var copy     = original.Copy();

            Assert.That(copy, Is.Not.Null);
            Assert.That(copy, Is.Not.SameAs(original), "Copy should be a new instance");
            Assert.That(copy.GetPrefix(), Is.EqualTo(original.GetPrefix()), "Key should be equal");
            Assert.That(copy.GetPrefix().Array, Is.Not.SameAs(original.GetPrefix().Array), "Key should be a copy of the original");

            Assert.That(copy, Is.EqualTo(original), "Copy and original should be considered equal");
            Assert.That(copy.ToString(), Is.EqualTo(original.ToString()), "Copy and original should have the same string representation");
            Assert.That(copy.GetHashCode(), Is.EqualTo(original.GetHashCode()), "Copy and original should have the same hashcode");
        }
예제 #9
0
        public void Test_DynamicKeySpace_API()
        {
            var location = KeySubspace.CreateDynamic(Slice.FromString("PREFIX"));

            Assert.That(location[Slice.FromString("SUFFIX")].ToString(), Is.EqualTo("PREFIXSUFFIX"));

            // Encode<T...>(...)
            Assert.That(location.Keys.Encode("hello").ToString(), Is.EqualTo("PREFIX<02>hello<00>"));
            Assert.That(location.Keys.Encode("hello", 123).ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{"));
            Assert.That(location.Keys.Encode("hello", 123, "world").ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{<02>world<00>"));
            Assert.That(location.Keys.Encode("hello", 123, "world", 456).ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8>"));
            Assert.That(location.Keys.Encode("hello", 123, "world", 456, "!").ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8><02>!<00>"));
            Assert.That(location.Keys.Encode("hello", 123, "world", 456, "!", 789).ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8><02>!<00><16><03><15>"));

            // Pack(ITuple)
            Assert.That(location.Keys.Pack((IVarTuple)STuple.Create("hello")).ToString(), Is.EqualTo("PREFIX<02>hello<00>"));
            Assert.That(location.Keys.Pack((IVarTuple)STuple.Create("hello", 123)).ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{"));
            Assert.That(location.Keys.Pack((IVarTuple)STuple.Create("hello", 123, "world")).ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{<02>world<00>"));
            Assert.That(location.Keys.Pack((IVarTuple)STuple.Create("hello", 123, "world", 456)).ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8>"));
            Assert.That(location.Keys.Pack((IVarTuple)STuple.Create("hello", 123, "world", 456, "!")).ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8><02>!<00>"));
            Assert.That(location.Keys.Pack((IVarTuple)STuple.Create("hello", 123, "world", 456, "!", 789)).ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8><02>!<00><16><03><15>"));

            // Pack(ValueTuple)
            Assert.That(location.Keys.Pack(ValueTuple.Create("hello")).ToString(), Is.EqualTo("PREFIX<02>hello<00>"));
            Assert.That(location.Keys.Pack(("hello", 123)).ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{"));
            Assert.That(location.Keys.Pack(("hello", 123, "world")).ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{<02>world<00>"));
            Assert.That(location.Keys.Pack(("hello", 123, "world", 456)).ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8>"));
            Assert.That(location.Keys.Pack(("hello", 123, "world", 456, "!")).ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8><02>!<00>"));
            Assert.That(location.Keys.Pack(("hello", 123, "world", 456, "!", 789)).ToString(), Is.EqualTo("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8><02>!<00><16><03><15>"));

            // ITuple Unpack(Slice)
            Assert.That(location.Keys.Unpack(Slice.Unescape("PREFIX<02>hello<00>")), Is.EqualTo(STuple.Create("hello")));
            Assert.That(location.Keys.Unpack(Slice.Unescape("PREFIX<02>hello<00><15>{")), Is.EqualTo(STuple.Create("hello", 123)));
            Assert.That(location.Keys.Unpack(Slice.Unescape("PREFIX<02>hello<00><15>{<02>world<00>")), Is.EqualTo(STuple.Create("hello", 123, "world")));
            Assert.That(location.Keys.Unpack(Slice.Unescape("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8>")), Is.EqualTo(STuple.Create("hello", 123, "world", 456)));
            Assert.That(location.Keys.Unpack(Slice.Unescape("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8><02>!<00>")), Is.EqualTo(STuple.Create("hello", 123, "world", 456, "!")));
            Assert.That(location.Keys.Unpack(Slice.Unescape("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8><02>!<00><16><03><15>")), Is.EqualTo(STuple.Create("hello", 123, "world", 456, "!", 789)));

            // STuple<T...> Decode(Slice)
            Assert.That(location.Keys.Decode <string>(Slice.Unescape("PREFIX<02>hello<00>")), Is.EqualTo("hello"));
            Assert.That(location.Keys.Decode <string, int>(Slice.Unescape("PREFIX<02>hello<00><15>{")), Is.EqualTo(("hello", 123)));
            Assert.That(location.Keys.Decode <string, int, string>(Slice.Unescape("PREFIX<02>hello<00><15>{<02>world<00>")), Is.EqualTo(("hello", 123, "world")));
            Assert.That(location.Keys.Decode <string, int, string, int>(Slice.Unescape("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8>")), Is.EqualTo(("hello", 123, "world", 456)));
            Assert.That(location.Keys.Decode <string, int, string, int, string>(Slice.Unescape("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8><02>!<00>")), Is.EqualTo(("hello", 123, "world", 456, "!")));
            Assert.That(location.Keys.Decode <string, int, string, int, string, int>(Slice.Unescape("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8><02>!<00><16><03><15>")), Is.EqualTo(("hello", 123, "world", 456, "!", 789)));

            // DecodeFirst/DecodeLast
            Assert.That(location.Keys.DecodeFirst <string>(Slice.Unescape("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8><02>!<00><16><03><15>")), Is.EqualTo("hello"));
            Assert.That(location.Keys.DecodeLast <int>(Slice.Unescape("PREFIX<02>hello<00><15>{<02>world<00><16><01><C8><02>!<00><16><03><15>")), Is.EqualTo(789));
        }
        public async Task Test_Can_Open_Database_With_Non_Empty_GlobalSpace()
        {
            // using a tuple prefix
            using (var db = await Fdb.OpenAsync(new FdbConnectionOptions {
                GlobalSpace = KeySubspace.FromKey(TuPack.EncodeKey("test"))
            }, this.Cancellation))
            {
                Assert.That(db, Is.Not.Null);
                Assert.That(db.GlobalSpace, Is.Not.Null);
                Assert.That(db.GlobalSpace.GetPrefix().ToString(), Is.EqualTo("<02>test<00>"));

                var subspace = db.Partition.ByKey("hello");
                Assert.That(subspace.GetPrefix().ToString(), Is.EqualTo("<02>test<00><02>hello<00>"));

                // keys inside the global space are valid
                Assert.That(db.IsKeyValid(TuPack.EncodeKey("test", 123)), Is.True);

                // keys outside the global space are invalid
                Assert.That(db.IsKeyValid(Slice.FromByte(42)), Is.False);
            }

            // using a random binary prefix
            using (var db = await Fdb.OpenAsync(new FdbConnectionOptions {
                GlobalSpace = KeySubspace.FromKey(new byte[] { 42, 255, 0, 90 }.AsSlice())
            }, this.Cancellation))
            {
                Assert.That(db, Is.Not.Null);
                Assert.That(db.GlobalSpace, Is.Not.Null);
                Assert.That(db.GlobalSpace.GetPrefix().ToString(), Is.EqualTo("*<FF><00>Z"));

                var subspace = db.Partition.ByKey("hello");
                Assert.That(subspace.GetPrefix().ToString(), Is.EqualTo("*<FF><00>Z<02>hello<00>"));

                // keys inside the global space are valid
                Assert.That(db.IsKeyValid(Slice.Unescape("*<FF><00>Z123")), Is.True);

                // keys outside the global space are invalid
                Assert.That(db.IsKeyValid(Slice.FromByte(123)), Is.False);
                Assert.That(db.IsKeyValid(Slice.Unescape("*<FF>")), Is.False);
            }
        }
예제 #11
0
        public void Test_Subspace_With_Binary_Prefix()
        {
            var subspace = KeySubspace.CreateDynamic(new byte[] { 42, 255, 0, 127 }.AsSlice());

            Assert.That(subspace.GetPrefix().ToString(), Is.EqualTo("*<FF><00><7F>"));
            Assert.That(subspace.Copy(), Is.Not.SameAs(subspace));
            Assert.That(subspace.Copy().GetPrefix(), Is.EqualTo(subspace.GetPrefix()));

            // concat(Slice) should append the slice to the binary prefix directly
            Assert.That(subspace[Slice.FromInt32(0x01020304)].ToString(), Is.EqualTo("*<FF><00><7F><04><03><02><01>"));
            Assert.That(subspace[Slice.FromStringAscii("hello")].ToString(), Is.EqualTo("*<FF><00><7F>hello"));

            // pack(...) should use tuple serialization
            Assert.That(subspace.Keys.Encode(123).ToString(), Is.EqualTo("*<FF><00><7F><15>{"));
            Assert.That(subspace.Keys.Encode("hello").ToString(), Is.EqualTo("*<FF><00><7F><02>hello<00>"));
            Assert.That(subspace.Keys.Encode(Slice.FromStringAscii("world")).ToString(), Is.EqualTo("*<FF><00><7F><01>world<00>"));
            Assert.That(subspace.Keys.Pack(STuple.Create("hello", 123)).ToString(), Is.EqualTo("*<FF><00><7F><02>hello<00><15>{"));
            Assert.That(subspace.Keys.Pack(("hello", 123)).ToString(), Is.EqualTo("*<FF><00><7F><02>hello<00><15>{"));

            // if we encode a tuple from this subspace, it should keep the binary prefix when converted to a key
            var k = subspace.Keys.Pack(("world", 123, false));

            Assert.That(k.ToString(), Is.EqualTo("*<FF><00><7F><02>world<00><15>{<14>"));

            // if we unpack the key with the binary prefix, we should get a valid tuple
            var t2 = subspace.Keys.Unpack(k);

            Assert.That(t2, Is.Not.Null);
            Assert.That(t2.Count, Is.EqualTo(3));
            Assert.That(t2.Get <string>(0), Is.EqualTo("world"));
            Assert.That(t2.Get <int>(1), Is.EqualTo(123));
            Assert.That(t2.Get <bool>(2), Is.False);

            // ValueTuple
            Assert.That(subspace.Keys.Pack(ValueTuple.Create("hello")).ToString(), Is.EqualTo("*<FF><00><7F><02>hello<00>"));
            Assert.That(subspace.Keys.Pack(("hello", 123)).ToString(), Is.EqualTo("*<FF><00><7F><02>hello<00><15>{"));
            Assert.That(subspace.Keys.Pack(("hello", 123, "world")).ToString(), Is.EqualTo("*<FF><00><7F><02>hello<00><15>{<02>world<00>"));
            Assert.That(subspace.Keys.Pack(("hello", 123, "world", 456)).ToString(), Is.EqualTo("*<FF><00><7F><02>hello<00><15>{<02>world<00><16><01><C8>"));
        }
예제 #12
0
        private static async Task RunMultiClientTest(IFdbDatabase db, KeySubspace location, bool highContention, string desc, int K, int NUM, CancellationToken ct)
        {
            Log("Starting {0} test with {1} threads and {2} iterations", desc, K, NUM);

            var queue = new FdbQueue <string>(location, highContention);
            await db.WriteAsync((tr) => queue.Clear(tr), ct);

            // use a CTS to ensure that everything will stop in case of problems...
            using (var go = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
            {
                var tok = go.Token;

                var pushLock = new AsyncCancelableMutex(tok);
                var popLock  = new AsyncCancelableMutex(tok);

                int pushCount = 0;
                int popCount  = 0;
                int stalls    = 0;

                var pushTreads = Enumerable.Range(0, K)
                                 .Select(async id =>
                {
                    try
                    {
                        // wait for the signal
                        await pushLock.Task.ConfigureAwait(false);

                        var res = new List <string>(NUM);

                        for (int i = 0; i < NUM; i++)
                        {
                            var item = id.ToString() + "." + i.ToString();
                            await db.ReadWriteAsync((tr) => queue.PushAsync(tr, item), tok).ConfigureAwait(false);

                            Interlocked.Increment(ref pushCount);
                            res.Add(item);
                        }

                        return(res);
                    }
                    catch (Exception e)
                    {
                        Log("PushThread[" + id + "] failed: " + e);
                        Assert.Fail("PushThread[" + id + "] failed: " + e.Message);
                        throw;
                    }
                }).ToArray();

                var popThreads = Enumerable.Range(0, K)
                                 .Select(async id =>
                {
                    try
                    {
                        // make everyone wait a bit, to ensure that they all start roughly at the same time
                        await popLock.Task.ConfigureAwait(false);

                        var res = new List <string>(NUM);

                        int i = 0;
                        while (i < NUM)
                        {
                            var item = await queue.PopAsync(db, tok).ConfigureAwait(false);
                            if (item.HasValue)
                            {
                                Interlocked.Increment(ref popCount);
                                res.Add(item.Value);
                                ++i;
                            }
                            else
                            {
                                Interlocked.Increment(ref stalls);
                                await Task.Delay(10).ConfigureAwait(false);
                            }
                        }

                        return(res);
                    }
                    catch (Exception e)
                    {
                        Log("PopThread[" + id + "] failed: " + e);
                        Assert.Fail("PopThread[" + id + "] failed: " + e.Message);
                        throw;
                    }
                }).ToArray();

                var sw = Stopwatch.StartNew();

                pushLock.Set(async: true);
                await Task.Delay(100);

                popLock.Set(async: true);

                //using (var timer = new Timer((_) =>
                //{
                //	var __ = TestHelpers.DumpSubspace(db, location);
                //}, null, 1000, 4000))
                {
                    await Task.WhenAll(pushTreads);

                    await Task.WhenAll(popThreads);
                }

                sw.Stop();
                Log("> Finished {0} test in {1} seconds", desc, sw.Elapsed.TotalSeconds);
                Log("> Pushed {0}, Popped {1} and Stalled {2}", pushCount, popCount, stalls);

                var pushedItems = pushTreads.SelectMany(t => t.Result).ToList();
                var poppedItems = popThreads.SelectMany(t => t.Result).ToList();

                Assert.That(pushCount, Is.EqualTo(K * NUM));
                Assert.That(popCount, Is.EqualTo(K * NUM));

                // all pushed items should have been popped (with no duplicates)
                Assert.That(poppedItems, Is.EquivalentTo(pushedItems));

                // the queue should be empty
                bool empty = await db.ReadAsync((tr) => queue.EmptyAsync(tr), ct);

                Assert.That(empty, Is.True);
            }
        }
예제 #13
0
        private static async Task MainAsync(CancellationToken ct)
        {
            // change the path to the native lib if not default
            if (NATIVE_PATH != null)
            {
                Fdb.Options.SetNativeLibPath(NATIVE_PATH);
            }

            // uncomment this to enable network thread tracing
            // FdbCore.TracePath = Path.Combine(Path.GetTempPath(), "fdb");

            int apiVersion = Fdb.GetMaxApiVersion();

            Console.WriteLine("Max API Version: " + apiVersion);

            try
            {
                Console.WriteLine("Starting network thread...");
                Fdb.Start(Fdb.GetDefaultApiVersion());
                Console.WriteLine("> Up and running");

                Console.WriteLine("Connecting to local cluster...");
                using (var cluster = await Fdb.CreateClusterAsync(CLUSTER_FILE, ct))
                {
                    Console.WriteLine("> Connected!");

                    Console.WriteLine("Opening database 'DB'...");
                    using (var db = await cluster.OpenDatabaseAsync(DB_NAME, KeySubspace.FromKey(Slice.FromByte(253)), false, ct))
                    {
                        Console.WriteLine("> Connected to db '{0}'", db.Name);

                        // get coordinators
                        var cf = await Fdb.System.GetCoordinatorsAsync(db, ct);

                        Console.WriteLine("Coordinators: " + cf.ToString());

                        // clear everything
                        using (var tr = db.BeginTransaction(ct))
                        {
                            Console.WriteLine("Clearing subspace " + db.GlobalSpace + " ...");
                            tr.ClearRange(db.GlobalSpace);
                            await tr.CommitAsync();

                            Console.WriteLine("> Database cleared");
                        }

                        Console.WriteLine();

                        await TestSimpleTransactionAsync(db, ct);

                        await BenchInsertSmallKeysAsync(db, N, 16, ct);                         // some guid
                        await BenchInsertSmallKeysAsync(db, N, 60 * 4, ct);                     // one Int32 per minutes, over an hour
                        await BenchInsertSmallKeysAsync(db, N, 512, ct);                        // small JSON payload
                        await BenchInsertSmallKeysAsync(db, N / 5, 4096, ct);                   // typical small cunk size
                        await BenchInsertSmallKeysAsync(db, N / 100, 65536, ct);                // typical medium chunk size
                        await BenchInsertSmallKeysAsync(db, 20, 100_000, ct);                   // Maximum value size (as of beta 1)

                        // insert keys in parrallel
                        await BenchConcurrentInsert(db, 1, 100, 512, ct);
                        await BenchConcurrentInsert(db, 1, 1_000, 512, ct);
                        await BenchConcurrentInsert(db, 1, 10_000, 512, ct);

                        await BenchConcurrentInsert(db, 1, N, 16, ct);
                        await BenchConcurrentInsert(db, 2, N, 16, ct);
                        await BenchConcurrentInsert(db, 4, N, 16, ct);
                        await BenchConcurrentInsert(db, 8, N, 16, ct);
                        await BenchConcurrentInsert(db, 16, N, 16, ct);

                        await BenchSerialWriteAsync(db, N, ct);
                        await BenchSerialReadAsync(db, N, ct);
                        await BenchConcurrentReadAsync(db, N, ct);

                        await BenchClearAsync(db, N, ct);

                        await BenchUpdateSameKeyLotsOfTimesAsync(db, 1000, ct);

                        await BenchUpdateLotsOfKeysAsync(db, 1000, ct);

                        await BenchBulkInsertThenBulkReadAsync(db, 100_000, 50, 128, ct);
                        await BenchBulkInsertThenBulkReadAsync(db, 100_000, 128, 50, ct);
                        await BenchBulkInsertThenBulkReadAsync(db, 1_000_000, 50, 128, ct);

                        await BenchMergeSortAsync(db, 100, 3, 20, ct);
                        await BenchMergeSortAsync(db, 1_000, 10, 100, ct);
                        await BenchMergeSortAsync(db, 100, 100, 100, ct);
                        await BenchMergeSortAsync(db, 100, 1_000, 100, ct);

                        Console.WriteLine("time to say goodbye...");
                    }
                }
            }
            finally
            {
                Console.WriteLine("### DONE ###");
                Fdb.Stop();
            }
#if DEBUG
            //Console.ReadLine();
#endif
        }
        //TODO: move these methods to FdbTest ?

        /// <summary>Connect to the local test database</summary>
        public static Task <IFdbDatabase> OpenTestDatabaseAsync(CancellationToken ct)
        {
            var subspace = new KeySubspace(TestGlobalPrefix.Memoize());

            return(Fdb.OpenAsync(TestClusterFile, TestDbName, subspace, false, ct));
        }