Example #1
0
        /// <summary>
        /// Signup a student to a class
        /// </summary>
        public async Task Signup(IFdbTransaction tr, string s, string c, IDynamicKeySubspace subspace)
        {
            var rec = AttendsKey(s, c);

            if ((await tr.GetAsync(rec)).IsPresent)
            {             // already signed up
                return;
            }
            int seatsLeft = Int32.Parse((await tr.GetAsync(ClassKey(c, subspace))).ToStringAscii());

            if (seatsLeft <= 0)
            {
                throw new InvalidOperationException("No remaining seats");
            }

            var classes = await tr.GetRange(AttendsKeys(s)).ToListAsync();

            if (classes.Count >= 5)
            {
                throw new InvalidOperationException("Too many classes");
            }

            tr.Set(ClassKey(c, subspace), Slice.FromStringAscii((seatsLeft - 1).ToString()));
            tr.Set(rec, Slice.Empty);
        }
Example #2
0
        /// <summary>Create an allocator operating under a specific location</summary>
        /// <param name="subspace"></param>
        public FdbHighContentionAllocator(IDynamicKeySubspace subspace)
        {
            Contract.NotNull(subspace, nameof(subspace));

            this.Subspace = subspace;
            this.Counters = subspace.Partition.ByKey(COUNTERS);
            this.Recent   = subspace.Partition.ByKey(RECENT);
        }
        /// <summary>Create a new sparse Vector</summary>
        /// <param name="subspace">Subspace where the vector will be stored</param>
        /// <param name="defaultValue">Default value for sparse entries</param>
        /// <param name="encoder">Encoder used for the values of this vector</param>
        public FdbVector([NotNull] IDynamicKeySubspace subspace, T defaultValue, IValueEncoder <T> encoder = null)
        {
            if (subspace == null)
            {
                throw new ArgumentNullException(nameof(subspace));
            }

            this.Subspace     = subspace;
            this.DefaultValue = defaultValue;
            this.Encoder      = encoder ?? TuPack.Encoding.GetValueEncoder <T>();
        }
        /// <summary>Create an allocator operating under a specific location</summary>
        /// <param name="subspace"></param>
        public FdbHighContentionAllocator(IDynamicKeySubspace subspace)
        {
            if (subspace == null)
            {
                throw new ArgumentNullException(nameof(subspace));
            }

            this.Subspace = subspace;
            this.Counters = subspace.Partition.ByKey(COUNTERS);
            this.Recent   = subspace.Partition.ByKey(RECENT);
        }
Example #5
0
 /// <summary>Change the current global namespace.</summary>
 /// <remarks>Do NOT call this, unless you know exactly what you are doing !</remarks>
 internal void ChangeRoot(IKeySubspace subspace, IFdbDirectory directory, bool readOnly)
 {
     //REVIEW: rename to "ChangeRootSubspace" ?
     subspace = subspace ?? KeySubspace.Empty;
     lock (this)            //TODO: don't use this for locking
     {
         m_readOnly        = readOnly;
         m_globalSpace     = subspace.Copy(TuPack.Encoding);
         m_globalSpaceCopy = subspace.Copy(TuPack.Encoding);                 // keep another copy
         m_directory       = directory;
     }
 }
