public override FdbRangeQuery <KeyValuePair <Slice, Slice> > GetRange(FdbKeySelector beginInclusive, FdbKeySelector endExclusive, FdbRangeOptions options = null)
            {
                m_parent.ThrowIfDisposed();
                var query = m_transaction.GetRange(beginInclusive, endExclusive, options);

                return(query.UseTransaction(this));
            }
        public async Task Test_GetKey()
        {
            Slice key;
            Slice value;

            using (var db = MemoryDatabase.CreateNew("DB"))
            {
                using (var tr = db.BeginTransaction(this.Cancellation))
                {
                    tr.Set(db.Pack(0), Slice.FromString("first"));
                    tr.Set(db.Pack(10), Slice.FromString("ten"));
                    tr.Set(db.Pack(20), Slice.FromString("ten ten"));
                    tr.Set(db.Pack(42), Slice.FromString("narf!"));
                    tr.Set(db.Pack(100), Slice.FromString("a hundred missipis"));
                    await tr.CommitAsync();
                }

                db.Debug_Dump();

                using (var tr = db.BeginTransaction(this.Cancellation))
                {
                    value = await tr.GetAsync(db.Pack(42));

                    Console.WriteLine(value);
                    Assert.That(value.ToString(), Is.EqualTo("narf!"));

                    key = await tr.GetKeyAsync(FdbKeySelector.FirstGreaterOrEqual(db.Pack(42)));

                    Assert.That(key, Is.EqualTo(db.Pack(42)));

                    key = await tr.GetKeyAsync(FdbKeySelector.FirstGreaterThan(db.Pack(42)));

                    Assert.That(key, Is.EqualTo(db.Pack(100)));

                    key = await tr.GetKeyAsync(FdbKeySelector.LastLessOrEqual(db.Pack(42)));

                    Assert.That(key, Is.EqualTo(db.Pack(42)));

                    key = await tr.GetKeyAsync(FdbKeySelector.LastLessThan(db.Pack(42)));

                    Assert.That(key, Is.EqualTo(db.Pack(20)));

                    var keys = await tr.GetKeysAsync(new[]
                    {
                        FdbKeySelector.FirstGreaterOrEqual(db.Pack(42)),
                        FdbKeySelector.FirstGreaterThan(db.Pack(42)),
                        FdbKeySelector.LastLessOrEqual(db.Pack(42)),
                        FdbKeySelector.LastLessThan(db.Pack(42))
                    });

                    Assert.That(keys.Length, Is.EqualTo(4));
                    Assert.That(keys[0], Is.EqualTo(db.Pack(42)));
                    Assert.That(keys[1], Is.EqualTo(db.Pack(100)));
                    Assert.That(keys[2], Is.EqualTo(db.Pack(42)));
                    Assert.That(keys[3], Is.EqualTo(db.Pack(20)));

                    await tr.CommitAsync();
                }
            }
        }
        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.Pack(level, key);
            //Console.WriteLine(k);
            //Console.WriteLine("GetPreviousNode(" + level + ", " + key + ")");
            //Console.WriteLine(FdbKeySelector.LastLessThan(k) + " <= x < " + FdbKeySelector.FirstGreaterOrEqual(k));
            var kv = await trans
                     .Snapshot
                     .GetRange(
                FdbKeySelector.LastLessThan(k),
                FdbKeySelector.FirstGreaterOrEqual(k)
                )
                     .FirstAsync()
                     .ConfigureAwait(false);

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

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

            trans.AddReadConflictRange(kv.Key + FdbKey.MinValue, k);
            trans.AddReadConflictKey(this.Subspace.Pack(0, prevKey));
            return(prevKey);
        }
Example #4
0
        public async Task <FdbRangeChunk> GetRangeAsync(FdbKeySelector beginInclusive, FdbKeySelector endExclusive, FdbRangeOptions options, int iteration, bool snapshot, CancellationToken cancellationToken)
        {
            Contract.Requires(beginInclusive.Key.HasValue && endExclusive.Key.HasValue && options != null);

            cancellationToken.ThrowIfCancellationRequested();

            //TODO: check system keys

            //Trace.WriteLine("## GetRange " + beginInclusive + " <= k < " + endExclusive + ", limit=" + options.Limit + ", reverse=" + options.Reverse + ", snapshot=" + snapshot);

            lock (m_buffer)
            {
                beginInclusive = m_buffer.InternSelector(beginInclusive);
                endExclusive   = m_buffer.InternSelector(endExclusive);
            }

            // we need the read version
            EnsureHasReadVersion();

            options = FdbRangeOptions.EnsureDefaults(options, null, null, FdbStreamingMode.Iterator, false);
            options.EnsureLegalValues();

            var result = await m_db.GetRangeAtVersion(beginInclusive, endExclusive, options.Limit ?? 0, options.TargetBytes ?? 0, options.Mode.Value, iteration, options.Reverse.Value, m_readVersion.Value).ConfigureAwait(false);

            if (!snapshot)
            {
                lock (m_lock)
                {
                    //TODO: use the result to create the conflict range (between the resolver key and the returned key)
                    //AddReadConflict_NeedsLocking(range);
                }
            }
            return(result);
        }
 public GetRangeCommand(FdbKeySelector begin, FdbKeySelector end, FdbRangeOptions options, int iteration)
 {
     this.Begin     = begin;
     this.End       = end;
     this.Options   = options;
     this.Iteration = iteration;
 }
 public override Task <FdbRangeChunk> GetRangeAsync(FdbKeySelector beginInclusive, FdbKeySelector endExclusive, FdbRangeOptions options = null, int iteration = 0)
 {
     return(ExecuteAsync(
                new FdbTransactionLog.GetRangeCommand(m_parent.Grab(beginInclusive), m_parent.Grab(endExclusive), options, iteration),
                (tr, cmd) => tr.GetRangeAsync(cmd.Begin, cmd.End, cmd.Options, cmd.Iteration)
                ));
 }
        private async Task <Chunk> GetChunkAtAsync([NotNull] IFdbTransaction trans, long offset)
        {
            Contract.Requires(trans != null && offset >= 0);

            var chunkKey = await trans.GetKeyAsync(FdbKeySelector.LastLessOrEqual(DataKey(offset))).ConfigureAwait(false);

            if (chunkKey.IsNull)
            {             // nothing before (sparse)
                return(default(Chunk));
            }

            if (chunkKey < DataKey(0))
            {             // off beginning
                return(default(Chunk));
            }

            long chunkOffset = DataKeyOffset(chunkKey);

            Slice chunkData = await trans.GetAsync(chunkKey).ConfigureAwait(false);

            if (chunkOffset + chunkData.Count <= offset)
            {             // in sparse region after chunk
                return(default(Chunk));
            }

            return(new Chunk(chunkKey, chunkData, chunkOffset));
        }
 public override Task <Slice> GetKeyAsync(FdbKeySelector selector)
 {
     return(ExecuteAsync(
                new FdbTransactionLog.GetKeyCommand(m_parent.Grab(selector)),
                (tr, cmd) => tr.GetKeyAsync(cmd.Selector)
                ));
 }
		private FdbKeySelector Encode(FdbKeySelector selector)
		{
			return new FdbKeySelector(
				m_prefix.Concat(selector.Key),
				selector.OrEqual,
				selector.Offset
			);
		}
		/// <summary>Copy a key selector into the buffer, and return a new identical selector</summary>
		/// <param name="selector">Key selector to copy to the buffer</param>
		/// <returns>Equivalent key selector that is backed by the buffer.</returns>
		public FdbKeySelector InternSelector(FdbKeySelector selector)
		{
			return new FdbKeySelector(
				Intern(selector.Key, aligned: true),
				selector.OrEqual,
				selector.Offset
			);
		}
 private FdbKeySelector Encode(FdbKeySelector selector)
 {
     return(new FdbKeySelector(
                m_prefix.ConcatKey(selector.Key),
                selector.OrEqual,
                selector.Offset
                ));
 }
        public Task <Slice> GetKeyAsync(FdbKeySelector selector, bool snapshot, CancellationToken cancellationToken)
        {
            var future = FdbNative.TransactionGetKey(m_handle, selector, snapshot);

            return(FdbFuture.CreateTaskFromHandle(
                       future,
                       (h) => GetKeyResult(h),
                       cancellationToken
                       ));
        }
        public override FdbRangeQuery <KeyValuePair <Slice, Slice> > GetRange(FdbKeySelector beginInclusive, FdbKeySelector endExclusive, FdbRangeOptions options = null)
        {
            ThrowIfDisposed();

            var query = m_transaction.GetRange(beginInclusive, endExclusive, options);

            // this method does not execute immediately, so we don't need to record any operation here, only when GetRangeAsync() is called (by ToListAsync() or any other LINQ operator)
            // we must override the transaction used by the query, so that we are notified when this happens
            return(query.UseTransaction(this));
        }
        private async Task <long> GetNextIndexAsync([NotNull] IFdbReadOnlyTransaction tr, IFdbDynamicSubspace subspace)
        {
            var range = subspace.Keys.ToRange();

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

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

            return(subspace.Keys.DecodeFirst <long>(lastKey) + 1);
        }
        private async Task Scenario5(IFdbTransaction tr)
        {
            var location = FdbSubspace.Create(Slice.FromAscii("TEST"));

            //tr.Set(location.Pack(42), Slice.FromString("42"));
            //tr.Set(location.Pack(50), Slice.FromString("50"));
            //tr.Set(location.Pack(60), Slice.FromString("60"));

            var x = await tr.GetKeyAsync(FdbKeySelector.LastLessThan(location.Pack(49)));

            Console.WriteLine(x);

            tr.Set(location.Pack("FOO"), Slice.FromString("BAR"));
        }
        private FdbKeySelector[] Grab(FdbKeySelector[] selectors)
        {
            if (selectors == null || selectors.Length == 0)
            {
                return(null);
            }

            var res = new FdbKeySelector[selectors.Length];

            for (int i = 0; i < selectors.Length; i++)
            {
                res[i] = Grab(selectors[i]);
            }
            return(res);
        }
        private async Task PushQueueAsync(IFdbTransaction tr, FdbSubspace 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.ToRange();
            var lastKey = await tr.Snapshot.GetKeyAsync(FdbKeySelector.LastLessThan(range.End)).ConfigureAwait(false);

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

            // set the value
            tr.Set(queue.Pack(count, GetRandomId()), taskId);
        }
