Example #1
0
        public void TakeAsyncShouldBeThreadSafe()
        {
            const int expected   = 10;
            const int max        = 100;
            var       exit       = false;
            var       collection = new NagleBlockingCollection <int>(10000000);

            var take1 = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None);
            var take2 = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None);
            var take3 = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None);

            take1.ContinueWith(t => Console.WriteLine("Take1 done..."));
            take2.ContinueWith(t => Console.WriteLine("Take2 done..."));
            take3.ContinueWith(t => Console.WriteLine("Take3 done..."));
            Task.WhenAll(take1, take2, take3).ContinueWith(x => exit = true);

            Parallel.ForEach(Enumerable.Range(0, max).ToList(),
                             new ParallelOptions {
                MaxDegreeOfParallelism = 20
            },
                             async x =>
            {
                while (exit == false)
                {
                    await collection.AddAsync(x, CancellationToken.None);
                    Thread.Sleep(100);
                }
            });

            Console.WriteLine("Left in collection: {0}", collection.Count);
            Assert.That(take1.Result.Count, Is.EqualTo(expected));
            Assert.That(take2.Result.Count, Is.EqualTo(expected));
            Assert.That(take3.Result.Count, Is.EqualTo(expected));
            Assert.That(collection.Count, Is.LessThan(max - (expected * 3)));
        }
Example #2
0
        public async void TakeAsyncShouldReturnEvenWhileMoreDataArrives()
        {
            var exit       = false;
            var collection = new NagleBlockingCollection <int>(10000000);

            var sw       = Stopwatch.StartNew();
            var dataTask = collection.TakeBatch(10, TimeSpan.FromMilliseconds(5000), CancellationToken.None);


            var highVolumeAdding = Task.Factory.StartNew(async() =>
            {
                //high volume of data adds
                while (exit == false)
                {
                    await collection.AddAsync(1, CancellationToken.None);
                    Thread.Sleep(5);
                }
            });

            Console.WriteLine("Awaiting data...");
            await dataTask;

            Assert.That(dataTask.Result.Count, Is.EqualTo(10));
            Assert.That(sw.ElapsedMilliseconds, Is.LessThan(5000));
            exit = true;

            Console.WriteLine("Waiting to unwind test...");
            await highVolumeAdding;
        }
Example #3
0
        public void TakeAsyncShouldPlayNiceWithTPL()
        {
            const int expected   = 200;
            const int max        = 400;
            var       exit       = false;
            var       collection = new NagleBlockingCollection <int>(10000000);

            var dataTask = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None);

            dataTask.ContinueWith(x => exit = true);

            Parallel.ForEach(Enumerable.Range(0, max).ToList(),
                             new ParallelOptions {
                MaxDegreeOfParallelism = 20
            },
                             async x =>
            {
                while (exit == false)
                {
                    await collection.AddAsync(x, CancellationToken.None);
                    Thread.Sleep(100);
                }
            });

            Console.WriteLine("Left in collection: {0}", collection.Count);
            Assert.That(dataTask.Result.Count, Is.EqualTo(expected));
            Assert.That(collection.Count, Is.LessThan(max - expected));
        }