Example #6
0
        /// <summary>
        /// Drop a student from a class
        /// </summary>
        public async Task Drop(IFdbTransaction tr, string s, string c, IDynamicKeySubspace subspace)
        {
            var rec = AttendsKey(s, c);

            if ((await tr.GetAsync(rec)).IsNullOrEmpty)
            {             // not taking this class
                return;
            }

            var students = Int32.Parse((await tr.GetAsync(ClassKey(c, subspace))).ToStringAscii());

            tr.Set(ClassKey(c, subspace), Slice.FromStringAscii((students + 1).ToString()));
            tr.Clear(rec);
        }
        private async Task PushQueueAsync(IFdbTransaction tr, IDynamicKeySubspace queue, Slice taskId)
        {
            //TODO: use a high contention algo ?
            // - must support Push and Pop
            // - an empty queue must correspond to an empty subspace

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

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

            // set the value
            tr.Set(queue.Keys.Encode(count, GetRandomId()), taskId);
        }
        /// <summary>
        /// Setup the initial state of the database
        /// </summary>
        public async Task Init(IFdbDatabase db, CancellationToken ct)
        {
            // open the folder where we will store everything
            this.Subspace = await db.Directory.CreateOrOpenAsync(new [] { "Benchmarks", "LeakTest" }, ct : ct);

            // clear all previous values
            await db.ClearRangeAsync(this.Subspace, ct);

            // insert all the classes
            await db.WriteAsync((tr) =>
            {
                tr.Set(this.Subspace.GetPrefix() + FdbKey.MinValue, Slice.FromString("BEGIN"));
                tr.Set(this.Subspace.GetPrefix() + FdbKey.MaxValue, Slice.FromString("END"));
            }, ct);
        }
        /// <summary>Create a new queue using either High Contention mode or Simple mode</summary>
        /// <param name="subspace">Subspace where the queue will be stored</param>
        /// <param name="highContention">If true, uses High Contention Mode (lots of popping clients). If true, uses the Simple Mode (a few popping clients).</param>
        /// <param name="encoder">Encoder for the values stored in this queue</param>
        public FdbQueue([NotNull] IDynamicKeySubspace subspace, bool highContention = false, IValueEncoder <T> encoder = null)
        {
            if (subspace == null)
            {
                throw new ArgumentNullException(nameof(subspace));
            }

            this.Subspace       = subspace;
            this.HighContention = highContention;
            this.Encoder        = encoder ?? TuPack.Encoding.GetValueEncoder <T>();

            //TODO: rewrite this, using FdbEncoderSubpsace<..> !
            this.ConflictedPop  = this.Subspace.Partition.ByKey(Slice.FromStringAscii("pop"));
            this.ConflictedItem = this.Subspace.Partition.ByKey(Slice.FromStringAscii("conflict"));
            this.QueueItem      = this.Subspace.Partition.ByKey(Slice.FromStringAscii("item"));
        }
Example #10
0
        /// <summary>
        /// Setup the initial state of the database
        /// </summary>
        public async Task Init(IFdbDatabase db, CancellationToken ct)
        {
            this.Subspace = await db.ReadWriteAsync(async tr =>
            {
                // open the folder where we will store everything
                var subspace = await db.Root["Benchmarks"]["LeakTest"].CreateOrOpenAsync(tr);

                // clear all previous values
                await db.ClearRangeAsync(subspace, ct);

                // insert all the classes
                tr.Set(subspace.GetPrefix() + FdbKey.MinValue, Slice.FromString("BEGIN"));
                tr.Set(subspace.GetPrefix() + FdbKey.MaxValue, Slice.FromString("END"));

                return(subspace);
            }, ct);
        }
Example #11
0
        /// <summary>
        /// Setup the initial state of the database
        /// </summary>
        public async Task Init(IFdbDatabase db, CancellationToken ct)
        {
            // open the folder where we will store everything
            this.Subspace = await db.Directory.CreateOrOpenAsync(new [] { "Tutorials", "ClassScheduling" }, ct : ct);

            // clear all previous values
            await db.ClearRangeAsync(this.Subspace, ct);

            // insert all the classes
            await db.WriteAsync((tr) =>
            {
                foreach (var c in this.ClassNames)
                {
                    tr.Set(ClassKey(c), Slice.FromStringAscii("100"));
                }
            }, ct);
        }
        /// <summary>Create a new High Contention counter, using a specific value encoder.</summary>
        /// <param name="db">Database used by this layer</param>
        /// <param name="subspace">Subspace to be used for storing the counter</param>
        /// <param name="encoder">Encoder for the counter values</param>
        public FdbHighContentionCounter([NotNull] IFdbDatabase db, [NotNull] IDynamicKeySubspace subspace, [NotNull] IValueEncoder <long> encoder)
        {
            if (db == null)
            {
                throw new ArgumentNullException(nameof(db));
            }
            if (subspace == null)
            {
                throw new ArgumentNullException(nameof(subspace));
            }
            if (encoder == null)
            {
                throw new ArgumentNullException(nameof(encoder));
            }

            this.Database = db;
            this.Subspace = subspace.AsDynamic();
            this.Encoder  = encoder;
        }