Example #18
0
        private async Task <long> ComputeSizeAsync(IFdbReadOnlyTransaction tr)
        {
            Contract.Requires(tr != null);

            var keyRange = this.Subspace.Keys.ToRange();

            var lastKey = await tr.GetKeyAsync(FdbKeySelector.LastLessOrEqual(keyRange.End)).ConfigureAwait(false);

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

            return(this.Subspace.Keys.DecodeFirst <long>(lastKey) + 1);
        }
Example #19
0
        public async Task <Slice[]> GetKeysAsync(FdbKeySelector[] selectors, bool snapshot, CancellationToken cancellationToken)
        {
            Contract.Requires(selectors != null);

            cancellationToken.ThrowIfCancellationRequested();

            // order and check the keys
            var ordered = new FdbKeySelector[selectors.Length];

            for (int i = 0; i < selectors.Length; i++)
            {
                if (selectors[i].Key.IsNullOrEmpty)
                {
                    throw new ArgumentException("Key cannot be null or empty");
                }
                //CheckAccessToSystemKeys(key);
                ordered[i] = selectors[i];
            }
            if (ordered.Length > 1)
            {             // the db expects the keys to be sorted
                Array.Sort(ordered, SelectorKeyComparer.Default);
            }

            // we need the read version
            EnsureHasReadVersion();

            lock (m_buffer)
            {
                for (int i = 0; i < ordered.Length; i++)
                {
                    ordered[i] = m_buffer.InternSelector(ordered[i]);
                }
            }

            var results = await m_db.GetKeysAtVersion(ordered, m_readVersion.Value).ConfigureAwait(false);

            if (!snapshot)
            {
                lock (m_lock)
                {
#if !DEBUGz
                    throw new NotImplementedException("TODO: track read ranges in GetKeysAsync() !");
#endif
                }
            }

            return(results);
        }
        public async Task <long?> Rank([NotNull] IFdbReadOnlyTransaction trans, Slice key)
        {
            if (trans == null)
            {
                throw new ArgumentNullException("trans");
            }
            if (key.IsNull)
            {
                throw new ArgumentException("Empty key not allowed in set", "key");
            }

            if (!(await ContainsAsync(trans, key).ConfigureAwait(false)))
            {
                return(default(long?));
            }

            long r       = 0;
            var  rankKey = Slice.Empty;

            for (int level = MAX_LEVELS - 1; level >= 0; level--)
            {
                var  lss       = this.Subspace.Partition(level);
                long lastCount = 0;
                var  kcs       = await trans.GetRange(
                    FdbKeySelector.FirstGreaterOrEqual(lss.Pack(rankKey)),
                    FdbKeySelector.FirstGreaterThan(lss.Pack(key))
                    ).ToListAsync().ConfigureAwait(false);

                foreach (var kc in kcs)
                {
                    rankKey   = lss.UnpackSingle <Slice>(kc.Key);
                    lastCount = DecodeCount(kc.Value);
                    r        += lastCount;
                }
                r -= lastCount;
                if (rankKey == key)
                {
                    break;
                }
            }
            return(r);
        }
