public async Task Bench_FdbCounter_Increment_Sequentially()
        {
            const int N = 100;

            using (var db = await OpenTestPartitionAsync())
            {
                var location = await GetCleanDirectory(db, "counters", "big");

                var c = new FdbHighContentionCounter(db, location);

                Console.WriteLine("Doing " + N + " inserts in one thread...");

                var sw = Stopwatch.StartNew();
                for (int i = 0; i < N; i++)
                {
                    await c.AddAsync(1, this.Cancellation);
                }
                sw.Stop();

                Console.WriteLine("> " + N + " completed in " + sw.Elapsed.TotalMilliseconds.ToString("N1") + " ms (" + (sw.Elapsed.TotalMilliseconds * 1000 / N).ToString("N0") + " µs/add)");

#if DEBUG
                await DumpSubspace(db, location);
#endif

                Assert.That(await c.GetSnapshotAsync(this.Cancellation), Is.EqualTo(N));
            }
        }
		public async Task Bench_FdbCounter_Increment_Sequentially()
		{
			const int N = 100;

			using (var db = await OpenTestPartitionAsync())
			{
				var location = await GetCleanDirectory(db, "counters", "big");

				var c = new FdbHighContentionCounter(db, location);

				Console.WriteLine("Doing " + N + " inserts in one thread...");

				var sw = Stopwatch.StartNew();
				for (int i = 0; i < N; i++)
				{
					await c.AddAsync(1, this.Cancellation);
				}
				sw.Stop();

				Console.WriteLine("> " + N + " completed in " + sw.Elapsed.TotalMilliseconds.ToString("N1") + " ms (" + (sw.Elapsed.TotalMilliseconds * 1000 / N).ToString("N0") + " µs/add)");

#if DEBUG
				await DumpSubspace(db, location);
#endif

				Assert.That(await c.GetSnapshotAsync(this.Cancellation), Is.EqualTo(N));
			}

		}
		public async Task Test_FdbCounter_Can_Increment_And_SetTotal()
		{
			using (var db = await OpenTestPartitionAsync())
			{
				var location = await GetCleanDirectory(db, "counters", "simple");

				var counter = new FdbHighContentionCounter(db, location);

				await counter.AddAsync(100, this.Cancellation);
				Assert.That(await counter.GetSnapshotAsync(this.Cancellation), Is.EqualTo(100));

				await counter.AddAsync(-10, this.Cancellation);
				Assert.That(await counter.GetSnapshotAsync(this.Cancellation), Is.EqualTo(90));

				await counter.SetTotalAsync(500, this.Cancellation);
				Assert.That(await counter.GetSnapshotAsync(this.Cancellation), Is.EqualTo(500));
			}
		}
        public async Task Test_FdbCounter_Can_Increment_And_SetTotal()
        {
            using (var db = await OpenTestPartitionAsync())
            {
                var location = await GetCleanDirectory(db, "counters", "simple");

                var counter = new FdbHighContentionCounter(db, location);

                await counter.AddAsync(100, this.Cancellation);

                Assert.That(await counter.GetSnapshotAsync(this.Cancellation), Is.EqualTo(100));

                await counter.AddAsync(-10, this.Cancellation);

                Assert.That(await counter.GetSnapshotAsync(this.Cancellation), Is.EqualTo(90));

                await counter.SetTotalAsync(500, this.Cancellation);

                Assert.That(await counter.GetSnapshotAsync(this.Cancellation), Is.EqualTo(500));
            }
        }
        public async Task Bench_FdbCounter_Increment_Concurrently()
        {
            const int B = 100;

            // repeat the process 10 times...
            foreach (int W in new [] { 1, 2, 5, 10, 20, 50, 100 })
            {
                int N = B * W;

                using (var db = await OpenTestPartitionAsync())
                {
                    var location = await GetCleanDirectory(db, "counters", "big", W.ToString());

                    var c = new FdbHighContentionCounter(db, location);

                    Console.WriteLine("Doing " + W + " x " + B + " inserts in " + W + " threads...");

                    var signal  = new TaskCompletionSource <object>();
                    var done    = new TaskCompletionSource <object>();
                    var workers = Enumerable.Range(0, W)
                                  .Select(async(id) =>
                    {
                        await signal.Task.ConfigureAwait(false);
                        for (int i = 0; i < B; i++)
                        {
                            await c.AddAsync(1, this.Cancellation).ConfigureAwait(false);
                        }
                    }).ToArray();

                    var sw = Stopwatch.StartNew();
                    // start
                    ThreadPool.UnsafeQueueUserWorkItem((_) => signal.TrySetResult(null), null);
                    // wait
                    await Task.WhenAll(workers);

                    sw.Stop();
                    Console.WriteLine("> " + N + " completed in " + sw.Elapsed.TotalMilliseconds.ToString("N1") + " ms (" + (sw.Elapsed.TotalMilliseconds * 1000 / B).ToString("N0") + " µs/add)");

                    long n = await c.GetSnapshotAsync(this.Cancellation);

                    if (n != N)
                    {                     // fail
                        await DumpSubspace(db, location);

                        Assert.That(n, Is.EqualTo(N), "Counter value does not match (first call)");
                    }

                    // wait a bit, in case there was some coalesce still running...
                    await Task.Delay(200);

                    n = await c.GetSnapshotAsync(this.Cancellation);

                    if (n != N)
                    {                     // fail
                        await DumpSubspace(db, location);

                        Assert.That(n, Is.EqualTo(N), "Counter value does not match (second call)");
                    }
                }
            }
        }
		public async Task Bench_FdbCounter_Increment_Concurrently()
		{
			const int B = 100;

			// repeat the process 10 times...
			foreach(int W in new [] { 1, 2, 5, 10, 20, 50, 100 })
			{
				int N = B * W;

				using (var db = await OpenTestPartitionAsync())
				{
					var location = await GetCleanDirectory(db, "counters", "big", W.ToString());

					var c = new FdbHighContentionCounter(db, location);

					Console.WriteLine("Doing " + W + " x " + B + " inserts in " + W + " threads...");

					var signal = new TaskCompletionSource<object>();
					var done = new TaskCompletionSource<object>();
					var workers = Enumerable.Range(0, W)
						.Select(async (id) =>
						{
							await signal.Task.ConfigureAwait(false);
							for (int i = 0; i < B; i++)
							{
								await c.AddAsync(1, this.Cancellation).ConfigureAwait(false);
							}
						}).ToArray();

					var sw = Stopwatch.StartNew();
					// start
					ThreadPool.UnsafeQueueUserWorkItem((_) => signal.TrySetResult(null), null);
					// wait
					await Task.WhenAll(workers);
					sw.Stop();
					Console.WriteLine("> " + N + " completed in " + sw.Elapsed.TotalMilliseconds.ToString("N1") + " ms (" + (sw.Elapsed.TotalMilliseconds * 1000 / B).ToString("N0") + " µs/add)");

					long n = await c.GetSnapshotAsync(this.Cancellation);
					if (n != N)
					{ // fail
						await DumpSubspace(db, location);
						Assert.That(n, Is.EqualTo(N), "Counter value does not match (first call)");
					}

					// wait a bit, in case there was some coalesce still running...
					await Task.Delay(200);
					n = await c.GetSnapshotAsync(this.Cancellation);
					if (n != N)
					{ // fail
						await DumpSubspace(db, location);
						Assert.That(n, Is.EqualTo(N), "Counter value does not match (second call)");
					}

				}
			}

		}