Example #13
0
        /// <summary>
        /// Setup the initial state of the database
        /// </summary>
        public async Task Init(IFdbDatabase db, CancellationToken ct)
        {
            // open the folder where we will store everything
            this.Subspace = await db.ReadWriteAsync(async tr =>
            {
                var subspace = await db.Root["Tutorials"]["ClassScheduling"].CreateOrOpenAsync(tr);

                // clear all previous values
                tr.ClearRange(subspace);

                // insert all the classes
                foreach (var c in this.ClassNames)
                {
                    tr.Set(ClassKey(c), Slice.FromStringAscii("100"));
                }

                return(subspace);
            }, ct);
        }
Example #14
0
        public async Task Run(IFdbDatabase db, TextWriter log, CancellationToken ct)
        {
            const int STUDENTS         = 10;
            const int OPS_PER_STUDENTS = 10;

            this.Subspace = db.GlobalSpace;

            await Init(db, ct);

            log.WriteLine("# Class sheduling test initialized");

            // run multiple students
            var elapsed = await Program.RunConcurrentWorkersAsync(
                STUDENTS,
                (i, _ct) => IndecisiveStudent(db, i, OPS_PER_STUDENTS, _ct),
                ct
                );

            log.WriteLine("# Ran {0} transactions in {1:0.0##} sec", (STUDENTS * OPS_PER_STUDENTS), elapsed.TotalSeconds);
        }
        private static async Task BenchSerialWriteAsync(IFdbDatabase db, int N, CancellationToken ct)
        {
            // read a lot of small keys, one by one

            Console.WriteLine($"=== BenchSerialWrite(N={N:N0}) ===");

            var                 location = db.Root.ByKey("hello");
            var                 sw       = Stopwatch.StartNew();
            IFdbTransaction     trans    = null;
            IDynamicKeySubspace subspace = null;

            try
            {
                for (int i = 0; i < N; i++)
                {
                    if (trans == null)
                    {
                        trans = await db.BeginTransactionAsync(ct);

                        subspace = await location.Resolve(trans);
                    }
                    trans.Set(subspace.Encode(i), Slice.FromInt32(i));
                    if (trans.Size > 100 * 1024)
                    {
                        await trans.CommitAsync();

                        trans.Dispose();
                        trans = null;
                    }
                }
                await trans.CommitAsync();
            }
            finally
            {
                trans?.Dispose();
            }
            sw.Stop();
            Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:N3} sec to read {N:N0} items ({FormatTimeMicro(sw.Elapsed.TotalMilliseconds / N)}/read, {N/sw.Elapsed.TotalSeconds:N0} read/sec)");
            Console.WriteLine();
        }
