private async Task <Slice> GetPreviousNodeAsync(IFdbTransaction trans, int level, Slice key)
            {
                // GetPreviousNodeAsync looks for the previous node on a level, but "doesn't care"
                // about the contents of that node. It therefore uses a non-isolated (snaphot)
                // read and explicitly adds a conflict range that is exclusive of the actual,
                // found previous node. This allows an increment of that node not to trigger
                // a transaction conflict. We also add a conflict key on the found previous
                // key in level 0. This allows detection of erasures.

                var k = this.Subspace.Encode(level, key);
                //Console.WriteLine(k);
                //Console.WriteLine("GetPreviousNode(" + level + ", " + key + ")");
                //Console.WriteLine(KeySelector.LastLessThan(k) + " <= x < " + KeySelector.FirstGreaterOrEqual(k));
                var kv = await trans
                         .Snapshot
                         .GetRange(
                    KeySelector.LastLessThan(k),
                    KeySelector.FirstGreaterOrEqual(k)
                    )
                         .FirstAsync()
                         .ConfigureAwait(false);

                //Console.WriteLine("Found " + FdbKey.Dump(kv.Key));

                var prevKey = this.Subspace.DecodeLast <Slice>(kv.Key);

                trans.AddReadConflictRange(kv.Key + FdbKey.MinValue, k);
                trans.AddReadConflictKey(this.Subspace.Encode(0, prevKey));
                return(prevKey);
            }
        private async Task <long> GetNextIndexAsync([NotNull] IFdbReadOnlyTransaction tr, IFdbDynamicSubspace subspace)
        {
            var range = subspace.Keys.ToRange();

            var lastKey = await tr.GetKeyAsync(KeySelector.LastLessThan(range.End)).ConfigureAwait(false);

            if (lastKey < range.Begin)
            {
                return(0);
            }

            return(subspace.Keys.DecodeFirst <long>(lastKey) + 1);
        }
        private async Task PushQueueAsync(IFdbTransaction tr, IDynamicKeySubspace queue, Slice taskId)
        {
            //TODO: use a high contention algo ?
            // - must support Push and Pop
            // - an empty queue must correspond to an empty subspace

            // get the current size of the queue
            var range   = queue.Keys.ToRange();
            var lastKey = await tr.Snapshot.GetKeyAsync(KeySelector.LastLessThan(range.End)).ConfigureAwait(false);

            int count = lastKey < range.Begin ? 0 : queue.Keys.DecodeFirst <int>(lastKey) + 1;

            // set the value
            tr.Set(queue.Keys.Encode(count, GetRandomId()), taskId);
        }
        public async void Test_Case_11()
        {
            using (var zedb = await OpenTestDatabaseAsync())
            {
                var db = FoundationDB.Filters.Logging.FdbLoggingExtensions.Logged(zedb, (tr) => Log(tr.Log.GetTimingsReport(true)));
                {
                    var subspace = db.GlobalSpace;

                    // clear everything and write some values
                    await db.WriteAsync((tr) =>
                    {
                        tr.ClearRange(subspace.Keys.Encode("K0000"), subspace.Keys.Encode("K9999Z"));
                        for (int i = 0; i < 100; i++)
                        {
                            tr.Set(subspace.Keys.Encode("K" + i.ToString("D4")), Slice.FromString("V" + i.ToString("D4")));
                        }
                    }, this.Cancellation);

                    using (var tr = db.BeginTransaction(this.Cancellation))
                    {
                        tr.ClearRange(subspace.Keys.Encode("K0010"), subspace.Keys.Encode("K0020"));
                        tr.ClearRange(subspace.Keys.Encode("K0050"), subspace.Keys.Encode("K0060"));
                        tr.Set(subspace.Keys.Encode("K0021"), Slice.Empty);
                        tr.Set(subspace.Keys.Encode("K0042"), Slice.Empty);

                        await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Keys.Encode("K0005")));

                        await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Keys.Encode("K0010")));

                        await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Keys.Encode("K0015")));

                        await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Keys.Encode("K0022")));

                        await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Keys.Encode("K0049")));

                        await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Keys.Encode("K0050")));

                        await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Keys.Encode("K0055")));

                        await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Keys.Encode("K0061")));

                        //no commit
                    }

                    using (var tr = db.BeginTransaction(this.Cancellation))
                    {
                        //tr.SetOption(FdbTransactionOption.ReadYourWritesDisable);
                        await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Keys.Encode("K0000")));                         // equal=false, offset=1

                        await tr.GetKeyAsync(KeySelector.FirstGreaterThan(subspace.Keys.Encode("K0011")));                            // equal=true, offset=1

                        await tr.GetKeyAsync(KeySelector.LastLessOrEqual(subspace.Keys.Encode("K0022")));                             // equal=true, offset=0

                        await tr.GetKeyAsync(KeySelector.LastLessThan(subspace.Keys.Encode("K0033")));                                // equal=false, offset=0

                        await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Keys.Encode("K0040")) + 1000);                  // equal=false, offset=7 ?

                        await tr.GetKeyAsync(KeySelector.LastLessThan(subspace.Keys.Encode("K0050")) + 1000);                         // equal=false, offset=6 ?
                    }
                }
            }
        }
        public async Task Test_Case_11()
        {
            using (var db = await OpenTestPartitionAsync())
            {
                db.SetDefaultLogHandler((log) => Log(log.GetTimingsReport(true)));

                var location = db.Root;

                // clear everything and write some values
                await db.WriteAsync(async tr =>
                {
                    var subspace = await location.Resolve(tr);
                    tr.ClearRange(subspace.Encode("K0000"), subspace.Encode("K9999Z"));
                    for (int i = 0; i < 100; i++)
                    {
                        tr.Set(subspace.Encode("K" + i.ToString("D4")), Value("V" + i.ToString("D4")));
                    }
                }, this.Cancellation);

                using (var tr = await db.BeginTransactionAsync(this.Cancellation))
                {
                    var subspace = await location.Resolve(tr);

                    tr.ClearRange(subspace.Encode("K0010"), subspace.Encode("K0020"));
                    tr.ClearRange(subspace.Encode("K0050"), subspace.Encode("K0060"));
                    tr.Set(subspace.Encode("K0021"), Slice.Empty);
                    tr.Set(subspace.Encode("K0042"), Slice.Empty);

                    await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Encode("K0005")));

                    await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Encode("K0010")));

                    await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Encode("K0015")));

                    await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Encode("K0022")));

                    await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Encode("K0049")));

                    await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Encode("K0050")));

                    await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Encode("K0055")));

                    await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Encode("K0061")));

                    //no commit
                }

                using (var tr = await db.BeginTransactionAsync(this.Cancellation))
                {
                    var subspace = await location.Resolve(tr);

                    //tr.SetOption(FdbTransactionOption.ReadYourWritesDisable);
                    await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Encode("K0000")));                     // equal=false, offset=1

                    await tr.GetKeyAsync(KeySelector.FirstGreaterThan(subspace.Encode("K0011")));                        // equal=true, offset=1

                    await tr.GetKeyAsync(KeySelector.LastLessOrEqual(subspace.Encode("K0022")));                         // equal=true, offset=0

                    await tr.GetKeyAsync(KeySelector.LastLessThan(subspace.Encode("K0033")));                            // equal=false, offset=0

                    await tr.GetKeyAsync(KeySelector.FirstGreaterOrEqual(subspace.Encode("K0040")) + 1000);              // equal=false, offset=7 ?

                    await tr.GetKeyAsync(KeySelector.LastLessThan(subspace.Encode("K0050")) + 1000);                     // equal=false, offset=6 ?
                }
            }
        }