Example #4
0
        private async Task BatchSendAsync()
        {
            var outstandingSendTasks = new System.Collections.Concurrent.ConcurrentDictionary <Task, Task>();

            while (_nagleBlockingCollection.IsCompleted == false || _nagleBlockingCollection.Count > 0)
            {
                List <TopicMessage> batch = null;

                try
                {
                    try
                    {
                        batch = await _nagleBlockingCollection.TakeBatch(BatchSize, BatchDelayTime, _stopToken.Token).ConfigureAwait(false);
                    }
                    catch (OperationCanceledException ex)
                    {
                        //TODO log that the operation was canceled, this only happens during a dispose
                    }

                    if (_nagleBlockingCollection.IsCompleted && _nagleBlockingCollection.Count > 0)
                    {
                        batch = batch ?? new List <TopicMessage>(_nagleBlockingCollection.Count);

                        //Drain any messages remaining in the queue and add them to the send batch
                        batch.AddRange(_nagleBlockingCollection.Drain());
                    }

                    //we want to fire the batch without blocking and then move on to fire another one
                    var sendTask = ProduceAndSendBatchAsync(batch, _stopToken.Token);

                    outstandingSendTasks.TryAdd(sendTask, sendTask);

                    var sendTaskCleanup = sendTask.ContinueWith(result =>
                    {
                        if (result.IsFaulted && batch != null)
                        {
                            batch.ForEach(x => x.Tcs.TrySetException(result.ExtractException()));
                        }

                        //TODO add statistics tracking
                        outstandingSendTasks.TryRemove(sendTask, out sendTask);
                    });
                }
                catch (Exception ex)
                {
                    if (batch != null)
                    {
                        batch.ForEach(x => x.Tcs.TrySetException(ex));
                    }
                }
            }

            var referenceToOutstanding = outstandingSendTasks.Values.ToList();

            if (referenceToOutstanding.Count > 0)
            {
                await Task.WhenAll(referenceToOutstanding).ConfigureAwait(false);
            }
        }
Example #5
0
        public async void TakeBatchShouldRemoveItemsFromCollection()
        {
            const int expectedCount = 10;

            var collection = new NagleBlockingCollection <int>(100);
            await collection.AddRangeAsync(Enumerable.Range(0, expectedCount), CancellationToken.None);

            var data = await collection.TakeBatch(expectedCount, TimeSpan.FromMilliseconds(100), CancellationToken.None);

            Assert.That(data.Count, Is.EqualTo(expectedCount));
            Assert.That(collection.Count, Is.EqualTo(0));
        }
Example #6
0
        public async void TakeAsyncShouldReturnAsSoonAsBatchSizeArrived()
        {
            var collection = new NagleBlockingCollection <int>(100);

            var dataTask = collection.TakeBatch(10, TimeSpan.FromSeconds(5), CancellationToken.None);

            collection.AddRangeAsync(Enumerable.Range(0, 10), CancellationToken.None);

            await dataTask;

            Assert.That(collection.Count, Is.EqualTo(0));
        }
Example #7
0
        public async void CollectionShouldWaitXForBatchSizeToCollect()
        {
            const int expectedDelay = 100;
            const int expectedCount = 10;

            var collection = new NagleBlockingCollection <int>(100);
            await collection.AddRangeAsync(Enumerable.Range(0, expectedCount), CancellationToken.None);

            var sw   = Stopwatch.StartNew();
            var data = await collection.TakeBatch(expectedCount + 1, TimeSpan.FromMilliseconds(expectedDelay), CancellationToken.None);

            Assert.That(sw.ElapsedMilliseconds, Is.GreaterThanOrEqualTo(expectedDelay));
            Assert.That(data.Count, Is.EqualTo(expectedCount));
        }
Example #8
0
        public async void CollectonTakeShouldBeAbleToCancel()
        {
            var cancelSource = new CancellationTokenSource();
            var collection   = new NagleBlockingCollection <int>(100);

            Task.Delay(TimeSpan.FromMilliseconds(100)).ContinueWith(t => cancelSource.Cancel());

            var sw   = Stopwatch.StartNew();
            var data = await collection.TakeBatch(10, TimeSpan.FromMilliseconds(500), cancelSource.Token);

            sw.Stop();

            Assert.That(sw.ElapsedMilliseconds, Is.LessThan(300));
        }
Example #9
0
        public async void CollectionShouldReportCorrectBufferCount()
        {
            var collection = new NagleBlockingCollection <int>(100);

            var dataTask = collection.TakeBatch(10, TimeSpan.FromSeconds(5), CancellationToken.None);

            await collection.AddRangeAsync(Enumerable.Range(0, 9), CancellationToken.None);

            Assert.That(collection.Count, Is.EqualTo(9));

            collection.AddAsync(1, CancellationToken.None);
            var data = await dataTask;

            Assert.That(data.Count, Is.EqualTo(10));
            Assert.That(collection.Count, Is.EqualTo(0));
        }
