/// <summary>Copy an existing set of options</summary>
		/// <param name="options"></param>
		public FdbRangeOptions(FdbRangeOptions options)
		{
			this.Limit = options.Limit;
			this.Reverse = options.Reverse;
			this.TargetBytes = options.TargetBytes;
			this.Mode = options.Mode;
		}
            private static async Task <List <Slice> > GetBoundaryKeysInternalAsync([NotNull] IFdbReadOnlyTransaction trans, Slice begin, Slice end)
            {
                Contract.Requires(trans != null && end >= begin);

#if TRACE_COUNTING
                trans.Annotate("Get boundary keys in range {0}", KeyRange.Create(begin, end));
#endif

                trans.WithReadAccessToSystemKeys();

                var results    = new List <Slice>();
                int iterations = 0;
                var options    = new FdbRangeOptions {
                    Mode = FdbStreamingMode.WantAll
                };
                while (begin < end)
                {
                    FdbException error     = null;
                    Slice        lastBegin = begin;
                    try
                    {
                        var chunk = await trans.Snapshot.GetRangeAsync(KeyServers + begin, KeyServers + end, options, iterations).ConfigureAwait(false);

                        ++iterations;
                        if (chunk.Count > 0)
                        {
                            foreach (var kvp in chunk.Chunk)
                            {
                                results.Add(kvp.Key.Substring(KeyServers.Count));
                            }
                            begin = chunk.Last.Key.Substring(KeyServers.Count) + 0;
                        }
                        if (!chunk.HasMore)
                        {
                            begin = end;
                        }
                    }
                    catch (FdbException e)
                    {
                        error = e;
                    }

                    if (error != null)
                    {
                        if (error.Code == FdbError.PastVersion && begin != lastBegin)
                        {                         // if we get a PastVersion and *something* has happened, then we are no longer transactionnal
                            trans.Reset();
                        }
                        else
                        {
                            await trans.OnErrorAsync(error.Code).ConfigureAwait(false);
                        }
                        iterations = 0;
                        trans.WithReadAccessToSystemKeys();
                    }
                }

#if TRACE_COUNTING
                if (results.Count == 0)
                {
                    trans.Annotate("There is no chunk boundary in range {0}", KeyRange.Create(begin, end));
                }
                else
                {
                    trans.Annotate("Found {0} boundaries in {1} iteration(s)", results.Count, iterations);
                }
#endif

                return(results);
            }
        public static FdbRangeQuery <KeyValuePair <Slice, Slice> > GetRangeStartsWith(this IFdbReadOnlyTransaction trans, [NotNull] IKeySubspace subspace, FdbRangeOptions options = null)
        {
            //REVIEW: should we remove this method?
            Contract.Requires(trans != null && subspace != null);

            return(trans.GetRange(subspace.ToRange(), options));
        }
		/// <summary>Add all missing values from the provided defaults</summary>
		/// <param name="options">Options provided by the caller (can be null)</param>
		/// <param name="limit">Default value for Limit if not provided</param>
		/// <param name="targetBytes">Default TargetBytes for limit if not provided</param>
		/// <param name="mode">Default value for StreamingMode if not provided</param>
		/// <param name="reverse">Default value for Reverse if not provided</param>
		/// <returns>Options with all the values filled</returns>
		public static FdbRangeOptions EnsureDefaults(FdbRangeOptions options, int? limit, int? targetBytes, FdbStreamingMode mode, bool reverse)
		{
			Contract.Requires((limit ?? 0) >= 0 && (targetBytes ?? 0) >= 0 && Enum.IsDefined(typeof(FdbStreamingMode), mode));

			if (options == null)
			{
				options = new FdbRangeOptions()
				{
					Limit = limit,
					TargetBytes = targetBytes,
					Mode = mode,
					Reverse = reverse
				};
			}
			else if (options.Limit == null || options.TargetBytes == null || options.Mode == null || options.Reverse == null)
			{
				options = new FdbRangeOptions()
				{
					Limit = options.Limit ?? limit,
					TargetBytes = options.TargetBytes ?? targetBytes,
					Mode = options.Mode ?? mode,
					Reverse = options.Reverse ?? reverse
				};
			}

			Contract.Ensures(options.Mode != null && options.Reverse != null);
			Contract.Ensures((options.Limit ?? 0) >= 0, "Limit cannot be negative");
			Contract.Ensures((options.TargetBytes ?? 0) >= 0, "TargetBytes cannot be negative");
			Contract.Ensures(options.Mode.HasValue && Enum.IsDefined(typeof(FdbStreamingMode), options.Mode.Value), "Streaming mode must be valid");

			return options;
		}