Example #21
0
        public FdbRangeQuery <TId> LookupLessThan([NotNull] IFdbReadOnlyTransaction trans, TValue value, bool orEqual, bool reverse = false)
        {
            var prefix = this.Location.Partial.Keys.Encode(value);

            if (orEqual)
            {
                prefix = FdbKey.Increment(prefix);
            }

            var space = new FdbKeySelectorPair(
                FdbKeySelector.FirstGreaterOrEqual(this.Location.ToRange().Begin),
                FdbKeySelector.FirstGreaterThan(prefix)
                );

            return(trans
                   .GetRange(space, new FdbRangeOptions {
                Reverse = reverse
            })
                   .Select((kvp) => this.Location.Keys.Decode(kvp.Key).Item2));
        }
		private FdbKeySelector[] Encode(FdbKeySelector[] selectors)
		{
			var keys = new Slice[selectors.Length];
			for (int i = 0; i < selectors.Length;i++)
			{
				keys[i] = selectors[i].Key;
			}
			keys = m_prefix.ConcatRange(keys);

			var res = new FdbKeySelector[selectors.Length];
			for (int i = 0; i < selectors.Length; i++)
			{
				res[i] = new FdbKeySelector(
					keys[i],
					selectors[i].OrEqual,
					selectors[i].Offset
				);
			}
			return res;
		}
        /// <summary>Asynchronously fetch a new page of results</summary>
        /// <returns>True if Chunk contains a new page of results. False if all results have been read.</returns>
        public Task <FdbRangeChunk> GetRangeAsync(FdbKeySelector begin, FdbKeySelector end, FdbRangeOptions options, int iteration, bool snapshot, CancellationToken cancellationToken)
        {
            Contract.Requires(options != null);

            bool reversed = options.Reverse ?? false;
            var  future   = FdbNative.TransactionGetRange(m_handle, begin, end, options.Limit ?? 0, options.TargetBytes ?? 0, options.Mode ?? FdbStreamingMode.Iterator, iteration, snapshot, reversed);

            return(FdbFuture.CreateTaskFromHandle(
                       future,
                       (h) =>
            {
                // TODO: quietly return if disposed

                bool hasMore;
                var chunk = GetKeyValueArrayResult(h, out hasMore);

                return new FdbRangeChunk(hasMore, chunk, iteration, reversed);
            },
                       cancellationToken
                       ));
        }
        private FdbKeySelector[] Encode(FdbKeySelector[] selectors)
        {
            var keys = new Slice[selectors.Length];

            for (int i = 0; i < selectors.Length; i++)
            {
                keys[i] = selectors[i].Key;
            }
            keys = m_prefix.ConcatKeys(keys);

            var res = new FdbKeySelector[selectors.Length];

            for (int i = 0; i < selectors.Length; i++)
            {
                res[i] = new FdbKeySelector(
                    keys[i],
                    selectors[i].OrEqual,
                    selectors[i].Offset
                    );
            }
            return(res);
        }
        public async Task MiniBench()
        {
            const int M       = 1 * 1000 * 1000;
            const int B       = 100;
            const int ENTROPY = 10 * 1000;

            const int  T         = M / B;
            const int  KEYSIZE   = 10;
            const int  VALUESIZE = 100;
            const bool RANDOM    = false;

            var rnd = new Random();

            //WARMUP
            using (var db = MemoryDatabase.CreateNew("FOO"))
            {
                await db.WriteAsync((tr) => tr.Set(db.Keys.Encode("hello"), Slice.FromString("world")), this.Cancellation);

                Slice.Random(rnd, KEYSIZE);
                Slice.Random(rnd, VALUESIZE);
            }

            Log("Inserting {0}-bytes {1} keys / {2}-bytes values, in {3:N0} transactions", KEYSIZE, RANDOM ? "random" : "ordered", VALUESIZE, T);

            bool   random = RANDOM;
            string fmt    = "D" + KEYSIZE;

            using (var db = MemoryDatabase.CreateNew("FOO"))
            {
                DumpMemory(collect: true);

                long total = 0;

                var payload = new byte[ENTROPY + VALUESIZE];
                rnd.NextBytes(payload);
                // help with compression by doubling every byte
                for (int i = 0; i < payload.Length; i += 2)
                {
                    payload[i + 1] = payload[i];
                }

                var sw = Stopwatch.StartNew();
                sw.Stop();

                sw.Restart();
                for (int i = 0; i < T; i++)
                {
                    using (var tr = db.BeginTransaction(this.Cancellation))
                    {
                        for (int j = 0; j < B; j++)
                        {
                            Slice key;
                            if (random)
                            {
                                do
                                {
                                    key = Slice.Random(rnd, KEYSIZE);
                                }while (key[0] == 255);
                            }
                            else
                            {
                                int x = i * B + j;
                                //x = x % 1000;
                                key = Slice.FromString(x.ToString(fmt));
                            }

                            tr.Set(key, Slice.Create(payload, rnd.Next(ENTROPY), VALUESIZE));
                            Interlocked.Increment(ref total);
                        }
                        await tr.CommitAsync().ConfigureAwait(false);
                    }
                    if (i % 1000 == 0)
                    {
                        Console.Write(".");                                   // + (i * B).ToString("D10"));
                    }
                }

                sw.Stop();
                Log("done");
                Log("* Inserted: {0:N0} keys", total);
                Log("* Elapsed : {0:N3} sec", sw.Elapsed.TotalSeconds);
                Log("* TPS: {0:N0} transactions/sec", T / sw.Elapsed.TotalSeconds);
                Log("* KPS: {0:N0} keys/sec", total / sw.Elapsed.TotalSeconds);
                Log("* BPS: {0:N0} bytes/sec", (total * (KEYSIZE + VALUESIZE)) / sw.Elapsed.TotalSeconds);

                DumpMemory(collect: true);

                db.Debug_Dump(false);

                DumpResult("WriteSeq" + B, total, total / B, sw.Elapsed);

                string path = @".\\minibench.pndb";
                Log("Saving {0} ...", path);
                sw.Restart();
                await db.SaveSnapshotAsync(path);

                sw.Stop();
                Log("* Saved {0:N0} bytes in {1:N3} sec", new System.IO.FileInfo(path).Length, sw.Elapsed.TotalSeconds);

                Log("Warming up reads...");
                var data = await db.GetValuesAsync(Enumerable.Range(0, 100).Select(i => Slice.FromString(i.ToString(fmt))), this.Cancellation);

                Log("Starting read tests...");

                #region sequential reads

                sw.Restart();
                for (int i = 0; i < total; i += 10)
                {
                    using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                    {
                        await tr.GetValuesAsync(Enumerable.Range(i, 10).Select(x => Slice.FromString(x.ToString(fmt)))).ConfigureAwait(false);
                    }
                }
                sw.Stop();
                DumpResult("SeqRead10", total, total / 10, sw.Elapsed);

                sw.Restart();
                for (int i = 0; i < total; i += 10)
                {
                    using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                    {
                        await tr.Snapshot.GetValuesAsync(Enumerable.Range(i, 10).Select(x => Slice.FromString(x.ToString(fmt)))).ConfigureAwait(false);
                    }
                }
                sw.Stop();
                DumpResult("SeqRead10S", total, total / 10, sw.Elapsed);

                sw.Restart();
                for (int i = 0; i < total; i += 10)
                {
                    using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                    {
                        int x = i;
                        int y = i + 10;
                        await tr.GetRangeAsync(
                            FdbKeySelector.FirstGreaterOrEqual(Slice.FromString(x.ToString(fmt))),
                            FdbKeySelector.FirstGreaterOrEqual(Slice.FromString(y.ToString(fmt)))
                            ).ConfigureAwait(false);
                    }
                }
                sw.Stop();
                DumpResult("SeqRead10R", total, total / 10, sw.Elapsed);

                sw.Restart();
                for (int i = 0; i < total; i += 100)
                {
                    using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                    {
                        await tr.GetValuesAsync(Enumerable.Range(i, 100).Select(x => Slice.FromString(x.ToString(fmt)))).ConfigureAwait(false);
                    }
                }
                sw.Stop();
                DumpResult("SeqRead100", total, total / 100, sw.Elapsed);

                sw.Restart();
                for (int i = 0; i < total; i += 100)
                {
                    using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                    {
                        await tr.Snapshot.GetValuesAsync(Enumerable.Range(i, 100).Select(x => Slice.FromString(x.ToString(fmt)))).ConfigureAwait(false);
                    }
                }
                sw.Stop();
                DumpResult("SeqRead100S", total, total / 100, sw.Elapsed);

                sw.Restart();
                for (int i = 0; i < total; i += 100)
                {
                    using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                    {
                        int x = i;
                        int y = i + 100;
                        await tr.GetRangeAsync(
                            FdbKeySelector.FirstGreaterOrEqual(Slice.FromString(x.ToString(fmt))),
                            FdbKeySelector.FirstGreaterOrEqual(Slice.FromString(y.ToString(fmt)))
                            ).ConfigureAwait(false);
                    }
                }
                sw.Stop();
                DumpResult("SeqRead100R", total, total / 100, sw.Elapsed);

                sw.Restart();
                for (int i = 0; i < total; i += 100)
                {
                    using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                    {
                        int x = i;
                        int y = i + 100;
                        await tr.Snapshot.GetRangeAsync(
                            FdbKeySelector.FirstGreaterOrEqual(Slice.FromString(x.ToString(fmt))),
                            FdbKeySelector.FirstGreaterOrEqual(Slice.FromString(y.ToString(fmt)))
                            ).ConfigureAwait(false);
                    }
                }
                sw.Stop();
                DumpResult("SeqRead100RS", total, total / 100, sw.Elapsed);

                sw.Restart();
                for (int i = 0; i < total; i += 1000)
                {
                    using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                    {
                        await tr.GetValuesAsync(Enumerable.Range(i, 1000).Select(x => Slice.FromString(x.ToString(fmt)))).ConfigureAwait(false);
                    }
                }
                sw.Stop();
                DumpResult("SeqRead1k", total, total / 1000, sw.Elapsed);

                #endregion

                DumpMemory();

                #region random reads

                //sw.Restart();
                //for (int i = 0; i < total; i++)
                //{
                //	using (var tr = db.BeginReadOnlyTransaction())
                //	{
                //		int x = rnd.Next((int)total);
                //		await tr.GetAsync(Slice.FromString(x.ToString(fmt)));
                //	}
                //}
                //sw.Stop();
                //Log("RndRead1   : " + total.ToString("N0") + " keys in " + sw.Elapsed.TotalSeconds.ToString("N3") + " sec => " + (total / sw.Elapsed.TotalSeconds).ToString("N0") + " kps");

                sw.Restart();
                for (int i = 0; i < total; i += 10)
                {
                    using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                    {
                        await tr.GetValuesAsync(Enumerable.Range(i, 10).Select(x => Slice.FromString(rnd.Next((int)total).ToString(fmt)))).ConfigureAwait(false);
                    }
                }
                sw.Stop();
                //Log("RndRead10  : " + total.ToString("N0") + " keys in " + sw.Elapsed.TotalSeconds.ToString("N3") + " sec => " + (total / sw.Elapsed.TotalSeconds).ToString("N0") + " kps, " + (total / (10 * sw.Elapsed.TotalSeconds)).ToString("N0") + " tps");
                DumpResult("RndRead10", total, total / 10, sw.Elapsed);

                sw.Restart();
                for (int i = 0; i < total; i += 10)
                {
                    using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                    {
                        await tr.Snapshot.GetValuesAsync(Enumerable.Range(i, 10).Select(x => Slice.FromString(rnd.Next((int)total).ToString(fmt)))).ConfigureAwait(false);
                    }
                }
                sw.Stop();
                //Log("RndRead10S : " + total.ToString("N0") + " keys in " + sw.Elapsed.TotalSeconds.ToString("N3") + " sec => " + (total / sw.Elapsed.TotalSeconds).ToString("N0") + " kps, " + (total / (10 * sw.Elapsed.TotalSeconds)).ToString("N0") + " tps");
                DumpResult("RndRead10S", total, total / 10, sw.Elapsed);

                sw.Restart();
                for (int i = 0; i < total; i += 10)
                {
                    using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                    {
                        int x = rnd.Next((int)total - 10);
                        int y = x + 10;
                        await tr.GetRangeAsync(
                            FdbKeySelector.FirstGreaterOrEqual(Slice.FromString(x.ToString(fmt))),
                            FdbKeySelector.FirstGreaterOrEqual(Slice.FromString(y.ToString(fmt)))
                            ).ConfigureAwait(false);
                    }
                }
                sw.Stop();
                //Log("RndRead10R : " + total.ToString("N0") + " keys in " + sw.Elapsed.TotalSeconds.ToString("N3") + " sec => " + (total / sw.Elapsed.TotalSeconds).ToString("N0") + " kps, " + (total / (10 * sw.Elapsed.TotalSeconds)).ToString("N0") + " tps");
                DumpResult("RndRead10R", total, total / 10, sw.Elapsed);

                sw.Restart();
                for (int i = 0; i < total; i += 100)
                {
                    using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                    {
                        await tr.GetValuesAsync(Enumerable.Range(i, 100).Select(x => Slice.FromString(rnd.Next((int)total).ToString(fmt)))).ConfigureAwait(false);
                    }
                }
                sw.Stop();
                //Log("RndRead100 : " + total.ToString("N0") + " keys in " + sw.Elapsed.TotalSeconds.ToString("N3") + " sec => " + (total / sw.Elapsed.TotalSeconds).ToString("N0") + " kps, " + (total / (100 * sw.Elapsed.TotalSeconds)).ToString("N0") + " tps");
                DumpResult("RndRead100", total, total / 100, sw.Elapsed);

                sw.Restart();
                for (int i = 0; i < total; i += 1000)
                {
                    using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                    {
                        await tr.GetValuesAsync(Enumerable.Range(i, 1000).Select(x => Slice.FromString(rnd.Next((int)total).ToString(fmt)))).ConfigureAwait(false);
                    }
                }
                sw.Stop();
                //Log("RndRead1k  : " + total.ToString("N0") + " keys in " + sw.Elapsed.TotalSeconds.ToString("N3") + " sec => " + (total / sw.Elapsed.TotalSeconds).ToString("N0") + " kps, " + (total / (1000 * sw.Elapsed.TotalSeconds)).ToString("N0") + " tps");
                DumpResult("RndRead1k", total, total / 1000, sw.Elapsed);

                #endregion

                DumpMemory();

                #region Parallel Reads...

                int CPUS = Environment.ProcessorCount;

                long read  = 0;
                var  mre   = new ManualResetEvent(false);
                var  tasks = Enumerable
                             .Range(0, CPUS)
                             .Select(k => Task.Run(async() =>
                {
                    var rndz = new Random(k);
                    mre.WaitOne();

                    int keys = 0;
                    for (int j = 0; j < 20; j++)
                    {
                        for (int i = 0; i < total / CPUS; i += 100)
                        {
                            int pp = i;                                    // rndz.Next((int)total - 10);
                            using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                            {
                                var res = await tr.GetValuesAsync(Enumerable.Range(i, 100).Select(x => Slice.FromString((pp + x).ToString(fmt)))).ConfigureAwait(false);
                                keys   += res.Length;
                            }
                        }
                    }
                    Interlocked.Add(ref read, keys);
                    return(keys);
                })).ToArray();

                sw.Restart();
                mre.Set();
                await Task.WhenAll(tasks);

                sw.Stop();
                mre.Dispose();
                //Log("ParaSeqRead: " + read.ToString("N0") + " keys in " + sw.Elapsed.TotalSeconds.ToString("N3") + " sec => " + (read / sw.Elapsed.TotalSeconds).ToString("N0") + " kps");
                DumpResult("ParaSeqRead", read, read / 100, sw.Elapsed);

                read  = 0;
                mre   = new ManualResetEvent(false);
                tasks = Enumerable
                        .Range(0, CPUS)
                        .Select(k => Task.Run(async() =>
                {
                    var rndz = new Random(k);
                    mre.WaitOne();

                    int keys = 0;
                    for (int j = 0; j < 20; j++)
                    {
                        for (int i = 0; i < total / CPUS; i += 100)
                        {
                            int pp = i;                                    // rndz.Next((int)total - 100);
                            using (var tr = db.BeginReadOnlyTransaction(this.Cancellation))
                            {
                                var res = await tr.GetRangeAsync(
                                    FdbKeySelector.FirstGreaterOrEqual(Slice.FromString(pp.ToString(fmt))),
                                    FdbKeySelector.FirstGreaterOrEqual(Slice.FromString((pp + 100).ToString(fmt)))
                                    ).ConfigureAwait(false);

                                keys += res.Count;
                            }
                        }
                    }
                    Interlocked.Add(ref read, keys);
                    return(keys);
                })).ToArray();

                sw.Restart();
                mre.Set();
                await Task.WhenAll(tasks);

                sw.Stop();
                mre.Dispose();
                DumpResult("ParaSeqRange", read, read / 100, sw.Elapsed);
                #endregion

                DumpMemory();
            }
        }
 public GetKeyCommand(FdbKeySelector selector)
 {
     this.Selector = selector;
 }
		public virtual Task<Slice> GetKeyAsync(FdbKeySelector selector)
		{
			ThrowIfDisposed();
			return m_transaction.GetKeyAsync(selector);
		}
        public async Task Run(IFdbDatabase db, TextWriter log, CancellationToken ct)
        {
            // estimate the number of machines...
            Console.WriteLine("# Detecting cluster topology...");
            var servers = await db.QueryAsync(tr => tr
                                              .WithReadAccessToSystemKeys()
                                              .GetRange(FdbKeyRange.StartsWith(Fdb.System.ServerList))
                                              .Select(kvp => new
            {
                Node       = kvp.Value.Substring(8, 16).ToHexaString(),
                Machine    = kvp.Value.Substring(24, 16).ToHexaString(),
                DataCenter = kvp.Value.Substring(40, 16).ToHexaString()
            }),
                                              ct
                                              );

            var numNodes    = servers.Select(s => s.Node).Distinct().Count();
            var numMachines = servers.Select(s => s.Machine).Distinct().Count();
            var numDCs      = servers.Select(s => s.DataCenter).Distinct().Count();

            Console.WriteLine("# > Found " + numNodes + " process(es) on " + numMachines + " machine(s) in " + numDCs + " datacenter(s)");
            Console.WriteLine("# Reading list of shards...");
            // dump keyServers
            var ranges = await Fdb.System.GetChunksAsync(db, FdbKey.MinValue, FdbKey.MaxValue, ct);

            Console.WriteLine("# > Found " + ranges.Count + " shards:");

            // take a sample
            var rnd = new Random(1234);
            int sz  = Math.Max((int)Math.Ceiling(this.Ratio * ranges.Count), 1);

            if (sz > 500)
            {
                sz = 500;                       //SAFETY
            }
            if (sz < 50)
            {
                sz = Math.Max(sz, Math.Min(50, ranges.Count));
            }

            var samples = new List <FdbKeyRange>();

            for (int i = 0; i < sz; i++)
            {
                int p = rnd.Next(ranges.Count);
                samples.Add(ranges[p]);
                ranges.RemoveAt(p);
            }

            Console.WriteLine("# Sampling " + sz + " out of " + ranges.Count + " shards (" + (100.0 * sz / ranges.Count).ToString("N1") + "%) ...");
            Console.WriteLine("{0,9}{1,10}{2,10}{3,10} : K+V size distribution", "Count", "Keys", "Values", "Total");

            var rangeOptions = new FdbRangeOptions {
                Mode = FdbStreamingMode.WantAll
            };

            samples = samples.OrderBy(x => x.Begin).ToList();

            long total   = 0;
            int  workers = Math.Min(numMachines, 8);

            var sw    = Stopwatch.StartNew();
            var tasks = new List <Task>();

            while (samples.Count > 0)
            {
                while (tasks.Count < workers && samples.Count > 0)
                {
                    var range = samples[0];
                    samples.RemoveAt(0);
                    tasks.Add(Task.Run(async() =>
                    {
                        var hh = new RobustHistogram(RobustHistogram.TimeScale.Ticks);

                        #region Method 1: get_range everything...

                        using (var tr = db.BeginTransaction(ct))
                        {
                            long keySize   = 0;
                            long valueSize = 0;
                            long count     = 0;

                            int iter          = 0;
                            var beginSelector = FdbKeySelector.FirstGreaterOrEqual(range.Begin);
                            var endSelector   = FdbKeySelector.FirstGreaterOrEqual(range.End);
                            while (true)
                            {
                                FdbRangeChunk data = default(FdbRangeChunk);
                                FdbException error = null;
                                try
                                {
                                    data = await tr.Snapshot.GetRangeAsync(
                                        beginSelector,
                                        endSelector,
                                        rangeOptions,
                                        iter
                                        ).ConfigureAwait(false);
                                }
                                catch (FdbException e)
                                {
                                    error = e;
                                }

                                if (error != null)
                                {
                                    await tr.OnErrorAsync(error.Code).ConfigureAwait(false);
                                    continue;
                                }

                                if (data.Count == 0)
                                {
                                    break;
                                }

                                count += data.Count;
                                foreach (var kvp in data.Chunk)
                                {
                                    keySize   += kvp.Key.Count;
                                    valueSize += kvp.Value.Count;

                                    hh.Add(TimeSpan.FromTicks(kvp.Key.Count + kvp.Value.Count));
                                }

                                if (!data.HasMore)
                                {
                                    break;
                                }

                                beginSelector = FdbKeySelector.FirstGreaterThan(data.Last.Key);
                                ++iter;
                            }

                            long totalSize = keySize + valueSize;
                            Interlocked.Add(ref total, totalSize);

                            Console.WriteLine("{0,9}{1,10}{2,10}{3,10} : {4}", count.ToString("N0"), FormatSize(keySize), FormatSize(valueSize), FormatSize(totalSize), hh.GetDistribution(begin: 1, end: 10000, fold: 2));
                        }
                        #endregion

                        #region Method 2: estimate the count using key selectors...

                        //long counter = await Fdb.System.EstimateCountAsync(db, range, ct);
                        //Console.WriteLine("COUNT = " + counter.ToString("N0"));

                        #endregion
                    }, ct));
                }

                var done = await Task.WhenAny(tasks);

                tasks.Remove(done);
            }

            await Task.WhenAll(tasks);

            sw.Stop();

            Console.WriteLine("> Sampled " + FormatSize(total) + " (" + total.ToString("N0") + " bytes) in " + sw.Elapsed.TotalSeconds.ToString("N1") + " sec");
            Console.WriteLine("> Estimated total size is " + FormatSize(total * ranges.Count / sz));
        }
		public override FdbRangeQuery<System.Collections.Generic.KeyValuePair<Slice, Slice>> GetRange(FdbKeySelector beginInclusive, FdbKeySelector endExclusive, FdbRangeOptions options = null)
		{
			throw new NotImplementedException();
		}
		public virtual Task<Slice> GetKeyAsync(FdbKeySelector selector)
		{
			return m_transaction.GetKeyAsync(selector);
		}
