public async Task MemoryCacheLayer_CacheStack() { await using (var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, null)) { //Get 100 misses for (var i = 0; i < 100; i++) { await cacheStack.GetAsync <int>("GetMiss_" + i); } var startDate = DateTime.UtcNow.AddDays(-50); //Set first 100 (simple type) for (var i = 0; i < 100; i++) { await cacheStack.SetAsync("Comparison_" + i, new CacheEntry <int>(1, startDate.AddDays(i) + TimeSpan.FromDays(1))); } //Set last 100 (complex type) for (var i = 100; i < 200; i++) { await cacheStack.SetAsync("Comparison_" + i, new CacheEntry <RealCostComplexType>(new RealCostComplexType { ExampleString = "Hello World", ExampleNumber = 42, ExampleDate = new DateTime(2000, 1, 1), DictionaryOfNumbers = new Dictionary <string, int>() { { "A", 1 }, { "B", 2 }, { "C", 3 } } }, startDate.AddDays(i - 100) + TimeSpan.FromDays(1))); } //Get first 50 (simple type) for (var i = 0; i < 50; i++) { await cacheStack.GetAsync <int>("Comparison_" + i); } //Get last 50 (complex type) for (var i = 150; i < 200; i++) { await cacheStack.GetAsync <RealCostComplexType>("Comparison_" + i); } //Evict middle 100 for (var i = 50; i < 150; i++) { await cacheStack.EvictAsync("Comparison_" + i); } //Cleanup outer 100 await cacheStack.CleanupAsync(); } }
public async Task GetOrSet_ConcurrentStaleCacheHits_OnlyOneRefresh() { using var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, Array.Empty <ICacheExtension>()); var cacheEntry = new CacheEntry <int>(23, DateTime.UtcNow.AddDays(2)); await cacheStack.SetAsync("GetOrSet_ConcurrentStaleCacheHits_OnlyOneRefresh", cacheEntry); Internal.DateTimeProvider.UpdateTime(); var refreshWaitSource = new TaskCompletionSource <bool>(); var getterCallCount = 0; Parallel.For(0, 100, async v => { await cacheStack.GetOrSetAsync <int>( "GetOrSet_ConcurrentStaleCacheHits_OnlyOneRefresh", async _ => { await Task.Delay(250); Interlocked.Increment(ref getterCallCount); refreshWaitSource.TrySetResult(true); return(27); }, new CacheSettings(TimeSpan.FromDays(2), TimeSpan.Zero) ); }); await Task.WhenAny(refreshWaitSource.Task, Task.Delay(TimeSpan.FromSeconds(5))); Assert.AreEqual(1, getterCallCount); }
public async Task GetOrSet_StaleCacheHit() { using var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, Array.Empty <ICacheExtension>()); var cacheEntry = new CacheEntry <int>(17, DateTime.UtcNow.AddDays(2)); await cacheStack.SetAsync("GetOrSet_StaleCacheHit", cacheEntry); Internal.DateTimeProvider.UpdateTime(); var refreshWaitSource = new TaskCompletionSource <bool>(); var result = await cacheStack.GetOrSetAsync <int>("GetOrSet_StaleCacheHit", (oldValue) => { Assert.AreEqual(17, oldValue); refreshWaitSource.TrySetResult(true); return(Task.FromResult(27)); }, new CacheSettings(TimeSpan.FromDays(2), TimeSpan.Zero)); Assert.AreEqual(17, result); await Task.WhenAny(refreshWaitSource.Task, Task.Delay(TimeSpan.FromSeconds(5))); var refetchedResult = await cacheStack.GetAsync <int>("GetOrSet_StaleCacheHit"); Assert.AreEqual(27, refetchedResult.Value); }
public async Task GetOrSet_CacheHitBackgroundRefresh() { var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, Array.Empty <ICacheExtension>()); var cacheEntry = new CacheEntry <int>(17, DateTime.UtcNow.AddDays(1)); await cacheStack.SetAsync("GetOrSet_CacheHitBackgroundRefresh", cacheEntry); var waitingOnBackgroundTask = new TaskCompletionSource <int>(); var result = await cacheStack.GetOrSetAsync <int>("GetOrSet_CacheHitBackgroundRefresh", (oldValue) => { waitingOnBackgroundTask.TrySetResult(27); return(Task.FromResult(27)); }, new CacheSettings(TimeSpan.FromDays(2), TimeSpan.Zero)); Assert.AreEqual(17, result); await waitingOnBackgroundTask.Task; //Give 400ms to return the value and set it to the MemoryCacheLayer await Task.Delay(400); var refetchedResult = await cacheStack.GetAsync <int>("GetOrSet_CacheHitBackgroundRefresh"); Assert.AreEqual(27, refetchedResult.Value); await DisposeOf(cacheStack); }
public async Task GetOrSet_ConcurrentStaleCacheHits() { await using var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, Array.Empty <ICacheExtension>()); var cacheEntry = new CacheEntry <int>(23, DateTime.UtcNow.AddDays(-2)); await cacheStack.SetAsync("GetOrSet_ConcurrentStaleCacheHits", cacheEntry); var request1LockSource = new TaskCompletionSource <bool>(); var request2StartLockSource = new TaskCompletionSource <bool>(); //Request 1 gets the lock on the refresh and ends up being tied up due to the TaskCompletionSource var request1Task = cacheStack.GetOrSetAsync <int>("GetOrSet_ConcurrentStaleCacheHits", async(oldValue) => { request2StartLockSource.SetResult(true); await request1LockSource.Task; return(99); }, new CacheSettings(TimeSpan.FromDays(2), TimeSpan.Zero)); await request2StartLockSource.Task; //Request 2 sees there is a lock already and because we still at least have old data, rather than wait //it is given the old cache data even though we are past the point where even stale data should be removed var request2Result = await cacheStack.GetOrSetAsync <int>("GetOrSet_ConcurrentStaleCacheHits", (oldValue) => { return(Task.FromResult(99)); }, new CacheSettings(TimeSpan.FromDays(2), TimeSpan.Zero)); //Unlock Request 1 to to continue request1LockSource.SetResult(true); //Wait for Request 1 to complete so we get the new data var request1Result = await request1Task; Assert.AreEqual(99, request1Result); Assert.AreEqual(23, request2Result); }
public async Task Set_ThrowsOnUseAfterDisposal_CacheEntry() { var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, null); await DisposeOf(cacheStack); await cacheStack.SetAsync("KeyDoesntMatter", new CacheEntry <int>(1, TimeSpan.FromDays(1))); }
public async Task Set_ThrowsOnUseAfterDisposal() { var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, null); using (cacheStack) { } await cacheStack.SetAsync("KeyDoesntMatter", 1, TimeSpan.FromDays(1)); }
public async Task Set_TriggersCacheChangeExtension() { var mockExtension = new Mock <ICacheChangeExtension>(); using var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, new[] { mockExtension.Object }); var cacheEntry = await cacheStack.SetAsync("Set_TriggersCacheChangeExtension", 42, TimeSpan.FromDays(1)); mockExtension.Verify(e => e.OnCacheUpdateAsync("Set_TriggersCacheChangeExtension", cacheEntry.Expiry), Times.Once); }
public async Task Set_TwoLayers() { await using (var cacheStack = new CacheStack(new[] { new MemoryCacheLayer(), new MemoryCacheLayer() }, Array.Empty <ICacheExtension>())) { for (var i = 0; i < WorkIterations; i++) { await cacheStack.SetAsync("Set", 15, TimeSpan.FromDays(1)); } } }
public async Task Set_SetsAllTheLayers() { var layer1 = new MemoryCacheLayer(); var layer2 = new MemoryCacheLayer(); using var cacheStack = new CacheStack(new[] { layer1, layer2 }, Array.Empty <ICacheExtension>()); var cacheEntry = await cacheStack.SetAsync("Set_SetsAllTheLayers", 42, TimeSpan.FromDays(1)); Assert.AreEqual(cacheEntry, await layer1.GetAsync <int>("Set_SetsAllTheLayers")); Assert.AreEqual(cacheEntry, await layer2.GetAsync <int>("Set_SetsAllTheLayers")); }
public async Task Evict_TriggersCacheChangeExtension() { var mockExtension = new Mock <ICacheChangeExtension>(); await using var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, new [] { mockExtension.Object }); var cacheEntry = await cacheStack.SetAsync("Evict_TriggerCacheChangeExtension", 42, TimeSpan.FromDays(1)); await cacheStack.EvictAsync("Evict_TriggerCacheChangeExtension"); mockExtension.Verify(e => e.OnCacheEvictionAsync("Evict_TriggerCacheChangeExtension"), Times.Once); }
public async Task GetHit() { await using (var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, Array.Empty <ICacheExtension>())) { await cacheStack.SetAsync("GetHit", 15, TimeSpan.FromDays(1)); for (var i = 0; i < WorkIterations; i++) { await cacheStack.GetAsync <int>("GetHit"); } } }
public async Task Cleanup() { await using (var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, Array.Empty <ICacheExtension>())) { for (var i = 0; i < WorkIterations; i++) { await cacheStack.SetAsync($"Cleanup_{i}", 15, TimeSpan.FromDays(1)); } await cacheStack.CleanupAsync(); } }
public async Task GetOrSet_CacheHit() { await using var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, Array.Empty <ICacheExtension>()); await cacheStack.SetAsync("GetOrSet_CacheHit", 17, TimeSpan.FromDays(2)); var result = await cacheStack.GetOrSetAsync <int>("GetOrSet_CacheHit", (oldValue) => { return(Task.FromResult(27)); }, new CacheSettings(TimeSpan.FromDays(1))); Assert.AreEqual(17, result); }
public async Task GetOrSet_CacheHitButAllowedStalePoint() { await using var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, Array.Empty <ICacheExtension>()); var cacheEntry = new CacheEntry <int>(17, DateTime.UtcNow.AddDays(-1)); await cacheStack.SetAsync("GetOrSet_CacheHitButAllowedStalePoint", cacheEntry); var result = await cacheStack.GetOrSetAsync <int>("GetOrSet_CacheHitButAllowedStalePoint", (oldValue) => { return(Task.FromResult(27)); }, new CacheSettings(TimeSpan.FromDays(1), TimeSpan.Zero)); Assert.AreEqual(27, result); }
public async Task CacheTower_RedisCacheLayer() { await using (var cacheStack = new CacheStack(new[] { new RedisCacheLayer(RedisHelper.GetConnection()) }, Array.Empty <ICacheExtension>())) { await LoopActionAsync(Iterations, async() => { await cacheStack.SetAsync("TestKey", 123, TimeSpan.FromDays(1)); await cacheStack.GetAsync <int>("TestKey"); await cacheStack.GetOrSetAsync <string>("GetOrSet_TestKey", (old) => { return(Task.FromResult("Hello World")); }, new CacheSettings(TimeSpan.FromDays(1), TimeSpan.FromDays(1))); }); } }
public async Task GetOrSet_UnderLoad() { await using (var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, Array.Empty <ICacheExtension>())) { await cacheStack.SetAsync("GetOrSet", new CacheEntry <int>(15, DateTime.UtcNow.AddDays(-1))); Parallel.For(0, WorkIterations, async value => { await cacheStack.GetOrSetAsync <int>("GetOrSet", async(old) => { await Task.Delay(30); return(12); }, new CacheSettings(TimeSpan.FromDays(1))); }); } }
public async Task Cleanup_CleansAllTheLayers() { var layer1 = new MemoryCacheLayer(); var layer2 = new MemoryCacheLayer(); using var cacheStack = new CacheStack(new[] { layer1, layer2 }, Array.Empty <ICacheExtension>()); var cacheEntry = new CacheEntry <int>(42, DateTime.UtcNow.AddDays(-1)); await cacheStack.SetAsync("Cleanup_CleansAllTheLayers", cacheEntry); Assert.AreEqual(cacheEntry, await layer1.GetAsync <int>("Cleanup_CleansAllTheLayers")); Assert.AreEqual(cacheEntry, await layer2.GetAsync <int>("Cleanup_CleansAllTheLayers")); await cacheStack.CleanupAsync(); Assert.IsNull(await layer1.GetAsync <int>("Cleanup_CleansAllTheLayers")); Assert.IsNull(await layer2.GetAsync <int>("Cleanup_CleansAllTheLayers")); }
public async Task Evict_EvictsAllTheLayers() { var layer1 = new MemoryCacheLayer(); var layer2 = new MemoryCacheLayer(); var cacheStack = new CacheStack(new[] { layer1, layer2 }, Array.Empty <ICacheExtension>()); var cacheEntry = await cacheStack.SetAsync("Evict_EvictsAllTheLayers", 42, TimeSpan.FromDays(1)); Assert.AreEqual(cacheEntry, layer1.Get <int>("Evict_EvictsAllTheLayers")); Assert.AreEqual(cacheEntry, layer2.Get <int>("Evict_EvictsAllTheLayers")); await cacheStack.EvictAsync("Evict_EvictsAllTheLayers"); Assert.IsNull(layer1.Get <int>("Evict_EvictsAllTheLayers")); Assert.IsNull(layer2.Get <int>("Evict_EvictsAllTheLayers")); await DisposeOf(cacheStack); }
public async Task GetOrSet_FourSimultaneous() { await using (var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, Array.Empty <ICacheExtension>())) { await cacheStack.SetAsync("GetOrSet", new CacheEntry <int>(15, DateTime.UtcNow.AddDays(-1))); for (var i = 0; i < WorkIterations; i++) { var task1 = cacheStack.GetOrSetAsync <int>("GetOrSet", async(old) => { await Task.Delay(30); return(12); }, new CacheSettings(TimeSpan.FromDays(1))); var task2 = cacheStack.GetOrSetAsync <int>("GetOrSet", async(old) => { await Task.Delay(30); return(12); }, new CacheSettings(TimeSpan.FromDays(1))); var task3 = cacheStack.GetOrSetAsync <int>("GetOrSet", async(old) => { await Task.Delay(30); return(12); }, new CacheSettings(TimeSpan.FromDays(1))); var task4 = cacheStack.GetOrSetAsync <int>("GetOrSet", async(old) => { await Task.Delay(30); return(12); }, new CacheSettings(TimeSpan.FromDays(1))); await task1; await task2; await task3; await task4; } } }
public async Task Set_ThrowsOnNullCacheEntry() { var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, Array.Empty <ICacheExtension>()); await cacheStack.SetAsync("MyCacheKey", (CacheEntry <int>) null); }
public async Task Set_ThrowsOnNullKey() { var cacheStack = new CacheStack(new[] { new MemoryCacheLayer() }, Array.Empty <ICacheExtension>()); await cacheStack.SetAsync(null, new CacheEntry <int>(1, TimeSpan.FromDays(1))); }