示例#5
0
            public FdbRangeQuery <KeyValuePair <Slice, Slice> > GetRange(FdbKeySelector beginInclusive, FdbKeySelector endExclusive, FdbRangeOptions options)
            {
                EnsureCanRead();

                return(m_parent.GetRangeCore(beginInclusive, endExclusive, options, snapshot: true));
            }
		public override FdbRangeQuery<System.Collections.Generic.KeyValuePair<Slice, Slice>> GetRange(FdbKeySelector beginInclusive, FdbKeySelector endExclusive, FdbRangeOptions options = null)
		{
			throw new NotImplementedException();
		}
			private static async Task<List<Slice>> GetBoundaryKeysInternalAsync([NotNull] IFdbReadOnlyTransaction trans, Slice begin, Slice end)
			{
				Contract.Requires(trans != null && end >= begin);

#if TRACE_COUNTING
				trans.Annotate("Get boundary keys in range {0}", FdbKeyRange.Create(begin, end));
#endif

				trans.WithReadAccessToSystemKeys();

				var results = new List<Slice>();
				int iterations = 0;
				var options = new FdbRangeOptions { Mode = FdbStreamingMode.WantAll };
				while (begin < end)
				{
					FdbException error = null;
					Slice lastBegin = begin;
					try
					{
						var chunk = await trans.Snapshot.GetRangeAsync(KeyServers + begin, KeyServers + end, options, iterations).ConfigureAwait(false);
						++iterations;
						if (chunk.Count > 0)
						{
							foreach (var kvp in chunk.Chunk)
							{
								results.Add(kvp.Key.Substring(KeyServers.Count));
							}
							begin = chunk.Last.Key.Substring(KeyServers.Count) + (byte)0;
						}
						if (!chunk.HasMore)
						{
							begin = end;
						}
					}
					catch (FdbException e)
					{
						error = e;
					}

					if (error != null)
					{
						if (error.Code == FdbError.PastVersion && begin != lastBegin)
						{ // if we get a PastVersion and *something* has happened, then we are no longer transactionnal
							trans.Reset();
						}
						else
						{
							await trans.OnErrorAsync(error.Code).ConfigureAwait(false);
						}
						iterations = 0;
						trans.WithReadAccessToSystemKeys();
					}
				}

#if TRACE_COUNTING
				if (results.Count == 0)
				{
					trans.Annotate("There is no chunk boundary in range {0}", FdbKeyRange.Create(begin, end));
				}
				else
				{
					trans.Annotate("Found {0} boundaries in {1} iteration(s)", results.Count, iterations);
				}
#endif

				return results;
			}
 /// <summary>Read a single page of a range query from the database, using a dedicated transaction.</summary>
 /// <param name="db">Database instance</param>
 /// <remarks>
 /// Use this method only if you intend to perform a single operation inside your execution context (ex: HTTP request).
 /// If you need to combine multiple read or write operations, consider using on of the multiple <see cref="IFdbReadOnlyRetryable.ReadAsync"/> or <see cref="IFdbRetryable.ReadWriteAsync"/> overrides.
 /// </remarks>
 public static Task <FdbRangeChunk> GetRangeAsync(this IFdbReadOnlyRetryable db, FdbKeySelector beginInclusive, FdbKeySelector endExclusive, FdbRangeOptions options, int iteration, CancellationToken cancellationToken)
 {
     if (db == null)
     {
         throw new ArgumentNullException("db");
     }
     return(db.ReadAsync((tr) => tr.GetRangeAsync(beginInclusive, endExclusive, options, iteration), cancellationToken));
 }