Example #31
0
		/// <summary>
		/// Create a new range query that will read all key-value pairs in the database snapshot represented by the transaction
		/// </summary>
		/// <param name="beginInclusive">key selector defining the beginning of the range</param>
		/// <param name="endExclusive">key selector defining the end of the range</param>
		/// <param name="options">Optionnal query options (Limit, TargetBytes, Mode, Reverse, ...)</param>
		/// <returns>Range query that, once executed, will return all the key-value pairs matching the providing selector pair</returns>
		public FdbRangeQuery<KeyValuePair<Slice, Slice>> GetRange(FdbKeySelector beginInclusive, FdbKeySelector endExclusive, FdbRangeOptions options = null)
		{
			EnsureCanRead();

			return GetRangeCore(beginInclusive, endExclusive, options, snapshot: false);
		}
 public static FdbQueryRangeExpression Range(FdbKeySelector start, FdbKeySelector stop, FdbRangeOptions options = null)
 {
     return(Range(new FdbKeySelectorPair(start, stop), options));
 }
Example #33
0
		/// <summary>Resolves a key selector against the keys in the database snapshot represented by transaction.</summary>
		/// <param name="selector">Key selector to resolve</param>
		/// <returns>Task that will return the key matching the selector, or an exception</returns>
		public async Task<Slice> GetKeyAsync(FdbKeySelector selector)
		{
			EnsureCanRead();

			m_database.EnsureKeyIsValid(selector.Key);

#if DEBUG
			if (Logging.On && Logging.IsVerbose) Logging.Verbose(this, "GetKeyAsync", String.Format("Getting key '{0}'", selector.ToString()));
#endif

			var key = await m_handler.GetKeyAsync(selector, snapshot: false, cancellationToken: m_cancellation).ConfigureAwait(false);

			// don't forget to truncate keys that would fall outside of the database's globalspace !
			return m_database.BoundCheck(key);
		}