Example #10
0
        public async void EnsureCollectionBlocksAtCapacity()
        {
            const int blockingCount = 10;
            const int expectedCount = 5;

            var collection = new NagleBlockingCollection <int>(blockingCount);

            var addTask = Task.Factory.StartNew(() => collection.AddRangeAsync(Enumerable.Range(0, blockingCount + expectedCount),
                                                                               CancellationToken.None).Wait());

            TaskTest.WaitFor(() => collection.Count >= blockingCount);

            Assert.That(collection.Count, Is.EqualTo(blockingCount), "The collection should only contain 10 items.");
            Assert.That(addTask.Status, Is.EqualTo(TaskStatus.Running), "The task should be blocking.");

            //unblock the collection
            await collection.TakeBatch(blockingCount, TimeSpan.FromMilliseconds(100), CancellationToken.None);

            await addTask;

            Assert.That(collection.Count, Is.EqualTo(expectedCount));
            Assert.That(addTask.Status, Is.EqualTo(TaskStatus.RanToCompletion));
        }
        public async void EnsureCollectionBlocksAtCapacity()
        {
            const int blockingCount = 10;
            const int expectedCount = 5;

            var collection = new NagleBlockingCollection<int>(blockingCount);

            var addTask = Task.Factory.StartNew(() => collection.AddRangeAsync(Enumerable.Range(0, blockingCount + expectedCount), 
                CancellationToken.None).Wait());

            TaskTest.WaitFor(() => collection.Count >= blockingCount);

            Assert.That(collection.Count, Is.EqualTo(blockingCount), "The collection should only contain 10 items.");
            Assert.That(addTask.Status, Is.EqualTo(TaskStatus.Running), "The task should be blocking.");

            //unblock the collection
            await collection.TakeBatch(blockingCount, TimeSpan.FromMilliseconds(100), CancellationToken.None);

            await addTask;

            Assert.That(collection.Count, Is.EqualTo(expectedCount));
            Assert.That(addTask.Status, Is.EqualTo(TaskStatus.RanToCompletion));
        }
        public async void CollectionShouldWaitXForBatchSizeToCollect()
        {
            const int expectedDelay = 100;
            const int expectedCount = 10;

            var collection = new NagleBlockingCollection<int>(100);
            await collection.AddRangeAsync(Enumerable.Range(0, expectedCount), CancellationToken.None);

            var sw = Stopwatch.StartNew();
            var data = await collection.TakeBatch(expectedCount + 1, TimeSpan.FromMilliseconds(expectedDelay), CancellationToken.None);

            Assert.That(sw.ElapsedMilliseconds, Is.GreaterThanOrEqualTo(expectedDelay));
            Assert.That(data.Count, Is.EqualTo(expectedCount));
        }
        public async void TakeAsyncShouldReturnAsSoonAsBatchSizeArrived()
        {
            var collection = new NagleBlockingCollection<int>(100);

            var dataTask = collection.TakeBatch(10, TimeSpan.FromSeconds(5), CancellationToken.None);

            collection.AddRangeAsync(Enumerable.Range(0, 10), CancellationToken.None);

            await dataTask;

            Assert.That(collection.Count, Is.EqualTo(0));

        }
        public async void TakeAsyncShouldReturnEvenWhileMoreDataArrives()
        {
            var exit = false;
            var collection = new NagleBlockingCollection<int>(10000000);

            var sw = Stopwatch.StartNew();
            var dataTask = collection.TakeBatch(10, TimeSpan.FromMilliseconds(5000), CancellationToken.None);


            var highVolumeAdding = Task.Factory.StartNew(async () =>
            {
                //high volume of data adds
                while (exit == false)
                {
                    await collection.AddAsync(1, CancellationToken.None);
                    Thread.Sleep(5);
                }
            });

            Console.WriteLine("Awaiting data...");
            await dataTask;

            Assert.That(dataTask.Result.Count, Is.EqualTo(10));
            Assert.That(sw.ElapsedMilliseconds, Is.LessThan(5000));
            exit = true;

            Console.WriteLine("Waiting to unwind test...");
            await highVolumeAdding;
        }
        public void TakeAsyncShouldPlayNiceWithTPL()
        {
            const int expected = 200;
            const int max = 400;
            var exit = false;
            var collection = new NagleBlockingCollection<int>(10000000);

            var dataTask = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None);

            dataTask.ContinueWith(x => exit = true);

            Parallel.ForEach(Enumerable.Range(0, max).ToList(),
                   new ParallelOptions { MaxDegreeOfParallelism = 20 },
                   async x =>
                   {
                       while (exit == false)
                       {
                           await collection.AddAsync(x, CancellationToken.None);
                           Thread.Sleep(100);
                       }
                   });

            Console.WriteLine("Left in collection: {0}", collection.Count);
            Assert.That(dataTask.Result.Count, Is.EqualTo(expected));
            Assert.That(collection.Count, Is.LessThan(max - expected));
        }
        public void TakeAsyncShouldBeThreadSafe()
        {
            const int expected = 10;
            const int max = 100;
            var exit = false;
            var collection = new NagleBlockingCollection<int>(10000000);

            var take1 = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None);
            var take2 = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None);
            var take3 = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None);

            take1.ContinueWith(t => Console.WriteLine("Take1 done..."));
            take2.ContinueWith(t => Console.WriteLine("Take2 done..."));
            take3.ContinueWith(t => Console.WriteLine("Take3 done..."));
            Task.WhenAll(take1, take2, take3).ContinueWith(x => exit = true);

            Parallel.ForEach(Enumerable.Range(0, max).ToList(),
                   new ParallelOptions { MaxDegreeOfParallelism = 20 },
                   async x =>
                   {
                       while (exit == false)
                       {
                           await collection.AddAsync(x, CancellationToken.None);
                           Thread.Sleep(100);
                       }
                   });

            Console.WriteLine("Left in collection: {0}", collection.Count);
            Assert.That(take1.Result.Count, Is.EqualTo(expected));
            Assert.That(take2.Result.Count, Is.EqualTo(expected));
            Assert.That(take3.Result.Count, Is.EqualTo(expected));
            Assert.That(collection.Count, Is.LessThan(max - (expected*3)));
        }
        public async void CollectionShouldReportCorrectBufferCount()
        {
            var collection = new NagleBlockingCollection<int>(100);

            var dataTask = collection.TakeBatch(10, TimeSpan.FromSeconds(5), CancellationToken.None);

            await collection.AddRangeAsync(Enumerable.Range(0, 9), CancellationToken.None);
            Assert.That(collection.Count, Is.EqualTo(9));

            collection.AddAsync(1, CancellationToken.None);
            var data = await dataTask;
            Assert.That(data.Count, Is.EqualTo(10));
            Assert.That(collection.Count, Is.EqualTo(0));
        }
        public async void TakeBatchShouldRemoveItemsFromCollection()
        {
            const int expectedCount = 10;

            var collection = new NagleBlockingCollection<int>(100);
            await collection.AddRangeAsync(Enumerable.Range(0, expectedCount), CancellationToken.None);

            var data = await collection.TakeBatch(expectedCount, TimeSpan.FromMilliseconds(100), CancellationToken.None);

            Assert.That(data.Count, Is.EqualTo(expectedCount));
            Assert.That(collection.Count, Is.EqualTo(0));
        }
        public async void CollectonTakeShouldBeAbleToCancel()
        {
            var cancelSource = new CancellationTokenSource();
            var collection = new NagleBlockingCollection<int>(100);

            Task.Delay(TimeSpan.FromMilliseconds(100)).ContinueWith(t => cancelSource.Cancel());

            var sw = Stopwatch.StartNew();
            var data = await collection.TakeBatch(10, TimeSpan.FromMilliseconds(500), cancelSource.Token);
            sw.Stop();

            Assert.That(sw.ElapsedMilliseconds, Is.LessThan(300));
        }