Beispiel #1
0
        public async Task CacheManager_Stats_Threaded <T>(T cache)
            where T : ICacheManager <object>
        {
            var puts       = cache.CacheHandles.Select(p => p.Stats.GetStatistic(CacheStatsCounterType.PutCalls));
            var adds       = cache.CacheHandles.Select(p => p.Stats.GetStatistic(CacheStatsCounterType.AddCalls));
            var threads    = 4;
            var iterations = 10;
            var putCounter = 0;

            using (cache)
            {
                var key = Guid.NewGuid().ToString();
                await ThreadTestHelper.RunAsync(
                    async() =>
                {
                    cache.Add(key, "hi");
                    cache.Put(key, "changed");
                    Interlocked.Increment(ref putCounter);
                    await Task.Delay(0);
                },
                    threads,
                    iterations);
            }

            await Task.Delay(20);

            putCounter.Should().Be(threads * iterations);
            puts.ShouldAllBeEquivalentTo(
                Enumerable.Repeat(threads * iterations, cache.CacheHandles.Count()));
        }
        public async Task Redis_NoRaceCondition_WithUpdate()
        {
            using (var cache = CacheFactory.Build <RaceConditionTestElement>(settings =>
            {
                settings.WithMaxRetries(int.MaxValue);
                settings.WithUpdateMode(CacheUpdateMode.Up)
                .WithJsonSerializer()
                .WithRedisCacheHandle("default")
                .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMinutes(20));
                settings.WithRedisConfiguration("default", config =>
                {
                    config.WithAllowAdmin()
                    .WithDatabase(7)
                    .WithEndpoint("127.0.0.1", 6379);
                });
            }))
            {
                var key = Guid.NewGuid().ToString();
                cache.Remove(key);
                cache.Add(key, new RaceConditionTestElement()
                {
                    Counter = 0
                });
                int numThreads          = 5;
                int iterations          = 10;
                int numInnerIterations  = 10;
                int countCasModifyCalls = 0;

                // act
                await ThreadTestHelper.RunAsync(
                    async() =>
                {
                    for (int i = 0; i < numInnerIterations; i++)
                    {
                        cache.Update(
                            key,
                            (value) =>
                        {
                            value.Counter++;
                            Interlocked.Increment(ref countCasModifyCalls);
                            return(value);
                        },
                            int.MaxValue);

                        await Task.Delay(0);
                    }
                },
                    numThreads,
                    iterations);

                // assert
                await Task.Delay(100);

                var result = cache.Get(key);
                result.Should().NotBeNull();
                result.Counter.Should().Be(numThreads * numInnerIterations * iterations, "counter should be exactly the expected value");
                countCasModifyCalls.Should().BeGreaterThan((int)result.Counter, "we expect many version collisions, so cas calls should be way higher then the count result");
            }
        }
Beispiel #3
0
        public async Task Memcached_NoRaceCondition_WithCasButTooFiewRetries()
        {
            // arrange
            using (var cache = CacheFactory.FromConfiguration <RaceConditionTestElement>(
                       TestManagers.BaseConfiguration.Builder
                       .WithUpdateMode(CacheUpdateMode.Up)
                       .WithMemcachedCacheHandle(Configuration)
                       .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromHours(10))
                       .Build()))
            {
                cache.Remove("myCounter");
                cache.Add("myCounter", new RaceConditionTestElement()
                {
                    Counter = 0
                });
                int numThreads          = 5;
                int iterations          = 10;
                int numInnerIterations  = 10;
                int countCasModifyCalls = 0;
                int retries             = 0;

                // act
                await ThreadTestHelper.RunAsync(
                    async() =>
                {
                    for (int i = 0; i < numInnerIterations; i++)
                    {
                        RaceConditionTestElement newValue;
                        cache.TryUpdate(
                            "myCounter",
                            (value) =>
                        {
                            value.Counter++;
                            Interlocked.Increment(ref countCasModifyCalls);
                            return(value);
                        },
                            retries,
                            out newValue);
                    }

                    await Task.Delay(10);
                },
                    numThreads,
                    iterations);

                // assert
                var result = cache.Get("myCounter");
                result.Should().NotBeNull();
                Trace.TraceInformation("Counter increased to " + result.Counter + " cas calls needed " + countCasModifyCalls);
                result.Counter.Should().BeLessThan(
                    numThreads * numInnerIterations * iterations,
                    "counter should NOT be exactly the expected value");
                countCasModifyCalls.Should().Be(
                    numThreads * numInnerIterations * iterations,
                    "with one try, we exactly one update call per iteration");
            }
        }