Example #34
0
        public async Task <Slice> GetKeyAsync(FdbKeySelector selector, bool snapshot, CancellationToken cancellationToken)
        {
            Contract.Requires(selector.Key.HasValue);
            cancellationToken.ThrowIfCancellationRequested();

            CheckAccessToSystemKeys(selector.Key, end: true);

            //Trace.WriteLine("## GetKey " + selector + ", snapshot=" + snapshot);

            FdbKeyRange keyRange;

            lock (m_buffer)
            {
                keyRange = m_buffer.InternRangeFromKey(selector.Key);
                selector = new FdbKeySelector(keyRange.Begin, selector.OrEqual, selector.Offset);
            }

            // we need the read version
            EnsureHasReadVersion();

            var results = await m_db.GetKeysAtVersion(new [] { selector }, m_readVersion.Value).ConfigureAwait(false);

            Contract.Assert(results != null && results.Length == 1);
            var result = results[0];

            FdbKeyRange resultRange;
            int         c = result.CompareTo(selector.Key);

            if (c == 0)
            {             // the result is identical to the key
                resultRange = keyRange;
                result      = keyRange.Begin;
            }
            else
            {             // intern the result
                lock (m_buffer)
                {
                    resultRange = m_buffer.InternRangeFromKey(result);
                    result      = resultRange.Begin;
                }
            }

            //TODO: how to merge the results with the local state mutations ?
            // => add values that were inserted
            // => remove values that were cleared
            // => change the value of keys that were mutated locally

            if (!snapshot)
            {
                lock (m_lock)
                {
                    //TODO: use the result to create the conflict range (between the resolver key and the returned key)
                    if (c == 0)
                    {                     // the key itself was selected, so it can only conflict if it gets deleted by another transaction
                        // [ result, result+\0 )
                        AddReadConflict_NeedsLocking(resultRange);
                    }
                    else if (c < 0)
                    {                     // the result is before the selected key, so any change between them (including deletion of the result) will conflict
                        // orEqual == true  => [ result, key + \0 )
                        // orEqual == false => [ result, key )
                        AddReadConflict_NeedsLocking(FdbKeyRange.Create(resultRange.Begin, selector.OrEqual ? keyRange.End : keyRange.Begin));
                    }
                    else
                    {                     // the result is after the selected key, so any change between it and the result will conflict
                        // orEqual == true  => [ key + \0, result + \0 )
                        // orEqual == false => [ key , result + \0 )
                        AddReadConflict_NeedsLocking(FdbKeyRange.Create(selector.OrEqual ? keyRange.End : keyRange.Begin, resultRange.End));
                    }
                }
            }

            return(result);
        }
		public Task<Slice[]> GetKeysAsync(FdbKeySelector[] selectors, bool snapshot, CancellationToken cancellationToken)
		{
			Contract.Requires(selectors != null);

			var futures = new FutureHandle[selectors.Length];
			try
			{
				for (int i = 0; i < selectors.Length; i++)
				{
					futures[i] = FdbNative.TransactionGetKey(m_handle, selectors[i], snapshot);
				}
			}
			catch
			{
				for (int i = 0; i < selectors.Length; i++)
				{
					if (futures[i] == null) break;
					futures[i].Dispose();
				}
				throw;
			}
			return FdbFuture.CreateTaskFromHandleArray(futures, (h) => GetKeyResult(h), cancellationToken);

		}
		public Task<Slice> GetKeyAsync(FdbKeySelector selector, bool snapshot, CancellationToken cancellationToken)
		{
			var future = FdbNative.TransactionGetKey(m_handle, selector, snapshot);
			return FdbFuture.CreateTaskFromHandle(
				future,
				(h) => GetKeyResult(h),
				cancellationToken
			);
		}
