Example #1
0
        public void Compare_SameInstance_ReturnsTrue()
        {
            var config1 = new Confluent.Kafka.ConsumerConfig
            {
                BootstrapServers            = "myserver",
                PartitionAssignmentStrategy = Confluent.Kafka.PartitionAssignmentStrategy.Range,
                EnableAutoCommit            = false
            };
            var config2 = config1;

            _dictionary.TryAdd(config1, null);

            _dictionary.Should().ContainKey(config2);
        }
        public async Task RunAsync_SubProcessListSupplied_AllAreRun(int processCount)
        {
            // arrange
            var processId    = 0;
            var expectedKeys = Enumerable.Range(1, processCount);
            var dict         = new ConcurrentDictionary <int, DateTime>();

            _fixture.Register(() =>
            {
                var process = A.Fake <IProcess>();
                A.CallTo(() => process.RunAsync(CancellationToken.None)).ReturnsLazily(() =>
                {
                    var id = Interlocked.Increment(ref processId);
                    dict.TryAdd(id, DateTime.Now);
                    return(Task.CompletedTask);
                });
                return(process);
            });

            var processes = _fixture.CreateMany <IProcess>(processCount);
            var sut       = new ParallelProcess(processes);

            // act
            await sut.RunAsync(CancellationToken.None);

            // assert
            dict.Should().ContainKeys(expectedKeys);
        }
Example #3
0
        public async Task ShouldRunThreadsWithDistinctKeysInParallel()
        {
            // Arrange
            var currentParallelism = 0;
            var maxParallelism     = 0;
            var parallelismLock    = new object();
            var index = new ConcurrentDictionary <string, IKeyedSemaphore>();

            using var keyedSemaphores = new KeyedSemaphoresCollection(index);

            // 100 threads, 100 keys
            var threads = Enumerable.Range(0, 100)
                          .Select(i => Task.Run(async() => await OccupyTheLockALittleBit(i).ConfigureAwait(false)))
                          .ToList();

            // Act
            await Task.WhenAll(threads).ConfigureAwait(false);

            maxParallelism.Should().BeGreaterThan(10);
            index.Should().BeEmpty();

            async Task OccupyTheLockALittleBit(int key)
            {
                var keyedSemaphore = keyedSemaphores.Provide(key.ToString());

                try
                {
                    await keyedSemaphore.WaitAsync().ConfigureAwait(false);

                    try
                    {
                        var incrementedCurrentParallelism = Interlocked.Increment(ref currentParallelism);


                        lock (parallelismLock)
                        {
                            maxParallelism = Math.Max(incrementedCurrentParallelism, maxParallelism);
                        }

                        const int delay = 250;


                        await Task.Delay(TimeSpan.FromMilliseconds(delay)).ConfigureAwait(false);

                        Interlocked.Decrement(ref currentParallelism);
                    }
                    finally
                    {
                        keyedSemaphore.Release();
                    }
                }
                finally
                {
                    keyedSemaphore.Dispose();
                }
            }
        }
Example #4
0
        public void Analyze_LineHasOneWord_ShouldBeAddedToDict()
        {
            var dict = new ConcurrentDictionary <string, int>();
            var line = "line";

            _lineSplitter.Setup(x => x.Split(line)).Returns(new[] { line });

            _sut.Analyze(line, dict);

            dict.Should().Contain(new KeyValuePair <string, int>(line, 1));
            _lineSplitter.Verify();
        }