Beispiel #4
0
        public async Task Memcached_NoRaceCondition_WithCasHandling()
        {
            // arrange
            using (var cache = CacheFactory.FromConfiguration <RaceConditionTestElement>(
                       TestManagers.BaseConfiguration.Builder
                       .WithMaxRetries(int.MaxValue)
                       .WithSystemRuntimeCacheHandle()
                       .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMilliseconds(1))
                       .And
                       .WithMemcachedCacheHandle(Configuration)
                       .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromSeconds(60))
                       .Build()))
            {
                var key = Guid.NewGuid().ToString();
                cache.Remove(key);
                cache.Add(key, new RaceConditionTestElement()
                {
                    Counter = 0
                }).Should().BeTrue();
                int numThreads          = 5;
                int iterations          = 10;
                int numInnerIterations  = 10;
                int countCasModifyCalls = 0;

                // act
                await ThreadTestHelper.RunAsync(
                    async() =>
                {
                    for (int i = 0; i < numInnerIterations; i++)
                    {
                        cache.Update(
                            key,
                            (value) =>
                        {
                            value.Counter++;
                            Interlocked.Increment(ref countCasModifyCalls);
                            return(value);
                        });
                    }

                    await Task.Delay(10);
                },
                    numThreads,
                    iterations);

                // assert
                var result = cache.Get(key);
                result.Should().NotBeNull();
                Trace.WriteLine("Counter increased to " + result.Counter + " cas calls needed " + countCasModifyCalls);
                result.Counter.Should().Be(numThreads * numInnerIterations * iterations, "counter should be exactly the expected value");
                countCasModifyCalls.Should().BeGreaterThan((int)result.Counter, "we expect many version collisions, so cas calls should be way higher then the count result");
            }
        }
        public async Task Redis_RaceCondition_WithoutUpdate()
        {
            using (var cache = CacheFactory.Build <RaceConditionTestElement>(settings =>
            {
                settings.WithUpdateMode(CacheUpdateMode.Up)
                .WithJsonSerializer()
                .WithRedisCacheHandle("default")
                .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMinutes(20));
                settings.WithRedisConfiguration("default", config =>
                {
                    config.WithAllowAdmin()
                    .WithDatabase(8)
                    .WithEndpoint("127.0.0.1", 6379);
                });
            }))
            {
                var key = Guid.NewGuid().ToString();
                cache.Add(key, new RaceConditionTestElement()
                {
                    Counter = 0
                });
                int numThreads         = 5;
                int iterations         = 10;
                int numInnerIterations = 10;

                // act
                await ThreadTestHelper.RunAsync(
                    async() =>
                {
                    for (int i = 0; i < numInnerIterations; i++)
                    {
                        var val = cache.Get(key);
                        val.Should().NotBeNull();
                        val.Counter++;

                        cache.Put(key, val);
                        await Task.Delay(1);
                    }
                },
                    numThreads,
                    iterations);

                // assert
                await Task.Delay(10);

                var result = cache.Get(key);
                result.Should().NotBeNull();
                result.Counter.Should().NotBe(numThreads * numInnerIterations * iterations);
            }
        }
Beispiel #6
0
        public async Task Memcached_RaceCondition_WithoutCasHandling()
        {
            // arrange
            using (var cache = CacheFactory.FromConfiguration <RaceConditionTestElement>(
                       TestManagers.BaseConfiguration.Builder
                       .WithUpdateMode(CacheUpdateMode.Up)
                       .WithMemcachedCacheHandle(Configuration)
                       .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMinutes(20))
                       .Build()))
            {
                var key = Guid.NewGuid().ToString();
                cache.Remove(key);
                cache.Add(key, new RaceConditionTestElement()
                {
                    Counter = 0
                });
                int numThreads         = 5;
                int iterations         = 10;
                int numInnerIterations = 10;

                // act
                await ThreadTestHelper.RunAsync(
                    async() =>
                {
                    for (int i = 0; i < numInnerIterations; i++)
                    {
                        var val = cache.Get(key);
                        val.Should().NotBeNull();
                        val.Counter++;

                        cache.Put(key, val);
                    }

                    await Task.Delay(10);
                },
                    numThreads,
                    iterations);

                // assert
                var result = cache.Get(key);
                result.Should().NotBeNull();
                Trace.TraceInformation("Counter increased to " + result.Counter);
                result.Counter.Should().NotBe(numThreads * numInnerIterations * iterations);
            }
        }
        public async Task Thread_Update(ICacheManager <object> cache)
        {
            using (cache)
            {
                var key        = Guid.NewGuid().ToString();
                var handleInfo = string.Join("\nh: ", cache.CacheHandles.Select(p => p.Configuration.Name + ":" + p.GetType().Name));

                cache.Remove(key);
                cache.Add(key, new RaceConditionTestElement()
                {
                    Counter = 0
                });
                int numThreads          = 5;
                int iterations          = 10;
                int numInnerIterations  = 10;
                int countCasModifyCalls = 0;

                // act
                await ThreadTestHelper.RunAsync(
                    async() =>
                {
                    for (int i = 0; i < numInnerIterations; i++)
                    {
                        cache.Update(
                            key,
                            (value) =>
                        {
                            var val = value as RaceConditionTestElement;
                            if (val == null)
                            {
                                throw new InvalidOperationException("WTF invalid object result");
                            }

                            val.Counter++;
                            Interlocked.Increment(ref countCasModifyCalls);
                            return(value);
                        },
                            int.MaxValue);
                    }

                    await Task.Delay(0);
                },
                    numThreads,
                    iterations);

                // assert
                await Task.Delay(10);

                for (var i = 0; i < cache.CacheHandles.Count(); i++)
                {
                    var handle = cache.CacheHandles.ElementAt(i);
                    var result = (RaceConditionTestElement)handle.Get(key);
                    if (i < cache.CacheHandles.Count() - 1)
                    {
                        // only the last one should have the item
                        result.Should().BeNull();
                    }
                    else
                    {
                        result.Should().NotBeNull(handleInfo + "\ncurrent: " + handle.Configuration.Name + ":" + handle.GetType().Name);
                        result.Counter.Should().Be(numThreads * numInnerIterations * iterations, handleInfo + "\ncounter should be exactly the expected value.");
                        countCasModifyCalls.Should().BeGreaterOrEqualTo((int)result.Counter, handleInfo + "\nexpecting no (if synced) or some version collisions.");
                    }
                }
            }
        }