示例#9
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);
		}
示例#10
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 virtual FdbRangeQuery<KeyValuePair<Slice, Slice>> GetRange(FdbKeySelector beginInclusive, FdbKeySelector endInclusive, FdbRangeOptions options = null)
		{
			return m_transaction.GetRange(beginInclusive, endInclusive, options);
		}
		public virtual Task<FdbRangeChunk> GetRangeAsync(FdbKeySelector beginInclusive, FdbKeySelector endExclusive, FdbRangeOptions options = null, int iteration = 0)
		{
			return m_transaction.GetRangeAsync(beginInclusive, endExclusive, options, iteration);
		}
 public FdbRangeQuery <TResult> GetRange <TResult>(KeySelector beginInclusive, KeySelector endExclusive, Func <KeyValuePair <Slice, Slice>, TResult> selector, FdbRangeOptions options = null)
 {
     return(m_parent.GetRangeCore(beginInclusive, endExclusive, options, snapshot: true, selector));
 }
 public FdbRangeQuery <KeyValuePair <Slice, Slice> > GetRange(KeySelector beginInclusive, KeySelector endExclusive, FdbRangeOptions options = null)
 {
     return(m_parent.GetRangeCore(beginInclusive, endExclusive, options, snapshot: true, kv => kv));
 }
		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));
		}
        /// <summary>Construct a query with a set of initial settings</summary>
        internal FdbRangeQuery([NotNull] IFdbReadOnlyTransaction transaction, KeySelector begin, KeySelector end, [NotNull] Func <KeyValuePair <Slice, Slice>, T> transform, bool snapshot, [CanBeNull] FdbRangeOptions options)
        {
            Contract.Requires(transaction != null && transform != null);

            this.Transaction   = transaction;
            this.Begin         = begin;
            this.End           = end;
            this.Transform     = transform;
            this.Snapshot      = snapshot;
            this.Options       = options ?? new FdbRangeOptions();
            this.OriginalRange = KeySelectorPair.Create(begin, end);
        }
示例#17
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 Task <FdbRangeChunk> GetRangeAsync(KeySelector beginInclusive, KeySelector endExclusive, FdbRangeOptions options, int iteration)
            {
                EnsureCanRead();

                m_parent.m_database.EnsureKeyIsValid(beginInclusive.Key);
                m_parent.m_database.EnsureKeyIsValid(endExclusive.Key);

                options = FdbRangeOptions.EnsureDefaults(options, null, null, FdbStreamingMode.Iterator, FdbReadMode.Both, 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_parent.m_handler.GetRangeAsync(beginInclusive, endExclusive, options, iteration, snapshot: true, ct: m_parent.m_cancellation));
            }