Example #16
0
 /// <summary>
 /// Drop a student from a class, and sign him up to another class
 /// </summary>
 public async Task Switch(IFdbTransaction tr, string s, string oldC, string newC, IDynamicKeySubspace subspace)
 {
     await Drop(tr, s, oldC, subspace);
     await Signup(tr, s, newC, subspace);
 }
        private async Task RunAsync(IFdbDatabase db, IDynamicKeySubspace location, CancellationToken ct, Action done, int N, int K, int W)
        {
            if (db == null)
            {
                throw new ArgumentNullException(nameof(db));
            }

            StringBuilder sb = new StringBuilder();

            db = new FdbLoggedDatabase(db, false, false, (log) =>
            {
                sb.AppendLine(log.Log.GetTimingsReport(true));
                //Console.WriteLine(log.Log.GetTimingsReport(true));
            });
            try
            {
                var workerPool = new FdbWorkerPool(location);
                Console.WriteLine($"workerPool at {location.GetPrefix():P}");

                var workerSignal = new AsyncCancelableMutex(ct);
                var clientSignal = new AsyncCancelableMutex(ct);

                int taskCounter = 0;

                int msgSent     = 0;
                int msgReceived = 0;

                Func <FdbWorkerMessage, CancellationToken, Task> handler = async(msg, _ct) =>
                {
                    Interlocked.Increment(ref msgReceived);

                    //await Task.Delay(10 + Math.Abs(msg.Id.GetHashCode()) % 50);
                    await Task.Delay(10).ConfigureAwait(false);
                };

                Func <int, Task> worker = async(id) =>
                {
                    await workerSignal.Task.ConfigureAwait(false);

                    Console.WriteLine("Worker #" + id + " is starting");
                    try
                    {
                        await workerPool.RunWorkerAsync(db, handler, ct).ConfigureAwait(false);
                    }
                    finally
                    {
                        Console.WriteLine("Worker #" + id + " has stopped");
                    }
                };

                Func <int, Task> client = async(id) =>
                {
                    await clientSignal.Task.ConfigureAwait(false);

                    await Task.Delay(10).ConfigureAwait(false);

                    var rnd = new Random(id * 111);
                    for (int i = 0; i < N; i++)
                    {
                        var taskId   = Slice.FromString("T" + Interlocked.Increment(ref taskCounter));
                        var taskBody = Slice.FromString("Message " + (i + 1) + " of " + N + " from client #" + id);

                        await workerPool.ScheduleTaskAsync(db, taskId, taskBody, ct).ConfigureAwait(false);

                        Interlocked.Increment(ref msgSent);

                        //if (i > 0 && i % 10 == 0) Console.WriteLine("@@@ Client#" + id + " pushed " + (i + 1) + " / " + N + " messages");

                        switch (rnd.Next(5))
                        {
                        case 0: await Task.Delay(10).ConfigureAwait(false); break;

                        case 1: await Task.Delay(100).ConfigureAwait(false); break;

                        case 2: await Task.Delay(500).ConfigureAwait(false); break;
                        }
                    }
                    Console.WriteLine("@@@ Client#" + id + " has finished!");
                };

                Func <string, Task> dump = async(label) =>
                {
                    Console.WriteLine($"<dump label=\'{label}\' key=\'{location.GetPrefix():P}\'>");
                    using (var tr = db.BeginTransaction(ct))
                    {
                        await tr.Snapshot
                        .GetRange(KeyRange.StartsWith(location.GetPrefix()))
                        .ForEachAsync((kvp) =>
                        {
                            Console.WriteLine($" - {location.Keys.Unpack(kvp.Key)} = {kvp.Value:V}");
                        }).ConfigureAwait(false);
                    }
                    Console.WriteLine("</dump>");
                };

                var workers = Enumerable.Range(0, W).Select((i) => worker(i)).ToArray();
                var clients = Enumerable.Range(0, K).Select((i) => client(i)).ToArray();

                DateTime start       = DateTime.Now;
                DateTime last        = start;
                int      lastHandled = -1;
                using (var timer = new Timer((_) =>
                {
                    var now = DateTime.Now;
                    Console.WriteLine("@@@ T=" + now.Subtract(start) + ", sent: " + msgSent.ToString("N0") + ", recv: " + msgReceived.ToString("N0"));
                    Console.WriteLine("### Workers: " + workerPool.IdleWorkers + " / " + workerPool.ActiveWorkers + " (" + new string('#', workerPool.IdleWorkers) + new string('.', workerPool.ActiveWorkers - workerPool.IdleWorkers) + "), sent: " + workerPool.MessageScheduled.ToString("N0") + ", recv: " + workerPool.MessageReceived.ToString("N0") + ", delta: " + (workerPool.MessageScheduled - workerPool.MessageReceived).ToString("N0") + ", busy: " + workerPool.WorkerBusyTime + " (avg " + workerPool.WorkerAverageBusyDuration.TotalMilliseconds.ToString("N3") + " ms)");

                    if (now.Subtract(last).TotalSeconds >= 10)
                    {
                        //dump("timer").GetAwaiter().GetResult();
                        last = now;
                        if (lastHandled == msgReceived)
                        {                         // STALL ?
                            Console.WriteLine("STALL! ");
                            done();
                        }
                        lastHandled = msgReceived;
                    }

                    if (msgReceived >= K * N)
                    {
                        dump("complete").GetAwaiter().GetResult();
                        done();
                    }
                }, null, 1000, 1000))
                {
                    var sw = Stopwatch.StartNew();

                    // start the workers
                    workerSignal.Set(async: true);
                    await Task.Delay(500);

                    await dump("workers started");

                    // start the clients
                    clientSignal.Set(async: true);

                    await Task.WhenAll(clients);

                    Console.WriteLine("Clients completed after " + sw.Elapsed);

                    await Task.WhenAll(workers);

                    Console.WriteLine("Workers completed after " + sw.Elapsed);
                }
            }
            finally
            {
                Console.WriteLine("---------------------------------------------------------------------------");
                Console.WriteLine("Transaction logs:");
                Console.WriteLine();

                Console.WriteLine(sb.ToString());
            }
        }
 public static DynamicKeySubspace Copy(this IDynamicKeySubspace subspace, ISubspaceContext?context = null)
 {
     Contract.NotNull(subspace);
     return(new DynamicKeySubspace(StealPrefix(subspace), subspace.KeyEncoder, context ?? subspace.Context));
 }
 internal DynamicPartition([NotNull] DynamicKeySubspace subspace)
 {
     Contract.Requires(subspace != null);
     this.Subspace = subspace;
 }