Example #5
0
        public void Analyze_LineHasFewWords_DictShouldHasCorrectCount()
        {
            var dict = new ConcurrentDictionary <string, int>();
            var word = "line";
            var line = $"{word}{word}{word}";

            _lineSplitter.Setup(x => x.Split(line)).Returns(new[] { word, word, word });

            _sut.Analyze(line, dict);

            dict.Should().Contain(new KeyValuePair <string, int>(word, 3));
            _lineSplitter.Verify();
        }
        public async Task An_interval_can_be_specified_before_which_a_released_lease_will_be_granted_again()
        {
            var tally       = new ConcurrentDictionary <string, int>();
            var distributor = CreateDistributor(waitInterval: TimeSpan.FromMilliseconds(500)).Trace();

            distributor.OnReceive(async w =>
            {
                tally.AddOrUpdate(w.Lease.Name,
                                  addValueFactory: s => 1,
                                  updateValueFactory: (s, v) => v + 1);
            });

            await distributor.Start();

            await Task.Delay(100);

            await distributor.Stop();

            tally.Count.Should().Be(10);
            tally.Should().ContainKeys("1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
            tally.Should().ContainValues(1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
        }
Example #7
0
        public void Learn_should_store_and_log_new_health_when_health_gets_increased_and_there_was_not_old_stored_health()
        {
            SetupTuningAction(AdaptiveHealthAction.Increase);

            implementation.CreateDefaultHealth().Returns(10);
            implementation.IncreaseHealth(10).Returns(20);

            modifier.Learn(CreateResult(replica1), storageProvider);

            storage.Should().Contain(replica1, 20);

            implementation.Received().LogHealthChange(replica1, 10, 20, log);
        }
        public void Learn_should_correctly_store_new_health(bool?old, bool isLeader, bool?expected)
        {
            if (old.HasValue)
            {
                storage[replica] = old.Value;
            }

            resultDetector.IsLeaderResult(result).Returns(isLeader);

            modifier.Learn(result, storageProvider);

            if (expected.HasValue)
            {
                storage[replica].Should().Be(expected.Value);
            }
            else
            {
                storage.Should().NotContainKey(replica);
            }
        }
        public virtual async Task A_lease_can_be_extended()
        {
            var tally        = new ConcurrentDictionary <string, int>();
            var pool         = DateTimeOffset.UtcNow.Ticks.ToString();
            var distributor1 = CreateDistributor(pool: pool).Trace();
            var distributor2 = CreateDistributor(pool: pool).Trace();

            Func <Lease <int>, Task> onReceive = async lease =>
            {
                tally.AddOrUpdate(lease.Leasable.Name,
                                  addValueFactory: s => 1,
                                  updateValueFactory: (s, v) => v + 1);

                if (lease.Leasable.Name == "5")
                {
                    // extend the lease
                    await lease.Extend(TimeSpan.FromDays(2));

                    // wait longer than the lease would normally last
                    await Task.Delay((int)(DefaultLeaseDuration.TotalMilliseconds * 5));
                }
            };

            distributor1.OnReceive(onReceive);
            distributor2.OnReceive(onReceive);
            await distributor1.Start();

            await distributor2.Start();

            await Task.Delay((int)(DefaultLeaseDuration.TotalMilliseconds * 2.5));

            await distributor1.Stop();

            await distributor2.Stop();

            Console.WriteLine(tally.ToLogString());

            tally.Should().ContainKey("5")
            .And
            .Subject["5"].Should().Be(1);
        }
Example #10
0
        public void Remove_with_value_should_not_remove_anything_when_value_does_not_match()
        {
            dictionary.Remove("key1", 2).Should().BeFalse();

            dictionary.Should().HaveCount(3);
        }
        public virtual async Task A_lease_can_be_extended()
        {
            var tally = new ConcurrentDictionary<string, int>();
            var scope = DateTimeOffset.UtcNow.Ticks.ToString();
            var distributor1 = CreateDistributor(scope: scope).Trace();
            var distributor2 = CreateDistributor(scope: scope).Trace();

            Func<Lease, Task> onReceive = async lease =>
            {
                tally.AddOrUpdate(lease.LeasableResource.Name,
                                  addValueFactory: s => 1,
                                  updateValueFactory: (s, v) => v + 1);

                if (lease.LeasableResource.Name == "5")
                {
                    // extend the lease
                    await lease.Extend(TimeSpan.FromDays(2));

                    // wait longer than the lease would normally last
                    await Task.Delay((int) (DefaultLeaseDuration.TotalMilliseconds*5));
                }
            };

            distributor1.OnReceive(onReceive);
            distributor2.OnReceive(onReceive);
            await distributor1.Start();
            await distributor2.Start();
            await Task.Delay((int) (DefaultLeaseDuration.TotalMilliseconds * 2.5));
            await distributor1.Stop();
            await distributor2.Stop();

            Console.WriteLine(tally.ToLogString());

            tally.Should().ContainKey("5")
                 .And
                 .Subject["5"].Should().Be(1);
        }
        public async Task An_interval_can_be_specified_before_which_a_released_lease_will_be_granted_again()
        {
            var tally = new ConcurrentDictionary<string, int>();
            var distributor = CreateDistributor(waitInterval: TimeSpan.FromMilliseconds(5000)).Trace();
            var countdown = new AsyncCountdownEvent(10);

            distributor.OnReceive(async lease =>
            {
                tally.AddOrUpdate(lease.LeasableResource.Name,
                                  addValueFactory: s => 1,
                                  updateValueFactory: (s, v) => v + 1);
                countdown.Signal();
            });

            await distributor.Start();
            await countdown.WaitAsync().Timeout();
            await distributor.Stop();

            tally.Count.Should().Be(10);
            tally.Should().ContainKeys("1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
            tally.Should().ContainValues(1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
        }
Example #13
0
        public async Task ShouldRunThreadsWithSameKeysLinearly()
        {
            // Arrange
            var runningTasksIndex  = new ConcurrentDictionary <int, int>();
            var parallelismLock    = new object();
            var currentParallelism = 0;
            var maxParallelism     = 0;
            var index = new ConcurrentDictionary <string, IKeyedSemaphore>();

            using var keyedSemaphores = new KeyedSemaphoresCollection(index);

            // 100 threads, 10 keys
            var threads = Enumerable.Range(0, 100)
                          .Select(i => Task.Run(async() => await OccupyTheLockALittleBit(i % 10).ConfigureAwait(false)))
                          .ToList();

            // Act + Assert
            await Task.WhenAll(threads).ConfigureAwait(false);

            maxParallelism.Should().BeLessOrEqualTo(10);
            index.Should().BeEmpty();

            async Task OccupyTheLockALittleBit(int key)
            {
                var keyedSemaphore = keyedSemaphores.Provide(key.ToString());

                try
                {
                    await keyedSemaphore.WaitAsync().ConfigureAwait(false);

                    try
                    {
                        var incrementedCurrentParallelism = Interlocked.Increment(ref currentParallelism);


                        lock (parallelismLock)
                        {
                            maxParallelism = Math.Max(incrementedCurrentParallelism, maxParallelism);
                        }

                        var currentTaskId = Task.CurrentId ?? -1;
                        if (runningTasksIndex.TryGetValue(key, out var otherThread))
                        {
                            throw new Exception($"Thread #{currentTaskId} acquired a lock using key ${key} " +
                                                $"but another thread #{otherThread} is also still running using this key!");
                        }

                        runningTasksIndex[key] = currentTaskId;

                        const int delay = 10;

                        await Task.Delay(TimeSpan.FromMilliseconds(delay)).ConfigureAwait(false);

                        if (!runningTasksIndex.TryRemove(key, out var value))
                        {
                            var ex = new Exception($"Thread #{currentTaskId} has finished " +
                                                   $"but when trying to cleanup the running threads index, the value is already gone");

                            throw ex;
                        }

                        if (value != currentTaskId)
                        {
                            var ex = new Exception($"Thread #{currentTaskId} has finished and has removed itself from the running threads index," +
                                                   $" but that index contained an incorrect value: #{value}!");

                            throw ex;
                        }

                        Interlocked.Decrement(ref currentParallelism);
                    }
                    finally
                    {
                        keyedSemaphore.Release();
                    }
                }
                finally
                {
                    keyedSemaphore.Dispose();
                }
            }
        }
Example #14
0
        public async Task DisposingTheKeyedSemaphoresCollectionShouldInterruptAllThreads()
        {
            // Arrange
            var runningTasksIndex  = new ConcurrentDictionary <int, int>();
            var parallelismLock    = new object();
            var currentParallelism = 0;
            var maxParallelism     = 0;
            var random             = new Random();
            var index = new ConcurrentDictionary <string, IKeyedSemaphore>();

            using var keyedSemaphores = new KeyedSemaphoresCollection(index);

            // 50 threads, 1 key
            var numberOfThreads = 50;

            Log($"Starting {numberOfThreads} threads");
            var threads = Enumerable.Range(0, numberOfThreads)
                          .Select(i => Task.Run(async() => await OccupyTheLockALittleBit(i, 1).ConfigureAwait(false)))
                          .ToList();

            // Act + Assert
            await Task.Delay(100);

            Log($"[WAITING] keyedSemaphores.Dispose");
            keyedSemaphores.Dispose();
            Log($"[OK]      keyedSemaphores.Dispose");

            await Task.WhenAll(threads).ConfigureAwait(false);

            maxParallelism.Should().Be(1);
            index.Should().BeEmpty();

            async Task OccupyTheLockALittleBit(int thread, int key)
            {
                var currentTaskId = Task.CurrentId ?? -1;
                var delay         = random.Next(0, 200);

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

                IKeyedSemaphore keyedSemaphore = null;

                try
                {
                    try
                    {
                        Log($"[{thread, 2}] [WAITING] KeyedSemaphores.Provide    : {key,3}");
                        keyedSemaphore = keyedSemaphores.Provide(key.ToString());
                        Log($"[{thread, 2}] [OK]      KeyedSemaphores.Provide    : {key,3}");
                    }
                    catch (ObjectDisposedException)
                    {
                        Log($"[{thread, 2}] [DISPOSED]KeyedSemaphores.Provide    : {key,3}");
                        return;
                    }

                    try
                    {
                        Log($"[{thread, 2}] [WAITING] KeyedSemaphores.WaitAsync  : {key,3}");
                        await keyedSemaphore.WaitAsync();

                        Log($"[{thread, 2}] [OK]      KeyedSemaphores.WaitAsync  : {key,3}");
                    }
                    catch (OperationCanceledException)
                    {
                        Log($"[{thread, 2}] [CANCELED]KeyedSemaphores.WaitAsync  : {key,3}");
                        return;
                    }

                    try
                    {
                        var incrementedCurrentParallelism = Interlocked.Increment(ref currentParallelism);

                        lock (parallelismLock)
                        {
                            maxParallelism = Math.Max(incrementedCurrentParallelism, maxParallelism);
                        }

                        if (runningTasksIndex.TryGetValue(key, out var otherThread))
                        {
                            throw new Exception($"[{thread, 2}] Task [{currentTaskId,3}] has a lock for key ${key} " +
                                                $"but another task [{otherThread,3}] also has an active lock for this key!");
                        }

                        runningTasksIndex[key] = currentTaskId;

                        if (!runningTasksIndex.TryRemove(key, out var value))
                        {
                            var ex = new Exception($"[{thread, 2}] Task [{currentTaskId,3}] has finished " +
                                                   $"but when trying to cleanup the running tasks index, the value is already gone");

                            throw ex;
                        }

                        if (value != currentTaskId)
                        {
                            var ex = new Exception($"[{thread, 2}] Task [{currentTaskId,3}] has finished and has removed itself from the running tasks index," +
                                                   $" but that index contained a task ID of another task: [{value}]!");

                            throw ex;
                        }

                        Interlocked.Decrement(ref currentParallelism);
                    }
                    finally
                    {
                        try
                        {
                            Log($"[{thread, 2}] [WAITING] KeyedSemaphore.Release     : {key,3}");
                            keyedSemaphore.Release();
                            Log($"[{thread, 2}] [OK]      KeyedSemaphore.Release     : {key,3}");
                        }
                        catch (ObjectDisposedException e)
                        {
                            Log($"[{thread, 2}] [DISPOSED]KeyedSemaphore.Release     : {e}");
                        }
                    }
                }
                finally
                {
                    if (keyedSemaphore != null)
                    {
                        Log($"[{thread, 2}] [WAITING] KeyedSemaphore.Dispose     : {key,3}");
                        keyedSemaphore.Dispose();
                        Log($"[{thread, 2}] [OK]      KeyedSemaphore.Dispose     : {key,3}");
                    }
                }
            }
        }
 public void Constructor_CalledMultipleTimes_ExpectStreamAddsItselfToTheSessionCollectionWithDifferentGuids()
 {
     var sessionCollection = new ConcurrentDictionary<Guid, IEventStream>();
     using (var firstStream = new NEventStoreSessionStream(sessionCollection, DummyEventStream()))
     {
         using (var secondStream = new NEventStoreSessionStream(sessionCollection, DummyEventStream()))
         {
             sessionCollection.Should().ContainValues(firstStream, secondStream);
         }
     }
 }
Example #16
0
        public async Task ShouldNeverCreateTwoSemaphoresForTheSameKey()
        {
            // Arrange
            var runningTasksIndex  = new ConcurrentDictionary <int, int>();
            var parallelismLock    = new object();
            var currentParallelism = 0;
            var maxParallelism     = 0;
            var random             = new Random();
            var index = new ConcurrentDictionary <string, IKeyedSemaphore>();

            using var keyedSemaphores = new KeyedSemaphoresCollection(index);

            // Many threads, 1 key
            var threads = Enumerable.Range(0, 100)
                          .Select(i => Task.Run(async() => await OccupyTheLockALittleBit(1).ConfigureAwait(false)))
                          .ToList();

            // Act + Assert
            await Task.WhenAll(threads).ConfigureAwait(false);

            maxParallelism.Should().Be(1);
            index.Should().BeEmpty();


            async Task OccupyTheLockALittleBit(int key)
            {
                var currentTaskId = Task.CurrentId ?? -1;
                var delay         = random.Next(500);


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


                IKeyedSemaphore keyedSemaphore = null;

                try
                {
                    keyedSemaphore = keyedSemaphores.Provide(key.ToString());


                    await keyedSemaphore.WaitAsync().ConfigureAwait(false);

                    try
                    {
                        var incrementedCurrentParallelism = Interlocked.Increment(ref currentParallelism);


                        lock (parallelismLock)
                        {
                            maxParallelism = Math.Max(incrementedCurrentParallelism, maxParallelism);
                        }

                        if (runningTasksIndex.TryGetValue(key, out var otherThread))
                        {
                            throw new Exception($"Task [{currentTaskId,3}] has a lock for key ${key} " +
                                                $"but another task [{otherThread,3}] also has an active lock for this key!");
                        }

                        runningTasksIndex[key] = currentTaskId;

                        if (!runningTasksIndex.TryRemove(key, out var value))
                        {
                            var ex = new Exception($"Task [{currentTaskId,3}] has finished " +
                                                   $"but when trying to cleanup the running tasks index, the value is already gone");

                            throw ex;
                        }

                        if (value != currentTaskId)
                        {
                            var ex = new Exception($"Task [{currentTaskId,3}] has finished and has removed itself from the running tasks index," +
                                                   $" but that index contained a task ID of another task: [{value}]!");

                            throw ex;
                        }

                        Interlocked.Decrement(ref currentParallelism);
                    }
                    finally
                    {
                        keyedSemaphore.Release();
                    }
                }
                finally
                {
                    keyedSemaphore?.Dispose();
                }
            }
        }
        public void Dispose_CalledWhenEventStreamThrowsAnException_ExpectStreamRemovesItselfFromTheSessionCollection()
        {
            var eventStream = StubEventStream();
            eventStream.When(x => x.Dispose()).Do(_ => { throw new Exception(); });

            var sessionCollection = new ConcurrentDictionary<Guid, IEventStream>();
            var stream = new NEventStoreSessionStream(sessionCollection, eventStream);
            stream.Invoking(x => x.Dispose()).ShouldThrow<Exception>();

            sessionCollection.Should().NotContainValue(stream);
        }
Example #18
0
        public void Learn_method_should_do_nothing_when_response_verdict_is_accept()
        {
            modifier.Learn(CreateResult(replica1, ResponseVerdict.Accept), storageProvider);

            storage.Should().BeEmpty();
        }
 public void Dispose_Called_ExpectStreamRemovesItselfFromTheSessionCollection()
 {
     var sessionCollection = new ConcurrentDictionary<Guid, IEventStream>();
     var stream = new NEventStoreSessionStream(sessionCollection, DummyEventStream());
     stream.Dispose();
     sessionCollection.Should().BeEmpty();
 }