Example #37
0
		/// <summary>
		/// Resolves several key selectors against the keys in the database snapshot represented by the current transaction.
		/// </summary>
		/// <param name="selectors">Key selectors to resolve</param>
		/// <returns>Task that will return an array of keys matching the selectors, or an exception</returns>
		public Task<Slice[]> GetKeysAsync(FdbKeySelector[] selectors)
		{
			EnsureCanRead();

			foreach (var selector in selectors)
			{
				m_database.EnsureKeyIsValid(selector.Key);
			}

#if DEBUG
			if (Logging.On && Logging.IsVerbose) Logging.Verbose(this, "GetKeysAsync", String.Format("Getting batch of {0} keys ...", selectors.Length));
#endif

			return m_handler.GetKeysAsync(selectors, snapshot: false, cancellationToken: m_cancellation);
		}
		public virtual Task<FdbRangeChunk> GetRangeAsync(FdbKeySelector beginInclusive, FdbKeySelector endExclusive, FdbRangeOptions options = null, int iteration = 0)
		{
			return m_transaction.GetRangeAsync(beginInclusive, endExclusive, options, iteration);
		}
Example #39
0
		internal FdbRangeQuery<KeyValuePair<Slice, Slice>> GetRangeCore(FdbKeySelector begin, FdbKeySelector end, FdbRangeOptions options, bool snapshot)
		{
			this.Database.EnsureKeyIsValid(begin.Key);
			this.Database.EnsureKeyIsValid(end.Key, endExclusive: true);

			options = FdbRangeOptions.EnsureDefaults(options, null, null, FdbStreamingMode.Iterator, false);
			options.EnsureLegalValues();

#if DEBUG
			if (Logging.On && Logging.IsVerbose) Logging.Verbose(this, "GetRangeCore", String.Format("Getting range '{0} <= x < {1}'", begin.ToString(), end.ToString()));
#endif

			return new FdbRangeQuery<KeyValuePair<Slice, Slice>>(this, begin, end, TaskHelpers.Cache<KeyValuePair<Slice, Slice>>.Identity, snapshot, options);
		}
		public virtual Task<Slice[]> GetKeysAsync(FdbKeySelector[] selectors)
		{
			return m_transaction.GetKeysAsync(selectors);
		}
