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 void 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 = 5; var iterations = 10; using (cache) { var key = Guid.NewGuid().ToString(); ThreadTestHelper.Run( () => { cache.Add(key, "hi"); cache.Put(key, "changed"); }, threads, iterations); } // item should have been added only once (not true in back plate scenarios) if (!cache.Configuration.HasBackPlate) { adds.ShouldAllBeEquivalentTo( Enumerable.Repeat(1, cache.CacheHandles.Count())); } 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"); } }
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"); } }
public void Thread_Update(ICacheManager <object> cache) { using (cache) { var key = Guid.NewGuid().ToString(); var handleInfo = string.Join("\nh: ", cache.CacheHandles.Select(p => p.Configuration.HandleName + ":" + 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 ThreadTestHelper.Run( () => { for (int i = 0; i < numInnerIterations; i++) { cache.Update(key, (value) => { var val = (RaceConditionTestElement)value; val.Counter++; Interlocked.Increment(ref countCasModifyCalls); return(value); }); } }, numThreads, iterations); // assert Thread.Sleep(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.HandleName + ":" + 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."); } } } }
public void Memcached_NoRaceCondition_WithCasButTooFiewRetries() { // arrange using (var cache = CacheFactory.Build <RaceConditionTestElement>(settings => { settings.WithUpdateMode(CacheUpdateMode.Full) .WithMemcachedCacheHandle("default") .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromHours(10)); })) { 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 ThreadTestHelper.Run( () => { for (int i = 0; i < numInnerIterations; i++) { cache.Update( "myCounter", (value) => { value.Counter++; Interlocked.Increment(ref countCasModifyCalls); return(value); }, new UpdateItemConfig(retries, VersionConflictHandling.EvictItemFromOtherCaches)); } }, numThreads, iterations); // assert Thread.Sleep(10); 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"); } }
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 void Memcached_NoRaceCondition_WithCasHandling_WithRegion() { // arrange using (var cache = CacheFactory.Build <RaceConditionTestElement>(settings => { settings.WithUpdateMode(CacheUpdateMode.Up) .WithMemcachedCacheHandle(Configuration) .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMinutes(10)); })) { var region = "region"; var key = "myKey"; cache.Remove(key, region); cache.Add(key, new RaceConditionTestElement() { Counter = 0 }, region); int numThreads = 5; int iterations = 10; int numInnerIterations = 10; int countCasModifyCalls = 0; // act ThreadTestHelper.Run( () => { for (int i = 0; i < numInnerIterations; i++) { cache.Update( key, region, (value) => { value.Counter++; Interlocked.Increment(ref countCasModifyCalls); return(value); }, 500); } }, numThreads, iterations); // assert Thread.Sleep(10); var result = cache.Get(key, region); result.Should().NotBeNull(); Trace.TraceInformation("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 void Memcached_NoRaceCondition_WithCasHandling() { // arrange using (var cache = CacheFactory.Build <RaceConditionTestElement>(settings => { settings.WithUpdateMode(CacheUpdateMode.Full) .WithSystemRuntimeDefaultCacheHandle() .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMilliseconds(1)) .And .WithMemcachedCacheHandle("default") .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromSeconds(10)); })) { cache.Remove("myCounter"); cache.Add("myCounter", new RaceConditionTestElement() { Counter = 0 }); int numThreads = 5; int iterations = 10; int numInnerIterations = 10; int countCasModifyCalls = 0; // act ThreadTestHelper.Run( () => { for (int i = 0; i < numInnerIterations; i++) { cache.Update( "myCounter", (value) => { value.Counter++; Interlocked.Increment(ref countCasModifyCalls); return(value); }, new UpdateItemConfig(50, VersionConflictHandling.EvictItemFromOtherCaches)); } }, numThreads, iterations); // assert Thread.Sleep(10); var result = cache.Get("myCounter"); 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); } }
public void Redis_RaceCondition_WithoutUpdate() { using (var cache = CacheFactory.Build <RaceConditionTestElement>("myCache", settings => { settings.WithUpdateMode(CacheUpdateMode.Full) .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 ThreadTestHelper.Run(() => { for (int i = 0; i < numInnerIterations; i++) { var val = cache.Get(key); val.Should().NotBeNull(); val.Counter++; cache.Put(key, val); } }, numThreads, iterations); // assert Thread.Sleep(10); 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 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 void Memcached_RaceCondition_WithoutCasHandling() { // arrange using (var cache = CacheFactory.Build <RaceConditionTestElement>(settings => { settings.WithUpdateMode(CacheUpdateMode.Up) .WithMemcachedCacheHandle(Configuration) .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMinutes(20)); })) { cache.Remove("myCounter"); cache.Add("myCounter", new RaceConditionTestElement() { Counter = 0 }); int numThreads = 5; int iterations = 10; int numInnerIterations = 10; // act ThreadTestHelper.Run( () => { for (int i = 0; i < numInnerIterations; i++) { var val = cache.Get("myCounter"); val.Should().NotBeNull(); val.Counter++; cache.Put("myCounter", val); } }, numThreads, iterations); // assert Thread.Sleep(10); var result = cache.Get("myCounter"); result.Should().NotBeNull(); Trace.TraceInformation("Counter increased to " + result.Counter); result.Counter.Should().NotBe(numThreads * numInnerIterations * iterations); } }
public void 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 = 5; var iterations = 10; using (cache) { var key = Guid.NewGuid().ToString(); ThreadTestHelper.Run( () => { cache.Add(key, "hi"); cache.Put(key, "changed"); }, threads, iterations); } puts.ShouldAllBeEquivalentTo( Enumerable.Repeat(threads * iterations, cache.CacheHandles.Count())); }
public void Thread_RandomAccess(ICacheManager <object> cache) { NotNull(cache, nameof(cache)); foreach (var handle in cache.CacheHandles) { Trace.TraceInformation("Using handle {0}", handle.GetType()); } var blob = new byte[1024]; using (cache) { Action test = () => { var hits = 0; var misses = 0; var tId = Thread.CurrentThread.ManagedThreadId; try { for (var r = 0; r < 5; r++) { for (int i = 0; i < 5; i++) { string key = "key" + i; object value = blob.Clone(); string region = "region" + r; CacheItem <object> item = null; if (r % 2 == 0) { item = new CacheItem <object>(key, value, ExpirationMode.Sliding, TimeSpan.FromMilliseconds(10)); } else { item = new CacheItem <object>(key, region, value, ExpirationMode.Absolute, TimeSpan.FromMilliseconds(10)); } cache.Put(item); if (!cache.Add(item)) { cache.Put(item); } var result = cache.Get(key); if (result == null) { misses++; } else { hits++; } if (!cache.Remove(key)) { misses++; } else { hits++; } Thread.Sleep(0); } } } catch (Exception ex) { Debug.WriteLine("{1} Error: {0}", ex.Message, tId); throw; } Debug.WriteLine("Hits: {0}, Misses: {1}", hits, misses); }; ThreadTestHelper.Run(test, 2, 1); } }