示例#19
0
            /// <summary>Asynchronously fetch a new page of results</summary>
            /// <param name="cancellationToken"></param>
            /// <returns>True if Chunk contains a new page of results. False if all results have been read.</returns>
            private Task <bool> FetchNextPageAsync(CancellationToken cancellationToken)
            {
                Contract.Requires(!this.AtEnd);
                Contract.Requires(this.Iteration >= 0);

                cancellationToken.ThrowIfCancellationRequested();
                this.Transaction.EnsureCanRead();

                this.Iteration++;

#if DEBUG_RANGE_PAGING
                Debug.WriteLine("FdbRangeQuery.PagingIterator.FetchNextPageAsync(iter=" + this.Iteration + ") started");
#endif

                var options = new FdbRangeOptions
                {
                    Limit       = this.RemainingCount,
                    TargetBytes = this.RemainingSize,
                    Mode        = this.Query.Mode,
                    Reverse     = this.Query.Reversed
                };

                // select the appropriate streaming mode if purpose is not default
                switch (m_mode)
                {
                case FdbAsyncMode.Iterator:
                {
                    // the caller is responsible for calling MoveNext(..) and deciding if it wants to continue or not..
                    options.Mode = FdbStreamingMode.Iterator;
                    break;
                }

                case FdbAsyncMode.All:
                {
                    // we are in a ToList or ForEach, we want to read everything in as few chunks as possible
                    options.Mode = FdbStreamingMode.WantAll;
                    break;
                }

                case FdbAsyncMode.Head:
                {
                    // the caller only expect one (or zero) values
                    options.Mode = FdbStreamingMode.Iterator;
                    break;
                }
                }

                var tr = this.Transaction;
                if (this.Query.Snapshot)
                {                 // make sure we have the snapshot version !
                    tr = tr.Snapshot;
                }

                //BUGBUG: mix the custom cancellation token with the transaction, if it is diffent !
                var task = tr
                           .GetRangeAsync(this.Begin, this.End, options, this.Iteration)
                           .Then((result) =>
                {
                    this.Chunk     = result.Chunk;
                    this.RowCount += result.Count;
                    this.HasMore   = result.HasMore;
                    // subtract number of row from the remaining allowed
                    if (this.RemainingCount.HasValue)
                    {
                        this.RemainingCount = this.RemainingCount.Value - result.Count;
                    }
                    // subtract size of rows from the remaining allowed
                    if (this.RemainingSize.HasValue)
                    {
                        this.RemainingSize = this.RemainingSize.Value - result.GetSize();
                    }

                    this.AtEnd = !result.HasMore || (this.RemainingCount.HasValue && this.RemainingCount.Value <= 0) || (this.RemainingSize.HasValue && this.RemainingSize.Value <= 0);

                    if (!this.AtEnd)
                    {                             // update begin..end so that next call will continue from where we left...
                        var lastKey = result.Last.Key;
                        if (this.Query.Reversed)
                        {
                            this.End = KeySelector.FirstGreaterOrEqual(lastKey);
                        }
                        else
                        {
                            this.Begin = KeySelector.FirstGreaterThan(lastKey);
                        }
                    }
#if DEBUG_RANGE_PAGING
                    Debug.WriteLine("FdbRangeQuery.PagingIterator.FetchNextPageAsync() returned " + this.Chunk.Length + " results (" + this.RowCount + " total) " + (hasMore ? " with more to come" : " and has no more data"));
#endif
                    if (!result.IsEmpty && this.Transaction != null)
                    {
                        return(Publish(result.Chunk));
                    }
                    return(Completed());
                });

                // keep track of this operation
                this.PendingReadTask = task;
                return(task);
            }
		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();
		}
示例#21
0
 /// <summary>Read a single page of a range query from the database, using a dedicated transaction.</summary>
 /// <param name="db">Database instance</param>
 /// <remarks>
 /// Use this method only if you intend to perform a single operation inside your execution context (ex: HTTP request).
 /// If you need to combine multiple read or write operations, consider using on of the multiple <see cref="IFdbReadOnlyRetryable.ReadAsync"/> or <see cref="IFdbRetryable.ReadWriteAsync"/> overrides.
 /// </remarks>
 public static Task <FdbRangeChunk> GetRangeAsync([NotNull] this IFdbReadOnlyRetryable db, KeySelector beginInclusive, KeySelector endExclusive, FdbRangeOptions options, int iteration, CancellationToken ct)
 {
     Contract.NotNull(db, nameof(db));
     return(db.ReadAsync((tr) => tr.GetRangeAsync(beginInclusive, endExclusive, options, iteration), ct));
 }
		public override Task<FdbRangeChunk> GetRangeAsync(FdbKeySelector beginInclusive, FdbKeySelector endExclusive, FdbRangeOptions options = null, int iteration = 0)
		{
			throw new NotImplementedException();
		}
        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));
        }