Example #41
0
		/// <summary>
		/// Reads all key-value pairs in the database snapshot represented by transaction (potentially limited by limit, target_bytes, or mode)
		/// which have a key lexicographically greater than or equal to the key resolved by the begin key selector
		/// and lexicographically less than the key resolved by the end key selector.
		/// </summary>
		/// <param name="beginInclusive">key selector defining the beginning of the range</param>
		/// <param name="endExclusive">key selector defining the end of the range</param>
		/// <param name="options">Optionnal query options (Limit, TargetBytes, StreamingMode, Reverse, ...)</param>
		/// <param name="iteration">If streaming mode is FdbStreamingMode.Iterator, this parameter should start at 1 and be incremented by 1 for each successive call while reading this range. In all other cases it is ignored.</param>
		/// <returns></returns>
		public Task<FdbRangeChunk> GetRangeAsync(FdbKeySelector beginInclusive, FdbKeySelector endExclusive, FdbRangeOptions options = null, int iteration = 0)
		{
			EnsureCanRead();

			m_database.EnsureKeyIsValid(beginInclusive.Key);
			m_database.EnsureKeyIsValid(endExclusive.Key, endExclusive: true);

			options = FdbRangeOptions.EnsureDefaults(options, null, null, FdbStreamingMode.Iterator, false);
			options.EnsureLegalValues();

			// The iteration value is only needed when in iterator mode, but then it should start from 1
			if (iteration == 0) iteration = 1;

			return m_handler.GetRangeAsync(beginInclusive, endExclusive, options, iteration, snapshot: false, cancellationToken: m_cancellation);
		}
		public override async Task<Slice[]> GetKeysAsync(FdbKeySelector[] selectors)
		{
			return Decode(await base.GetKeysAsync(Encode(selectors)).ConfigureAwait(false));
		}
		public static FutureHandle TransactionGetKey(TransactionHandle transaction, FdbKeySelector selector, bool snapshot)
		{
			if (selector.Key.IsNull) throw new ArgumentException("Key cannot be null", "selector");

			fixed (byte* ptrKey = selector.Key.Array)
			{
				var future = NativeMethods.fdb_transaction_get_key(transaction, ptrKey + selector.Key.Offset, selector.Key.Count, selector.OrEqual, selector.Offset, snapshot);
				Contract.Assert(future != null);
#if DEBUG_NATIVE_CALLS
				Debug.WriteLine("fdb_transaction_get_key(0x" + transaction.Handle.ToString("x") + ", " + selector.ToString() + ", " + snapshot + ") => 0x" + future.Handle.ToString("x"));
#endif
				return future;
			}
		}
		public override Task<FdbRangeChunk> GetRangeAsync(FdbKeySelector beginInclusive, FdbKeySelector endExclusive, FdbRangeOptions options = null, int iteration = 0)
		{
			throw new NotImplementedException();
		}
		public static FutureHandle TransactionGetRange(TransactionHandle transaction, FdbKeySelector begin, FdbKeySelector end, int limit, int targetBytes, FdbStreamingMode mode, int iteration, bool snapshot, bool reverse)
		{
			fixed (byte* ptrBegin = begin.Key.Array)
			fixed (byte* ptrEnd = end.Key.Array)
			{
				var future = NativeMethods.fdb_transaction_get_range(
					transaction,
					ptrBegin + begin.Key.Offset, begin.Key.Count, begin.OrEqual, begin.Offset,
					ptrEnd + end.Key.Offset, end.Key.Count, end.OrEqual, end.Offset,
					limit, targetBytes, mode, iteration, snapshot, reverse);
				Contract.Assert(future != null);
#if DEBUG_NATIVE_CALLS
					Debug.WriteLine("fdb_transaction_get_range(0x" + transaction.Handle.ToString("x") + ", begin: " + begin.PrettyPrint(FdbKey.PrettyPrintMode.Begin) + ", end: " + end.PrettyPrint(FdbKey.PrettyPrintMode.End) + ", " + snapshot + ") => 0x" + future.Handle.ToString("x"));
#endif
				return future;
			}
		}
		public virtual Task<Slice[]> GetKeysAsync(FdbKeySelector[] selectors)
		{
			ThrowIfDisposed();
			return m_transaction.GetKeysAsync(selectors);
		}
		public virtual FdbRangeQuery<KeyValuePair<Slice, Slice>> GetRange(FdbKeySelector beginInclusive, FdbKeySelector endInclusive, FdbRangeOptions options = null)
		{
			return m_transaction.GetRange(beginInclusive, endInclusive, options);
		}
        /// <summary>
        /// Read from the blob, starting at <paramref name="offset"/>, retrieving up to <paramref name="n"/> bytes (fewer then n bytes are returned when the end of the blob is reached).
        /// </summary>
        public async Task <Slice> ReadAsync([NotNull] IFdbReadOnlyTransaction trans, long offset, int n)
        {
            if (trans == null)
            {
                throw new ArgumentNullException("trans");
            }
            if (offset < 0)
            {
                throw new ArgumentNullException("offset", "Offset cannot be less than zero");
            }

            long?size = await GetSizeAsync(trans).ConfigureAwait(false);

            if (size == null)
            {
                return(Slice.Nil);                          // not found
            }
            if (offset >= size.Value)
            {
                return(Slice.Empty);
            }

            // read all chunks matching the segment we need, and copy them in our buffer
            var buffer = new byte[Math.Min(n, size.Value - offset)];

            await trans
            .GetRange(
                FdbKeySelector.LastLessOrEqual(DataKey(offset)),
                FdbKeySelector.FirstGreaterOrEqual(DataKey(offset + n))
                )
            .ForEachAsync((chunk) =>
            {
                // get offset of this chunk
                long chunkOffset = DataKeyOffset(chunk.Key);
                Slice chunkData  = chunk.Value;

                checked
                {
                    // intersect chunk bounds with output
                    int delta = (int)(chunkOffset - offset);
                    int start = delta;
                    int end   = delta + chunkData.Count;
                    if (start < 0)
                    {
                        start = 0;
                    }
                    if (end > n)
                    {
                        end = n;
                    }

                    // compute the relative offsets in the chunk
                    int rStart = start - delta;
                    int rEnd   = end - delta;

                    var intersect = chunkData[rStart, rEnd];
                    if (intersect.IsPresent)
                    {                             // copy the data that fits
                        intersect.CopyTo(buffer, start);
                    }
                }
            })
            .ConfigureAwait(false);

            return(new Slice(buffer, 0, buffer.Length));
        }
 private FdbKeySelector Grab(FdbKeySelector selector)
 {
     return(new FdbKeySelector(Grab(selector.Key), selector.OrEqual, selector.Offset));
 }