Example #20
0
 protected Slice ClassKey(string c, IDynamicKeySubspace subspace)
 {
     return(subspace.Keys.Encode("class", c));
 }
 public static DynamicKeySubspace Copy([NotNull] this IDynamicKeySubspace subspace)
 {
     Contract.NotNull(subspace, nameof(subspace));
     return(new DynamicKeySubspace(StealPrefix(subspace), subspace.Encoding));
 }
        private async Task <KeyValuePair <Slice, Slice> > FindRandomItem(IFdbTransaction tr, IDynamicKeySubspace ring)
        {
            var range = ring.Keys.ToRange();

            // start from a random position around the ring
            Slice key = ring.Keys.Encode(GetRandomId());

            // We want to find the next item in the clockwise direction. If we reach the end of the ring, we "wrap around" by starting again from the start
            // => So we do find_next(key <= x < MAX) and if that does not produce any result, we do a find_next(MIN <= x < key)

            // When the ring only contains a few items (or is empty), there is more than 50% change that we wont find anything in the first read.
            // To reduce the latency for this case, we will issue both range reads at the same time, and discard the second one if the first returned something.
            // This should reduce the latency in half when the ring is empty, or when it contains only items before the random key.

            var candidate = await tr.GetRange(key, range.End).FirstOrDefaultAsync();

            if (!candidate.Key.IsPresent)
            {
                candidate = await tr.GetRange(range.Begin, key).FirstOrDefaultAsync();
            }

            return(candidate);
        }
Example #23
0
 public State(IDynamicKeySubspace subspace)
 {
     Contract.Debug.Requires(subspace != null);
     this.Subspace = subspace;
 }
 public State(IDynamicKeySubspace subspace)
 {
     this.Subspace = subspace;
 }
Example #25
0
 internal State(IDynamicKeySubspace subspace, T defaultValue, IValueEncoder <T> encoder)
 {
     this.Subspace     = subspace;
     this.DefaultValue = defaultValue;
     this.Encoder      = encoder;
 }
Example #26
0
 internal State(FdbStringIntern layer, IDynamicKeySubspace subspace)
 {
     this.Layer    = layer;
     this.Subspace = subspace;
 }