Example #50
0
        public static async Task Sampling(string[] path, IFdbTuple extras, IFdbDatabase db, TextWriter log, CancellationToken ct)
        {
            double ratio = 0.1d;
            bool   auto  = true;

            if (extras.Count > 0)
            {
                double x = extras.Get <double>(0);
                if (x > 0 && x <= 1)
                {
                    ratio = x;
                }
                auto = false;
            }

            var folder = await TryOpenCurrentDirectoryAsync(path, db, ct);

            FdbKeyRange span;

            if (folder is FdbDirectorySubspace)
            {
                span = FdbKeyRange.StartsWith((folder as FdbDirectorySubspace).Copy());
                log.WriteLine("Reading list of shards for /{0} under {1} ...", String.Join("/", path), FdbKey.Dump(span.Begin));
            }
            else
            {
                log.WriteLine("Reading list of shards for the whole cluster ...");
                span = FdbKeyRange.All;
            }

            // dump keyServers
            var ranges = await Fdb.System.GetChunksAsync(db, span, ct);

            log.WriteLine("> Found {0:N0} shard(s)", ranges.Count);

            // take a sample
            var samples = new List <FdbKeyRange>();

            if (ranges.Count <= 32)
            {             // small enough to scan it all
                samples.AddRange(ranges);
                log.WriteLine("Sampling all {0:N0} shards ...", samples.Count);
            }
            else
            {             // need to take a random subset
                var rnd = new Random();
                int sz  = Math.Max((int)Math.Ceiling(ratio * ranges.Count), 1);
                if (auto)
                {
                    if (sz > 100)
                    {
                        sz = 100;                               //SAFETY
                    }
                    if (sz < 32)
                    {
                        sz = Math.Max(sz, Math.Min(32, ranges.Count));
                    }
                }

                var population = new List <FdbKeyRange>(ranges);
                for (int i = 0; i < sz; i++)
                {
                    int p = rnd.Next(population.Count);
                    samples.Add(population[p]);
                    population.RemoveAt(p);
                }
                log.WriteLine("Sampling " + samples.Count + " out of " + ranges.Count + " shards (" + (100.0 * samples.Count / ranges.Count).ToString("N1") + "%) ...");
            }

            log.WriteLine();
            const string FORMAT_STRING = "{0,9} ║{1,10}{6,6} {2,-29} ║{3,10}{7,7} {4,-37} ║{5,10}";
            const string SCALE_KEY     = "....--------========########M";
            const string SCALE_VAL     = "....--------========########@@@@@@@@M";

            log.WriteLine(FORMAT_STRING, "Count", "Keys", SCALE_KEY, "Values", SCALE_VAL, "Total", "med.", "med.");

            var rangeOptions = new FdbRangeOptions {
                Mode = FdbStreamingMode.WantAll
            };

            samples = samples.OrderBy(x => x.Begin).ToList();

            long globalSize  = 0;
            long globalCount = 0;
            int  workers     = 8;        // Math.Max(4, Environment.ProcessorCount);

            var sw    = Stopwatch.StartNew();
            var tasks = new List <Task>();
            int n     = samples.Count;

            while (samples.Count > 0)
            {
                while (tasks.Count < workers && samples.Count > 0)
                {
                    var range = samples[0];
                    samples.RemoveAt(0);
                    tasks.Add(Task.Run(async() =>
                    {
                        var kk = new RobustHistogram(RobustHistogram.TimeScale.Ticks);
                        var vv = new RobustHistogram(RobustHistogram.TimeScale.Ticks);

                        #region Method 1: get_range everything...

                        using (var tr = db.BeginTransaction(ct))
                        {
                            long keySize   = 0;
                            long valueSize = 0;
                            long count     = 0;

                            int iter          = 0;
                            var beginSelector = FdbKeySelector.FirstGreaterOrEqual(range.Begin);
                            var endSelector   = FdbKeySelector.FirstGreaterOrEqual(range.End);
                            while (true)
                            {
                                FdbRangeChunk data = default(FdbRangeChunk);
                                FdbException error = null;
                                try
                                {
                                    data = await tr.Snapshot.GetRangeAsync(
                                        beginSelector,
                                        endSelector,
                                        rangeOptions,
                                        iter
                                        ).ConfigureAwait(false);
                                }
                                catch (FdbException e)
                                {
                                    error = e;
                                }

                                if (error != null)
                                {
                                    await tr.OnErrorAsync(error.Code).ConfigureAwait(false);
                                    continue;
                                }

                                if (data.Count == 0)
                                {
                                    break;
                                }

                                count += data.Count;
                                foreach (var kvp in data.Chunk)
                                {
                                    keySize   += kvp.Key.Count;
                                    valueSize += kvp.Value.Count;

                                    kk.Add(TimeSpan.FromTicks(kvp.Key.Count));
                                    vv.Add(TimeSpan.FromTicks(kvp.Value.Count));
                                }

                                if (!data.HasMore)
                                {
                                    break;
                                }

                                beginSelector = FdbKeySelector.FirstGreaterThan(data.Last.Key);
                                ++iter;
                            }

                            long totalSize = keySize + valueSize;
                            Interlocked.Add(ref globalSize, totalSize);
                            Interlocked.Add(ref globalCount, count);

                            lock (log)
                            {
                                log.WriteLine(FORMAT_STRING, count.ToString("N0"), FormatSize(keySize), kk.GetDistribution(begin: 1, end: 12000, fold: 2), FormatSize(valueSize), vv.GetDistribution(begin: 1, end: 120000, fold: 2), FormatSize(totalSize), FormatSize((int)Math.Ceiling(kk.Median)), FormatSize((int)Math.Ceiling(vv.Median)));
                            }
                        }
                        #endregion

                        #region Method 2: estimate the count using key selectors...

                        //long counter = await Fdb.System.EstimateCountAsync(db, range, ct);
                        //Console.WriteLine("COUNT = " + counter.ToString("N0"));

                        #endregion
                    }, ct));
                }

                var done = await Task.WhenAny(tasks);

                tasks.Remove(done);
            }

            await Task.WhenAll(tasks);

            sw.Stop();

            log.WriteLine();
            if (n != ranges.Count)
            {
                log.WriteLine("Sampled " + FormatSize(globalSize) + " (" + globalSize.ToString("N0") + " bytes) and " + globalCount.ToString("N0") + " keys in " + sw.Elapsed.TotalSeconds.ToString("N1") + " sec");
                log.WriteLine("> Estimated total size is " + FormatSize(globalSize * ranges.Count / n));
            }
            else
            {
                log.WriteLine("Found " + FormatSize(globalSize) + " (" + globalSize.ToString("N0") + " bytes) and " + globalCount.ToString("N0") + " keys in " + sw.Elapsed.TotalSeconds.ToString("N1") + " sec");
                // compare to the whole cluster
                ranges = await Fdb.System.GetChunksAsync(db, FdbKey.MinValue, FdbKey.MaxValue, ct);

                log.WriteLine("> This directory contains ~{0:N2}% of all data", (100.0 * n / ranges.Count));
            }
            log.WriteLine();
        }
		/// <summary>Asynchronously fetch a new page of results</summary>
		/// <returns>True if Chunk contains a new page of results. False if all results have been read.</returns>
		public Task<FdbRangeChunk> GetRangeAsync(FdbKeySelector begin, FdbKeySelector end, FdbRangeOptions options, int iteration, bool snapshot, CancellationToken cancellationToken)
		{
			Contract.Requires(options != null);

			bool reversed = options.Reverse ?? false;
			var future = FdbNative.TransactionGetRange(m_handle, begin, end, options.Limit ?? 0, options.TargetBytes ?? 0, options.Mode ?? FdbStreamingMode.Iterator, iteration, snapshot, reversed);
			return FdbFuture.CreateTaskFromHandle(
				future,
				(h) =>
				{
					// TODO: quietly return if disposed

					bool hasMore;
					var chunk = GetKeyValueArrayResult(h, out hasMore);

					return new FdbRangeChunk(hasMore, chunk, iteration, reversed);
				},
				cancellationToken
			);
		}