diff --git a/CodeCoverage.runsettings b/CodeCoverage.runsettings index 7e9d628c..754249ec 100644 --- a/CodeCoverage.runsettings +++ b/CodeCoverage.runsettings @@ -10,8 +10,10 @@ .*\.dll$ - - CacheTower.Tests.dll + + CacheTower.Tests.dll + CacheTower.Benchmarks.dll + CacheTower.AlternativesBenchmark.dll diff --git a/docs/Comparison.md b/docs/Comparison.md index 1aaa40e9..495fb9d2 100644 --- a/docs/Comparison.md +++ b/docs/Comparison.md @@ -12,77 +12,78 @@ If you are one of the maintainers of the libraries referenced below and you feel **Test Machine** ``` -BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362 +BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18362 Intel Core i7-6700HQ CPU 2.60GHz (Skylake), 1 CPU, 8 logical and 4 physical cores .NET Core SDK=3.0.100 - [Host] : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT - Core : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT + [Host] : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), X64 RyuJIT + Job-CQNZSR : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), X64 RyuJIT -Job=Core Runtime=Core +Runtime=.NET Core 3.0 MaxIterationCount=200 +UnrollFactor=1 ``` ## Memory Caching | Method | Iterations | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | |------------------------------------------ |----------- |-------------------:|-----------------:|-----------------:|---------:|--------:|-----------:|-----------:|------:|-----------:| -| CacheTower_MemoryCacheLayer_Direct | 1 | 758.2 ns | 12.00 ns | 11.22 ns | 0.32 | 0.00 | 0.1631 | - | - | 512 B | -| LazyCache_MemoryProvider | 1 | 1,698.7 ns | 17.63 ns | 16.49 ns | 0.72 | 0.01 | 0.4139 | - | - | 1304 B | -| LazyCache_MemoryProviderAsync | 1 | 1,984.2 ns | 38.70 ns | 30.21 ns | 0.84 | 0.02 | 0.4845 | - | - | 1520 B | -| CacheTower_MemoryCacheLayer_ViaCacheStack | 1 | 2,355.6 ns | 23.82 ns | 21.12 ns | 1.00 | 0.00 | 0.3548 | - | - | 1120 B | -| EasyCaching_InMemory | 1 | 9,869.4 ns | 133.65 ns | 125.02 ns | 4.19 | 0.06 | 1.3580 | - | - | 4281 B | -| CacheManager_MicrosoftMemoryCache | 1 | 18,324.3 ns | 201.38 ns | 188.37 ns | 7.78 | 0.12 | 2.4719 | 1.2207 | - | 7848 B | -| EasyCaching_InMemoryAsync | 1 | 23,729.5 ns | 466.39 ns | 555.21 ns | 10.08 | 0.26 | 2.0142 | - | - | 6257 B | -| Akavache_InMemory | 1 | 1,297,026.2 ns | 10,505.78 ns | 9,827.12 ns | 550.27 | 4.88 | 19.5313 | 9.7656 | - | 66232 B | +| CacheTower_MemoryCacheLayer_Direct | 1 | 778.2 ns | 16.37 ns | 14.51 ns | 0.33 | 0.01 | 0.1574 | - | - | 496 B | +| LazyCache_MemoryProvider | 1 | 1,747.6 ns | 31.36 ns | 29.34 ns | 0.73 | 0.01 | 0.4139 | - | - | 1304 B | +| LazyCache_MemoryProviderAsync | 1 | 2,048.3 ns | 11.69 ns | 10.36 ns | 0.86 | 0.01 | 0.4845 | - | - | 1520 B | +| CacheTower_MemoryCacheLayer_ViaCacheStack | 1 | 2,392.3 ns | 22.62 ns | 18.89 ns | 1.00 | 0.00 | 0.3510 | - | - | 1104 B | +| EasyCaching_InMemory | 1 | 9,788.1 ns | 139.27 ns | 130.28 ns | 4.09 | 0.07 | 1.3580 | - | - | 4281 B | +| CacheManager_MicrosoftMemoryCache | 1 | 18,617.1 ns | 172.65 ns | 161.50 ns | 7.77 | 0.08 | 2.4719 | 1.2207 | - | 7848 B | +| EasyCaching_InMemoryAsync | 1 | 25,383.4 ns | 503.14 ns | 654.23 ns | 10.70 | 0.28 | 2.0142 | - | - | 6260 B | +| Akavache_InMemory | 1 | 1,316,664.7 ns | 11,369.24 ns | 10,634.80 ns | 550.04 | 7.27 | 19.5313 | 9.7656 | - | 66232 B | | | | | | | | | | | | | -| CacheTower_MemoryCacheLayer_Direct | 100 | 38,767.1 ns | 446.65 ns | 417.80 ns | 0.44 | 0.01 | 1.4038 | - | - | 4472 B | -| CacheTower_MemoryCacheLayer_ViaCacheStack | 100 | 87,286.9 ns | 1,434.07 ns | 1,341.43 ns | 1.00 | 0.00 | 4.8828 | - | - | 15376 B | -| LazyCache_MemoryProvider | 100 | 168,978.2 ns | 2,303.73 ns | 2,154.91 ns | 1.94 | 0.03 | 33.9355 | - | - | 106642 B | -| LazyCache_MemoryProviderAsync | 100 | 189,229.9 ns | 2,746.71 ns | 2,293.63 ns | 2.17 | 0.04 | 40.7715 | - | - | 128240 B | -| CacheManager_MicrosoftMemoryCache | 100 | 196,564.2 ns | 3,686.03 ns | 3,447.91 ns | 2.25 | 0.06 | 10.9863 | 3.6621 | - | 34790 B | -| EasyCaching_InMemory | 100 | 451,180.2 ns | 6,187.16 ns | 5,166.56 ns | 5.18 | 0.09 | 35.6445 | - | - | 112806 B | -| EasyCaching_InMemoryAsync | 100 | 913,772.6 ns | 17,705.40 ns | 17,389.07 ns | 10.46 | 0.25 | 66.4063 | - | - | 210705 B | -| Akavache_InMemory | 100 | 128,480,626.8 ns | 1,157,242.01 ns | 1,025,864.90 ns | 1,474.27 | 22.51 | 2000.0000 | 1000.0000 | - | 6576334 B | +| CacheTower_MemoryCacheLayer_Direct | 100 | 39,798.7 ns | 425.38 ns | 377.09 ns | 0.44 | 0.01 | 1.1597 | - | - | 3664 B | +| CacheTower_MemoryCacheLayer_ViaCacheStack | 100 | 90,246.3 ns | 1,062.95 ns | 994.28 ns | 1.00 | 0.00 | 4.6387 | - | - | 14570 B | +| LazyCache_MemoryProvider | 100 | 172,256.9 ns | 2,014.73 ns | 1,884.58 ns | 1.91 | 0.02 | 33.9355 | - | - | 106641 B | +| LazyCache_MemoryProviderAsync | 100 | 191,666.9 ns | 1,486.80 ns | 1,390.75 ns | 2.12 | 0.02 | 40.7715 | - | - | 128240 B | +| CacheManager_MicrosoftMemoryCache | 100 | 204,438.9 ns | 3,591.56 ns | 3,359.54 ns | 2.27 | 0.05 | 10.9863 | 3.6621 | - | 34790 B | +| EasyCaching_InMemory | 100 | 452,204.4 ns | 4,000.21 ns | 3,741.80 ns | 5.01 | 0.07 | 35.6445 | - | - | 112806 B | +| EasyCaching_InMemoryAsync | 100 | 903,208.0 ns | 17,237.22 ns | 18,443.63 ns | 10.01 | 0.25 | 66.4063 | - | - | 210689 B | +| Akavache_InMemory | 100 | 131,507,873.3 ns | 1,732,164.29 ns | 1,620,267.55 ns | 1,457.31 | 19.56 | 2000.0000 | 1000.0000 | - | 6577278 B | | | | | | | | | | | | | -| CacheTower_MemoryCacheLayer_Direct | 1000 | 398,735.8 ns | 1,764.86 ns | 1,564.50 ns | 0.46 | 0.00 | 12.6953 | - | - | 40473 B | -| CacheTower_MemoryCacheLayer_ViaCacheStack | 1000 | 873,629.7 ns | 3,261.48 ns | 2,891.22 ns | 1.00 | 0.00 | 45.8984 | - | - | 144976 B | -| LazyCache_MemoryProvider | 1000 | 1,684,822.1 ns | 25,771.86 ns | 24,107.01 ns | 1.93 | 0.03 | 337.8906 | - | - | 1064243 B | -| CacheManager_MicrosoftMemoryCache | 1000 | 1,809,405.6 ns | 25,329.40 ns | 23,693.13 ns | 2.07 | 0.03 | 87.8906 | - | - | 279715 B | -| LazyCache_MemoryProviderAsync | 1000 | 1,856,364.0 ns | 27,768.92 ns | 25,975.07 ns | 2.12 | 0.03 | 406.2500 | - | - | 1280245 B | -| EasyCaching_InMemory | 1000 | 4,388,849.5 ns | 54,388.28 ns | 50,874.83 ns | 5.03 | 0.05 | 343.7500 | - | - | 1099399 B | -| EasyCaching_InMemoryAsync | 1000 | 8,220,673.5 ns | 102,349.65 ns | 95,737.93 ns | 9.41 | 0.12 | 656.2500 | - | - | 2068651 B | -| Akavache_InMemory | 1000 | 1,327,851,400.0 ns | 13,538,489.80 ns | 12,663,911.76 ns | 1,520.00 | 14.80 | 20000.0000 | 10000.0000 | - | 65753656 B | +| CacheTower_MemoryCacheLayer_Direct | 1000 | 405,720.8 ns | 7,902.60 ns | 8,115.39 ns | 0.45 | 0.01 | 10.2539 | - | - | 32464 B | +| CacheTower_MemoryCacheLayer_ViaCacheStack | 1000 | 893,106.3 ns | 16,676.90 ns | 16,378.95 ns | 1.00 | 0.00 | 42.9688 | - | - | 136968 B | +| LazyCache_MemoryProvider | 1000 | 1,830,634.8 ns | 35,334.35 ns | 37,807.36 ns | 2.05 | 0.04 | 337.8906 | - | - | 1064240 B | +| CacheManager_MicrosoftMemoryCache | 1000 | 1,838,591.6 ns | 24,330.29 ns | 22,758.57 ns | 2.06 | 0.06 | 87.8906 | - | - | 279714 B | +| LazyCache_MemoryProviderAsync | 1000 | 2,056,004.3 ns | 39,896.97 ns | 57,219.05 ns | 2.30 | 0.06 | 406.2500 | - | - | 1280241 B | +| EasyCaching_InMemory | 1000 | 4,985,703.7 ns | 99,385.27 ns | 218,153.07 ns | 5.82 | 0.33 | 343.7500 | - | - | 1099395 B | +| EasyCaching_InMemoryAsync | 1000 | 8,306,778.8 ns | 159,580.60 ns | 149,271.80 ns | 9.30 | 0.25 | 656.2500 | - | - | 2068651 B | +| Akavache_InMemory | 1000 | 1,326,507,671.4 ns | 18,398,324.62 ns | 16,309,635.56 ns | 1,484.44 | 34.87 | 20000.0000 | 10000.0000 | - | 65745312 B | ## File Caching | Method | Iterations | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | |---------------------------------- |----------- |-------------:|-----------:|-----------:|------:|--------:|-----------:|------:|------:|------------:| -| EasyCaching_Disk | 1 | 4.367 ms | 0.1388 ms | 0.5799 ms | 0.73 | 0.13 | - | - | - | 37.96 KB | -| CacheTower_ProtobufFileCacheLayer | 1 | 4.991 ms | 0.1752 ms | 0.7245 ms | 0.83 | 0.16 | - | - | - | 24.45 KB | -| MonkeyCache_FileStore | 1 | 5.743 ms | 0.1617 ms | 0.6669 ms | 0.96 | 0.16 | - | - | - | 65.81 KB | -| CacheTower_JsonFileCacheLayer | 1 | 6.071 ms | 0.1727 ms | 0.7181 ms | 1.00 | 0.00 | - | - | - | 55.5 KB | +| EasyCaching_Disk | 1 | 4.466 ms | 0.1541 ms | 0.6508 ms | 0.73 | 0.14 | - | - | - | 38.03 KB | +| CacheTower_ProtobufFileCacheLayer | 1 | 4.824 ms | 0.1557 ms | 0.6402 ms | 0.79 | 0.16 | - | - | - | 22.66 KB | +| MonkeyCache_FileStore | 1 | 5.790 ms | 0.1885 ms | 0.7773 ms | 0.95 | 0.18 | - | - | - | 65.81 KB | +| CacheTower_JsonFileCacheLayer | 1 | 6.180 ms | 0.2037 ms | 0.8353 ms | 1.00 | 0.00 | - | - | - | 54.63 KB | | | | | | | | | | | | | -| CacheTower_ProtobufFileCacheLayer | 100 | 93.950 ms | 1.8486 ms | 3.2859 ms | 0.71 | 0.03 | - | - | - | 1109.38 KB | -| EasyCaching_Disk | 100 | 108.159 ms | 2.1508 ms | 5.4744 ms | 0.83 | 0.04 | - | - | - | 1766.05 KB | -| CacheTower_JsonFileCacheLayer | 100 | 131.364 ms | 2.5835 ms | 5.0390 ms | 1.00 | 0.00 | - | - | - | 2779.68 KB | -| MonkeyCache_FileStore | 100 | 186.004 ms | 3.4555 ms | 3.0632 ms | 1.40 | 0.05 | 1000.0000 | - | - | 4379.57 KB | +| CacheTower_ProtobufFileCacheLayer | 100 | 96.250 ms | 1.9033 ms | 3.3830 ms | 0.71 | 0.03 | - | - | - | 1108.1 KB | +| EasyCaching_Disk | 100 | 111.801 ms | 2.2223 ms | 5.1945 ms | 0.83 | 0.05 | - | - | - | 1766.05 KB | +| CacheTower_JsonFileCacheLayer | 100 | 134.760 ms | 2.6579 ms | 5.9993 ms | 1.00 | 0.00 | - | - | - | 2776.66 KB | +| MonkeyCache_FileStore | 100 | 189.205 ms | 3.6147 ms | 3.8677 ms | 1.39 | 0.08 | 1000.0000 | - | - | 4379.57 KB | | | | | | | | | | | | | -| CacheTower_ProtobufFileCacheLayer | 1000 | 890.211 ms | 16.0164 ms | 14.9817 ms | 0.72 | 0.01 | 3000.0000 | - | - | 10990.64 KB | -| EasyCaching_Disk | 1000 | 1,042.211 ms | 15.8395 ms | 14.8162 ms | 0.84 | 0.01 | 5000.0000 | - | - | 17489.97 KB | -| CacheTower_JsonFileCacheLayer | 1000 | 1,240.015 ms | 16.4974 ms | 15.4317 ms | 1.00 | 0.00 | 9000.0000 | - | - | 27566.44 KB | -| MonkeyCache_FileStore | 1000 | 1,831.111 ms | 12.2941 ms | 11.4999 ms | 1.48 | 0.02 | 14000.0000 | - | - | 43596.71 KB | +| CacheTower_ProtobufFileCacheLayer | 1000 | 896.184 ms | 17.0967 ms | 16.7913 ms | 0.71 | 0.02 | 3000.0000 | - | - | 10967.19 KB | +| EasyCaching_Disk | 1000 | 1,084.950 ms | 21.6665 ms | 28.1726 ms | 0.85 | 0.02 | 5000.0000 | - | - | 17494.84 KB | +| CacheTower_JsonFileCacheLayer | 1000 | 1,264.125 ms | 9.6589 ms | 8.5624 ms | 1.00 | 0.00 | 9000.0000 | - | - | 27543.12 KB | +| MonkeyCache_FileStore | 1000 | 1,837.440 ms | 27.0019 ms | 25.2576 ms | 1.45 | 0.02 | 14000.0000 | - | - | 43596.71 KB | ## Redis Caching | Method | Iterations | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | |--------------------------- |----------- |-----------:|----------:|----------:|-----------:|------:|--------:|----------:|------:|------:|-----------:| -| CacheTower_RedisCacheLayer | 1 | 1.556 ms | 0.0737 ms | 0.3032 ms | 1.538 ms | 1.00 | 0.00 | - | - | - | 8.68 KB | -| CacheManager_Redis | 1 | 2.671 ms | 0.1258 ms | 0.5229 ms | 2.595 ms | 1.78 | 0.53 | - | - | - | 27.32 KB | -| EasyCaching_Redis | 1 | 4.185 ms | 0.1176 ms | 0.4849 ms | 4.137 ms | 2.80 | 0.67 | - | - | - | 508.97 KB | +| CacheTower_RedisCacheLayer | 1 | 1.392 ms | 0.0824 ms | 0.3399 ms | 1.356 ms | 1.00 | 0.00 | - | - | - | 8.69 KB | +| CacheManager_Redis | 1 | 2.441 ms | 0.1261 ms | 0.5270 ms | 2.445 ms | 1.86 | 0.61 | - | - | - | 27.34 KB | +| EasyCaching_Redis | 1 | 3.752 ms | 0.1574 ms | 0.6597 ms | 3.628 ms | 2.85 | 0.84 | - | - | - | 509.45 KB | | | | | | | | | | | | | | -| EasyCaching_Redis | 100 | 42.269 ms | 0.8360 ms | 2.1280 ms | 41.626 ms | 1.03 | 0.06 | - | - | - | 851.64 KB | -| CacheManager_Redis | 100 | 42.639 ms | 0.8600 ms | 2.7176 ms | 41.706 ms | 1.06 | 0.05 | - | - | - | 554.92 KB | -| CacheTower_RedisCacheLayer | 100 | 43.361 ms | 1.9639 ms | 1.9288 ms | 42.616 ms | 1.00 | 0.00 | - | - | - | 475.92 KB | +| CacheTower_RedisCacheLayer | 100 | 40.059 ms | 0.7942 ms | 2.3541 ms | 39.633 ms | 1.00 | 0.00 | - | - | - | 381.15 KB | +| EasyCaching_Redis | 100 | 41.750 ms | 0.8300 ms | 2.0046 ms | 41.330 ms | 1.04 | 0.06 | - | - | - | 851.66 KB | +| CacheManager_Redis | 100 | 46.709 ms | 0.9291 ms | 2.9088 ms | 46.250 ms | 1.17 | 0.08 | - | - | - | 554.92 KB | | | | | | | | | | | | | | -| CacheTower_RedisCacheLayer | 1000 | 376.746 ms | 4.1325 ms | 3.8655 ms | 377.178 ms | 1.00 | 0.00 | 1000.0000 | - | - | 3856.94 KB | -| EasyCaching_Redis | 1000 | 379.035 ms | 3.7092 ms | 3.2881 ms | 379.064 ms | 1.01 | 0.01 | 1000.0000 | - | - | 3998.33 KB | -| CacheManager_Redis | 1000 | 398.433 ms | 4.7762 ms | 4.4676 ms | 398.183 ms | 1.06 | 0.02 | 1000.0000 | - | - | 5351.58 KB | \ No newline at end of file +| CacheTower_RedisCacheLayer | 1000 | 379.765 ms | 8.7609 ms | 8.9968 ms | 376.901 ms | 1.00 | 0.00 | 1000.0000 | - | - | 3660.41 KB | +| EasyCaching_Redis | 1000 | 385.377 ms | 7.1510 ms | 6.6891 ms | 385.932 ms | 1.01 | 0.03 | 1000.0000 | - | - | 3999.08 KB | +| CacheManager_Redis | 1000 | 432.212 ms | 6.8948 ms | 6.4494 ms | 432.085 ms | 1.14 | 0.03 | 1000.0000 | - | - | 5352.86 KB | \ No newline at end of file diff --git a/docs/Performance.md b/docs/Performance.md index f12a3a39..db77acf3 100644 --- a/docs/Performance.md +++ b/docs/Performance.md @@ -8,41 +8,42 @@ Regarding specific tests, it is best to look at the implementations themselves t **Test Machine** ``` -BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362 +BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18362 Intel Core i7-6700HQ CPU 2.60GHz (Skylake), 1 CPU, 8 logical and 4 physical cores .NET Core SDK=3.0.100 - [Host] : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT - Core : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT + [Host] : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), X64 RyuJIT + Job-CQNZSR : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), X64 RyuJIT -Job=Core Runtime=Core +Runtime=.NET Core 3.0 MaxIterationCount=200 +UnrollFactor=1 ``` ## Cache Stack Benchmark | Method | Mean [ns] | Error [ns] | StdDev [ns] | Gen 0 | Gen 1 | Gen 2 | Allocated [B] | |-------------------------- |----------------:|--------------:|--------------:|-------:|------:|------:|--------------:| -| SetupAndTeardown | 275.0 ns | 1.30 ns | 1.22 ns | 0.1326 | - | - | 416 B | -| Set | 678.8 ns | 3.35 ns | 3.13 ns | 0.1879 | - | - | 592 B | -| Set_TwoLayers | 773.4 ns | 2.06 ns | 1.93 ns | 0.2575 | - | - | 808 B | -| Evict | 790.9 ns | 3.48 ns | 3.25 ns | 0.1879 | - | - | 592 B | -| Evict_TwoLayers | 941.2 ns | 4.91 ns | 4.60 ns | 0.2575 | - | - | 808 B | -| Cleanup | 974.4 ns | 7.65 ns | 7.16 ns | 0.1869 | - | - | 592 B | -| Cleanup_TwoLayers | 1,208.6 ns | 4.53 ns | 3.54 ns | 0.2575 | - | - | 808 B | -| GetMiss | 388.1 ns | 2.34 ns | 2.07 ns | 0.1326 | - | - | 416 B | -| GetHit | 800.7 ns | 5.10 ns | 4.52 ns | 0.1879 | - | - | 592 B | -| GetOrSet | 2,043.9 ns | 14.51 ns | 13.58 ns | 0.3357 | - | - | 1064 B | -| GetOrSet_TwoSimultaneous | 62,232,054.8 ns | 329,492.60 ns | 308,207.58 ns | - | - | - | 3325 B | -| GetOrSet_FourSimultaneous | 62,144,815.6 ns | 395,286.63 ns | 369,751.36 ns | - | - | - | 3677 B | +| SetupAndTeardown | 269.3 ns | 4.63 ns | 4.11 ns | 0.1326 | - | - | 416 B | +| Set | 661.3 ns | 6.44 ns | 5.38 ns | 0.1860 | - | - | 584 B | +| Set_TwoLayers | 869.1 ns | 16.48 ns | 17.63 ns | 0.2975 | - | - | 936 B | +| Evict | 799.2 ns | 14.25 ns | 13.33 ns | 0.1860 | - | - | 584 B | +| Evict_TwoLayers | 1,030.8 ns | 14.00 ns | 13.09 ns | 0.2975 | - | - | 936 B | +| Cleanup | 958.3 ns | 6.89 ns | 6.11 ns | 0.1850 | - | - | 584 B | +| Cleanup_TwoLayers | 1,421.2 ns | 17.53 ns | 15.54 ns | 0.2975 | - | - | 936 B | +| GetMiss | 375.4 ns | 3.88 ns | 3.63 ns | 0.1326 | - | - | 416 B | +| GetHit | 793.1 ns | 12.73 ns | 11.91 ns | 0.1860 | - | - | 584 B | +| GetOrSet | 1,916.0 ns | 21.73 ns | 18.15 ns | 0.3319 | - | - | 1048 B | +| GetOrSet_TwoSimultaneous | 62,147,289.6 ns | 459,902.87 ns | 430,193.43 ns | - | - | - | 2322 B | +| GetOrSet_FourSimultaneous | 62,142,030.0 ns | 393,933.53 ns | 368,485.67 ns | - | - | - | 2831 B | ## Cache Layer Comparison Benchmark | Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | |----------------------- |-------------:|------------:|-------------:|-------------:|---------:|--------:|-----------:|------:|------:|------------:| -| MemoryCacheLayer | 124.3 us | 1.40 us | 1.17 us | 124.7 us | 1.00 | 0.00 | 30.7617 | - | - | 94.34 KB | -| RedisCacheLayer | 50,689.9 us | 1,008.28 us | 2,529.59 us | 49,719.1 us | 439.95 | 23.84 | - | - | - | 320.88 KB | -| ProtobufFileCacheLayer | 214,656.5 us | 4,261.38 us | 7,001.57 us | 214,159.9 us | 1,753.22 | 63.32 | - | - | - | 1585.24 KB | -| JsonFileCacheLayer | 262,911.9 us | 5,165.79 us | 9,182.18 us | 261,568.6 us | 2,103.16 | 74.19 | 1000.0000 | - | - | 3298.81 KB | -| MongoDbCacheLayer | 466,444.2 us | 9,211.19 us | 20,024.37 us | 464,238.5 us | 3,859.08 | 207.18 | 11000.0000 | - | - | 33892.99 KB | +| MemoryCacheLayer | 118.7 us | 2.26 us | 2.12 us | 118.4 us | 1.00 | 0.00 | 30.2734 | - | - | 92.77 KB | +| RedisCacheLayer | 48,898.5 us | 970.75 us | 2,488.40 us | 47,959.8 us | 442.92 | 16.99 | - | - | - | 315.05 KB | +| ProtobufFileCacheLayer | 225,156.9 us | 3,912.92 us | 3,468.70 us | 224,579.6 us | 1,896.36 | 47.60 | - | - | - | 1612.24 KB | +| JsonFileCacheLayer | 279,037.0 us | 5,569.81 us | 11,869.73 us | 275,174.1 us | 2,450.32 | 112.80 | 1000.0000 | - | - | 3314.62 KB | +| MongoDbCacheLayer | 484,883.7 us | 9,534.35 us | 19,901.73 us | 481,217.7 us | 4,177.79 | 176.27 | 10000.0000 | - | - | 30962.02 KB | ## In-Memory Benchmarks @@ -50,53 +51,53 @@ Job=Core Runtime=Core | Method | Mean [ns] | Error [ns] | StdDev [ns] | Gen 0 | Gen 1 | Gen 2 | Allocated [B] | |------------ |------------:|-----------:|------------:|-------:|------:|------:|--------------:| -| Overhead | 142.7 ns | 1.15 ns | 1.02 ns | 0.0663 | - | - | 208 B | -| GetMiss | 208.5 ns | 1.99 ns | 1.77 ns | 0.0663 | - | - | 208 B | -| GetHit | 533.8 ns | 3.10 ns | 2.90 ns | 0.1221 | - | - | 384 B | -| SetNew | 448.7 ns | 3.02 ns | 2.83 ns | 0.1221 | - | - | 384 B | -| SetExisting | 709.7 ns | 3.25 ns | 3.04 ns | 0.1345 | - | - | 424 B | -| SetMany | 34,425.9 ns | 160.00 ns | 149.66 ns | 6.9580 | - | - | 21920 B | +| Overhead | 135.1 ns | 1.09 ns | 0.97 ns | 0.0663 | - | - | 208 B | +| GetMiss | 212.0 ns | 1.64 ns | 1.53 ns | 0.0663 | - | - | 208 B | +| GetHit | 533.4 ns | 10.20 ns | 10.48 ns | 0.1192 | - | - | 376 B | +| SetNew | 433.4 ns | 6.15 ns | 5.45 ns | 0.1197 | - | - | 376 B | +| SetExisting | 745.5 ns | 10.43 ns | 9.24 ns | 0.1297 | - | - | 408 B | +| SetMany | 33,831.8 ns | 483.94 ns | 429.00 ns | 6.7139 | - | - | 21120 B | ## File System Benchmarks ### FileCacheLayerBase (Overhead) -| Method | Mean [ns] | Error [ns] | StdDev [ns] | Gen 0 | Gen 1 | Gen 2 | Allocated [B] | -|------------------------ |----------------:|-------------:|---------------:|------:|------:|------:|--------------:| -| GetHitSimultaneous | 2,341,841.8 ns | 76,116.2 ns | 318,943.0 ns | - | - | - | 16120 B | -| SetExistingSimultaneous | 2,339,074.7 ns | 75,701.7 ns | 312,161.1 ns | - | - | - | 12664 B | -| Overhead | 1,073,281.4 ns | 39,850.4 ns | 166,101.1 ns | - | - | - | 4560 B | -| GetMiss | 1,482,845.9 ns | 50,339.9 ns | 209,822.5 ns | - | - | - | 7400 B | -| GetHit | 2,113,604.9 ns | 58,434.3 ns | 237,663.9 ns | - | - | - | 13424 B | -| SetNew | 1,957,598.5 ns | 59,701.2 ns | 249,502.0 ns | - | - | - | 9856 B | -| SetExisting | 2,160,977.6 ns | 70,054.7 ns | 293,544.4 ns | - | - | - | 11704 B | -| SetMany | 44,174,175.0 ns | 877,421.9 ns | 2,102,246.8 ns | - | - | - | 269352 B | +| Method | Mean [ns] | Error [ns] | StdDev [ns] | Median [ns] | Gen 0 | Gen 1 | Gen 2 | Allocated [B] | +|------------------------ |----------------:|-------------:|---------------:|----------------:|------:|------:|------:|--------------:| +| GetHitSimultaneous | 2,239,577.2 ns | 67,345.3 ns | 276,948.1 ns | 2,202,500.0 ns | - | - | - | 16408 B | +| SetExistingSimultaneous | 2,332,610.9 ns | 70,150.4 ns | 290,836.7 ns | 2,264,750.0 ns | - | - | - | 12792 B | +| Overhead | 1,087,240.7 ns | 37,834.9 ns | 157,280.7 ns | 1,063,050.0 ns | - | - | - | 4560 B | +| GetMiss | 1,445,024.1 ns | 45,014.7 ns | 184,102.9 ns | 1,423,500.0 ns | - | - | - | 7400 B | +| GetHit | 2,091,793.5 ns | 53,136.4 ns | 219,705.9 ns | 2,050,550.0 ns | - | - | - | 13344 B | +| SetNew | 1,918,547.1 ns | 53,247.8 ns | 217,774.8 ns | 1,889,100.0 ns | - | - | - | 9840 B | +| SetExisting | 2,207,402.1 ns | 73,197.0 ns | 303,467.6 ns | 2,181,050.0 ns | - | - | - | 11520 B | +| SetMany | 46,902,491.5 ns | 973,060.0 ns | 1,754,627.9 ns | 46,771,950.0 ns | - | - | - | 254400 B | ### JsonFileCacheLayer | Method | Mean [ns] | Error [ns] | StdDev [ns] | Median [ns] | Gen 0 | Gen 1 | Gen 2 | Allocated [B] | |------------------------ |----------------:|---------------:|---------------:|----------------:|------:|------:|------:|--------------:| -| GetHitSimultaneous | 5,034,252.0 ns | 159,425.6 ns | 671,531.7 ns | 4,960,550.0 ns | - | - | - | 51816 B | -| SetExistingSimultaneous | 5,403,373.1 ns | 174,596.2 ns | 733,517.1 ns | 5,318,100.0 ns | - | - | - | 51432 B | -| Overhead | 1,668,915.7 ns | 55,233.5 ns | 232,048.2 ns | 1,618,800.0 ns | - | - | - | 12488 B | -| GetMiss | 2,696,957.2 ns | 85,972.3 ns | 358,342.7 ns | 2,612,950.0 ns | - | - | - | 23816 B | -| GetHit | 4,511,776.6 ns | 163,788.1 ns | 688,109.6 ns | 4,472,800.0 ns | - | - | - | 42816 B | -| SetNew | 3,760,407.9 ns | 112,108.2 ns | 463,539.5 ns | 3,740,600.0 ns | - | - | - | 33568 B | -| SetExisting | 4,620,312.1 ns | 155,706.6 ns | 655,866.8 ns | 4,574,850.0 ns | - | - | - | 42984 B | -| SetMany | 90,178,101.8 ns | 1,798,547.6 ns | 3,909,894.4 ns | 89,256,200.0 ns | - | - | - | 1090800 B | +| GetHitSimultaneous | 4,487,127.1 ns | 125,167.5 ns | 518,932.3 ns | 4,397,400.0 ns | - | - | - | 51928 B | +| SetExistingSimultaneous | 4,983,330.6 ns | 123,043.3 ns | 511,494.1 ns | 4,892,300.0 ns | - | - | - | 51440 B | +| Overhead | 1,644,103.4 ns | 48,518.2 ns | 200,610.7 ns | 1,613,850.0 ns | - | - | - | 12488 B | +| GetMiss | 2,583,441.9 ns | 78,073.1 ns | 322,812.8 ns | 2,505,800.0 ns | - | - | - | 23656 B | +| GetHit | 4,067,251.8 ns | 103,713.9 ns | 428,831.3 ns | 4,003,700.0 ns | - | - | - | 42720 B | +| SetNew | 3,569,423.2 ns | 96,998.7 ns | 399,981.1 ns | 3,509,900.0 ns | - | - | - | 33480 B | +| SetExisting | 4,229,421.4 ns | 109,822.2 ns | 455,312.2 ns | 4,148,700.0 ns | - | - | - | 42888 B | +| SetMany | 92,741,550.0 ns | 1,837,211.9 ns | 3,217,728.5 ns | 92,088,850.0 ns | - | - | - | 1081200 B | ### ProtobufFileCacheLayer -| Method | Mean [ns] | Error [ns] | StdDev [ns] | Gen 0 | Gen 1 | Gen 2 | Allocated [B] | -|------------------------ |----------------:|---------------:|---------------:|------:|------:|------:|--------------:| -| GetHitSimultaneous | 3,580,929.3 ns | 100,444.5 ns | 415,313.0 ns | - | - | - | 21304 B | -| SetExistingSimultaneous | 3,978,112.4 ns | 112,489.1 ns | 467,620.1 ns | - | - | - | 21240 B | -| Overhead | 1,269,990.8 ns | 49,961.3 ns | 209,348.7 ns | - | - | - | 4608 B | -| GetMiss | 1,697,858.4 ns | 54,100.6 ns | 223,087.7 ns | - | - | - | 7440 B | -| GetHit | 3,366,020.6 ns | 93,677.2 ns | 385,234.3 ns | - | - | - | 17768 B | -| SetNew | 3,222,964.6 ns | 103,708.6 ns | 429,965.9 ns | - | - | - | 14040 B | -| SetExisting | 3,634,562.3 ns | 114,139.8 ns | 471,939.9 ns | - | - | - | 17856 B | -| SetMany | 62,429,050.0 ns | 1,259,236.3 ns | 2,365,151.0 ns | - | - | - | 490696 B | +| Method | Mean [ns] | Error [ns] | StdDev [ns] | Median [ns] | Gen 0 | Gen 1 | Gen 2 | Allocated [B] | +|------------------------ |----------------:|---------------:|---------------:|----------------:|------:|------:|------:|--------------:| +| GetHitSimultaneous | 3,116,055.4 ns | 67,536.2 ns | 275,448.7 ns | 3,052,450.0 ns | - | - | - | 21272 B | +| SetExistingSimultaneous | 3,627,764.3 ns | 84,783.8 ns | 348,661.2 ns | 3,544,450.0 ns | - | - | - | 21208 B | +| Overhead | 1,183,173.3 ns | 35,858.8 ns | 148,267.1 ns | 1,176,100.0 ns | - | - | - | 4608 B | +| GetMiss | 1,562,540.4 ns | 48,793.1 ns | 202,834.2 ns | 1,524,000.0 ns | - | - | - | 7440 B | +| GetHit | 3,108,708.2 ns | 95,251.7 ns | 398,074.3 ns | 2,997,200.0 ns | - | - | - | 17744 B | +| SetNew | 2,895,570.7 ns | 82,929.6 ns | 340,103.9 ns | 2,814,650.0 ns | - | - | - | 14184 B | +| SetExisting | 3,224,126.8 ns | 93,260.0 ns | 388,718.7 ns | 3,126,650.0 ns | - | - | - | 17976 B | +| SetMany | 62,606,770.0 ns | 1,249,913.1 ns | 2,795,609.8 ns | 62,614,000.0 ns | - | - | - | 477120 B | ## Database Benchmarks @@ -104,14 +105,14 @@ Job=Core Runtime=Core | Method | Mean [ns] | Error [ns] | StdDev [ns] | Median [ns] | Gen 0 | Gen 1 | Gen 2 | Allocated [B] | |------------------------ |-----------------:|---------------:|---------------:|-----------------:|----------:|------:|------:|--------------:| -| GetHitSimultaneous | 70,652,243.9 ns | 1,847,772.3 ns | 7,783,178.4 ns | 69,219,350.0 ns | - | - | - | 277504 B | -| SetExistingSimultaneous | 70,761,139.7 ns | 1,785,866.2 ns | 7,443,701.3 ns | 69,789,050.0 ns | - | - | - | 253016 B | -| Overhead | 7,777.6 ns | 493.5 ns | 1,891.7 ns | 7,400.0 ns | - | - | - | 424 B | -| GetMiss | 67,504,475.6 ns | 1,778,059.7 ns | 7,470,019.1 ns | 65,904,500.0 ns | - | - | - | 121680 B | -| GetHit | 71,031,643.2 ns | 1,820,413.6 ns | 7,687,867.3 ns | 70,016,600.0 ns | - | - | - | 198000 B | -| SetNew | 69,524,188.8 ns | 1,715,738.5 ns | 7,208,194.0 ns | 68,905,900.0 ns | - | - | - | 109984 B | -| SetExisting | 70,536,871.4 ns | 1,895,253.2 ns | 7,941,517.9 ns | 68,789,700.0 ns | - | - | - | 181504 B | -| SetMany | 128,326,730.3 ns | 2,562,373.3 ns | 7,514,997.3 ns | 127,383,300.0 ns | 2000.0000 | - | - | 7294544 B | +| GetHitSimultaneous | 72,721,353.5 ns | 1,949,497.6 ns | 8,211,665.2 ns | 71,905,100.0 ns | - | - | - | 261544 B | +| SetExistingSimultaneous | 70,983,916.3 ns | 2,088,962.4 ns | 8,753,201.0 ns | 69,894,400.0 ns | - | - | - | 210224 B | +| Overhead | 6,833.7 ns | 794.4 ns | 3,026.2 ns | 5,900.0 ns | - | - | - | 424 B | +| GetMiss | 67,859,459.3 ns | 1,720,821.5 ns | 7,172,587.1 ns | 66,883,550.0 ns | - | - | - | 121664 B | +| GetHit | 69,726,953.5 ns | 1,907,277.3 ns | 8,033,824.9 ns | 68,625,600.0 ns | - | - | - | 182888 B | +| SetNew | 69,912,851.0 ns | 1,938,316.5 ns | 8,079,132.0 ns | 68,548,250.0 ns | - | - | - | 95720 B | +| SetExisting | 68,935,014.2 ns | 1,906,826.9 ns | 8,010,998.5 ns | 67,035,400.0 ns | - | - | - | 152976 B | +| SetMany | 125,761,659.1 ns | 2,502,151.4 ns | 7,759,473.3 ns | 124,211,200.0 ns | 1000.0000 | - | - | 5867032 B | ## Other @@ -119,15 +120,14 @@ Job=Core Runtime=Core | Method | Mean [ns] | Error [ns] | StdDev [ns] | Median [ns] | Gen 0 | Gen 1 | Gen 2 | Allocated [B] | |------------------------ |----------------:|-------------:|-------------:|----------------:|------:|------:|------:|--------------:| -| GetHitSimultaneous | 689,292.9 ns | 28,848.7 ns | 117,005.6 ns | 683,250.0 ns | - | - | - | 3040 B | -| SetExistingSimultaneous | 694,434.0 ns | 30,077.4 ns | 123,011.6 ns | 688,150.0 ns | - | - | - | 3232 B | -| Overhead | 8,091.0 ns | 1,256.6 ns | 4,847.1 ns | 6,300.0 ns | - | - | - | 136 B | -| GetMiss | 404,778.8 ns | 21,734.5 ns | 89,380.1 ns | 389,800.0 ns | - | - | - | 840 B | -| GetHit | 663,348.3 ns | 22,604.0 ns | 90,642.7 ns | 658,800.0 ns | - | - | - | 2296 B | -| SetNew | 424,456.9 ns | 24,487.5 ns | 100,426.2 ns | 400,350.0 ns | - | - | - | 1304 B | -| SetExisting | 694,905.3 ns | 28,549.4 ns | 117,084.4 ns | 684,850.0 ns | - | - | - | 2288 B | -| SetMany | 13,767,330.3 ns | 268,302.3 ns | 985,616.9 ns | 13,577,950.0 ns | - | - | - | 97456 B | - +| GetHitSimultaneous | 543,613.0 ns | 32,141.7 ns | 133,256.3 ns | 519,700.0 ns | - | - | - | 3168 B | +| SetExistingSimultaneous | 655,500.0 ns | 40,606.6 ns | 169,253.1 ns | 642,500.0 ns | - | - | - | 3184 B | +| Overhead | 7,708.5 ns | 1,506.6 ns | 5,989.1 ns | 5,300.0 ns | - | - | - | 136 B | +| GetMiss | 343,654.7 ns | 18,416.4 ns | 76,352.8 ns | 329,850.0 ns | - | - | - | 840 B | +| GetHit | 582,914.5 ns | 23,003.7 ns | 93,821.2 ns | 574,150.0 ns | - | - | - | 2256 B | +| SetNew | 387,381.4 ns | 19,223.8 ns | 78,186.9 ns | 382,050.0 ns | - | - | - | 1288 B | +| SetExisting | 595,099.5 ns | 22,497.1 ns | 90,987.9 ns | 591,600.0 ns | - | - | - | 2256 B | +| SetMany | 12,999,862.4 ns | 267,127.9 ns | 886,036.4 ns | 12,924,600.0 ns | - | - | - | 95832 B | ## Extensions diff --git a/src/CacheTower.Extensions.Redis/RedisLockExtension.cs b/src/CacheTower.Extensions.Redis/RedisLockExtension.cs index ff03ee67..75405713 100644 --- a/src/CacheTower.Extensions.Redis/RedisLockExtension.cs +++ b/src/CacheTower.Extensions.Redis/RedisLockExtension.cs @@ -90,7 +90,7 @@ private async Task> WaitForResult(string cacheKey, CacheSetting //Last minute check to confirm whether waiting is required (in case the notification is missed) var currentEntry = await RegisteredStack.GetAsync(cacheKey); - if (currentEntry != null && !currentEntry.HasElapsed(settings.StaleAfter)) + if (currentEntry != null && currentEntry.GetStaleDate(settings) > DateTime.UtcNow) { UnlockWaitingTasks(cacheKey); return currentEntry; diff --git a/src/CacheTower.Providers.Database.MongoDB/Commands/SetCommand.cs b/src/CacheTower.Providers.Database.MongoDB/Commands/SetCommand.cs index 8be66f4d..4a89a5d1 100644 --- a/src/CacheTower.Providers.Database.MongoDB/Commands/SetCommand.cs +++ b/src/CacheTower.Providers.Database.MongoDB/Commands/SetCommand.cs @@ -23,8 +23,6 @@ public IEnumerable> GetModel() var filter = Builders.Filter.Eq(e => e.CacheKey, Entry.CacheKey); var updateDefinition = Builders.Update .Set(e => e.CacheKey, Entry.CacheKey) - .Set(e => e.CachedAt, Entry.CachedAt) - .Set(e => e.TimeToLive, Entry.TimeToLive) .Set(e => e.Expiry, Entry.Expiry) .Set(e => e.Value, Entry.Value); diff --git a/src/CacheTower.Providers.Database.MongoDB/Entities/DbCachedEntry.cs b/src/CacheTower.Providers.Database.MongoDB/Entities/DbCachedEntry.cs index 604b87f2..2d0bbbff 100644 --- a/src/CacheTower.Providers.Database.MongoDB/Entities/DbCachedEntry.cs +++ b/src/CacheTower.Providers.Database.MongoDB/Entities/DbCachedEntry.cs @@ -14,15 +14,9 @@ public class DbCachedEntry [Index(MongoFramework.IndexSortOrder.Ascending)] public string CacheKey { get; set; } - public DateTime CachedAt { get; set; } - public TimeSpan TimeToLive { get; set; } [Index(MongoFramework.IndexSortOrder.Ascending)] - public DateTime Expiry - { - get => CachedAt + TimeToLive; - set { } - } + public DateTime Expiry { get; set; } public object Value { get; set; } } diff --git a/src/CacheTower.Providers.Database.MongoDB/MongoDbCacheLayer.cs b/src/CacheTower.Providers.Database.MongoDB/MongoDbCacheLayer.cs index 29008da6..1fe1574d 100644 --- a/src/CacheTower.Providers.Database.MongoDB/MongoDbCacheLayer.cs +++ b/src/CacheTower.Providers.Database.MongoDB/MongoDbCacheLayer.cs @@ -60,7 +60,7 @@ public async Task> GetAsync(string cacheKey) if (dbEntry != default) { - cacheEntry = new CacheEntry((T)dbEntry.Value, dbEntry.CachedAt, dbEntry.TimeToLive); + cacheEntry = new CacheEntry((T)dbEntry.Value, dbEntry.Expiry); } return cacheEntry; @@ -72,8 +72,7 @@ public async Task SetAsync(string cacheKey, CacheEntry cacheEntry) var command = new SetCommand(new DbCachedEntry { CacheKey = cacheKey, - CachedAt = cacheEntry.CachedAt, - TimeToLive = cacheEntry.TimeToLive, + Expiry = cacheEntry.Expiry, Value = cacheEntry.Value }); diff --git a/src/CacheTower.Providers.FileSystem.Json/JsonFileCacheLayer.cs b/src/CacheTower.Providers.FileSystem.Json/JsonFileCacheLayer.cs index b1476741..01228c99 100644 --- a/src/CacheTower.Providers.FileSystem.Json/JsonFileCacheLayer.cs +++ b/src/CacheTower.Providers.FileSystem.Json/JsonFileCacheLayer.cs @@ -14,11 +14,6 @@ public class JsonFileCacheLayer : FileCacheLayerBase, ICacheLayer public JsonFileCacheLayer(string directoryPath) : base(directoryPath, ".json") { } - private class DataWrapper - { - public T Value { get; set; } - } - protected override T Deserialize(Stream stream) { using (var streamReader = new StreamReader(stream, Encoding.UTF8, false, 1024)) diff --git a/src/CacheTower.Providers.FileSystem.Protobuf/ProtobufManifestEntry.cs b/src/CacheTower.Providers.FileSystem.Protobuf/ProtobufManifestEntry.cs index 466b6f88..064c1934 100644 --- a/src/CacheTower.Providers.FileSystem.Protobuf/ProtobufManifestEntry.cs +++ b/src/CacheTower.Providers.FileSystem.Protobuf/ProtobufManifestEntry.cs @@ -11,8 +11,6 @@ public class ProtobufManifestEntry : IManifestEntry [ProtoMember(1)] public string FileName { get; set; } [ProtoMember(2)] - public DateTime CachedAt { get; set; } - [ProtoMember(3)] - public TimeSpan TimeToLive { get; set; } + public DateTime Expiry { get; set; } } } diff --git a/src/CacheTower.Providers.Redis/Entities/RedisCacheEntry.cs b/src/CacheTower.Providers.Redis/Entities/RedisCacheEntry.cs index f3c5aa3b..bd0c93ca 100644 --- a/src/CacheTower.Providers.Redis/Entities/RedisCacheEntry.cs +++ b/src/CacheTower.Providers.Redis/Entities/RedisCacheEntry.cs @@ -9,10 +9,8 @@ namespace CacheTower.Providers.Redis.Entities public class RedisCacheEntry { [ProtoMember(1)] - public DateTime CachedAt { get; set; } + public DateTime Expiry { get; set; } [ProtoMember(2)] - public TimeSpan TimeToLive { get; set; } - [ProtoMember(3)] public T Value { get; set; } } } diff --git a/src/CacheTower.Providers.Redis/RedisCacheLayer.cs b/src/CacheTower.Providers.Redis/RedisCacheLayer.cs index 29501cda..38a149f4 100644 --- a/src/CacheTower.Providers.Redis/RedisCacheLayer.cs +++ b/src/CacheTower.Providers.Redis/RedisCacheLayer.cs @@ -12,7 +12,7 @@ public class RedisCacheLayer : IAsyncCacheLayer private IDatabaseAsync Database { get; } private bool? IsCacheAvailable { get; set; } - public RedisCacheLayer(ConnectionMultiplexer connection, int databaseIndex = -1) + public RedisCacheLayer(IConnectionMultiplexer connection, int databaseIndex = -1) { Database = connection.GetDatabase(databaseIndex); } @@ -36,7 +36,7 @@ public async Task> GetAsync(string cacheKey) using (var stream = new MemoryStream(redisValue)) { var redisCacheEntry = Serializer.Deserialize>(stream); - return new CacheEntry(redisCacheEntry.Value, redisCacheEntry.CachedAt, redisCacheEntry.TimeToLive); + return new CacheEntry(redisCacheEntry.Value, redisCacheEntry.Expiry); } } @@ -63,17 +63,15 @@ public async Task IsAvailableAsync(string cacheKey) public async Task SetAsync(string cacheKey, CacheEntry cacheEntry) { - //Redis doesn't support setting a TTL in the past, let's confirm the expiry date - var trueTtl = (cacheEntry.CachedAt + cacheEntry.TimeToLive) - DateTime.UtcNow; - if (trueTtl < TimeSpan.Zero) + var expiryOffset = cacheEntry.Expiry - DateTime.UtcNow; + if (expiryOffset < TimeSpan.Zero) { return; } var redisCacheEntry = new RedisCacheEntry { - CachedAt = cacheEntry.CachedAt, - TimeToLive = cacheEntry.TimeToLive, + Expiry = cacheEntry.Expiry, Value = cacheEntry.Value }; @@ -83,7 +81,7 @@ public async Task SetAsync(string cacheKey, CacheEntry cacheEntry) stream.Seek(0, SeekOrigin.Begin); var redisValue = RedisValue.CreateFrom(stream); - await Database.StringSetAsync(cacheKey, redisValue, cacheEntry.TimeToLive); + await Database.StringSetAsync(cacheKey, redisValue, expiryOffset); } } } diff --git a/src/CacheTower/CacheEntry.cs b/src/CacheTower/CacheEntry.cs index 63b273b8..8722cde9 100644 --- a/src/CacheTower/CacheEntry.cs +++ b/src/CacheTower/CacheEntry.cs @@ -7,27 +7,20 @@ namespace CacheTower { public abstract class CacheEntry { - public DateTime CachedAt { get; } + public DateTime Expiry { get; } - public TimeSpan TimeToLive { get; } - - protected CacheEntry(DateTime cachedAt, TimeSpan timeToLive) + protected CacheEntry(DateTime expiry) { - if (timeToLive < TimeSpan.Zero) - { - throw new ArgumentOutOfRangeException(nameof(timeToLive), "TimeSpan must be greater than or equal to zero"); - } - - CachedAt = new DateTime( - cachedAt.Year, cachedAt.Month, cachedAt.Day, cachedAt.Hour, cachedAt.Minute, cachedAt.Second, DateTimeKind.Utc + //Force the resolution of the expiry date to be to the second + Expiry = new DateTime( + expiry.Year, expiry.Month, expiry.Day, expiry.Hour, expiry.Minute, expiry.Second, DateTimeKind.Utc ); - TimeToLive = timeToLive; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasElapsed(TimeSpan timeSpan) + public DateTime GetStaleDate(CacheSettings cacheSettings) { - return CachedAt.Add(timeSpan) < DateTime.UtcNow; + return Expiry - cacheSettings.TimeToLive + cacheSettings.StaleAfter; } } @@ -35,7 +28,8 @@ public class CacheEntry : CacheEntry, IEquatable> { public T Value { get; } - public CacheEntry(T value, DateTime cachedAt, TimeSpan timeToLive) : base(cachedAt, timeToLive) + public CacheEntry(T value, TimeSpan timeToLive) : this(value, DateTime.UtcNow + timeToLive) { } + public CacheEntry(T value, DateTime expiry) : base(expiry) { Value = value; } @@ -48,8 +42,7 @@ public bool Equals(CacheEntry other) } return Equals(Value, other.Value) && - CachedAt == other.CachedAt && - TimeToLive == other.TimeToLive; + Expiry == other.Expiry; } public override bool Equals(object obj) @@ -64,7 +57,7 @@ public override bool Equals(object obj) public override int GetHashCode() { - return (Value?.GetHashCode() ?? 1) ^ CachedAt.GetHashCode() ^ TimeToLive.GetHashCode(); + return (Value?.GetHashCode() ?? 1) ^ Expiry.GetHashCode(); } } } diff --git a/src/CacheTower/CacheStack.cs b/src/CacheTower/CacheStack.cs index d48a697c..fa0a2ed5 100644 --- a/src/CacheTower/CacheStack.cs +++ b/src/CacheTower/CacheStack.cs @@ -97,7 +97,8 @@ public async ValueTask> SetAsync(string cacheKey, T value, Time { ThrowIfDisposed(); - var cacheEntry = new CacheEntry(value, DateTime.UtcNow, timeToLive); + var expiry = DateTime.UtcNow + timeToLive; + var cacheEntry = new CacheEntry(value, expiry); await SetAsync(cacheKey, cacheEntry); return cacheEntry; } @@ -222,10 +223,10 @@ public async ValueTask GetOrSetAsync(string cacheKey, Func> RefreshValueAsync(string cacheKey, Fun //Last minute check to confirm whether waiting is required var currentEntry = await GetAsync(cacheKey); - if (currentEntry != null && !currentEntry.HasElapsed(settings.StaleAfter)) + if (currentEntry != null && currentEntry.GetStaleDate(settings) > DateTime.UtcNow) { UnlockWaitingTasks(cacheKey); return currentEntry; diff --git a/src/CacheTower/Providers/FileSystem/FileCacheLayerBase.cs b/src/CacheTower/Providers/FileSystem/FileCacheLayerBase.cs index 8528a14f..0c36e054 100644 --- a/src/CacheTower/Providers/FileSystem/FileCacheLayerBase.cs +++ b/src/CacheTower/Providers/FileSystem/FileCacheLayerBase.cs @@ -158,11 +158,11 @@ public async Task CleanupAsync() { await TryLoadManifestAsync(); + var currentTime = DateTime.UtcNow; foreach (var cachePair in CacheManifest) { var manifestEntry = cachePair.Value; - var expiryDate = manifestEntry.CachedAt.Add(manifestEntry.TimeToLive); - if (expiryDate < DateTime.UtcNow && CacheManifest.TryRemove(cachePair.Key, out var _)) + if (manifestEntry.Expiry < currentTime && CacheManifest.TryRemove(cachePair.Key, out var _)) { if (FileLock.TryRemove(manifestEntry.FileName, out var lockObj)) { @@ -213,7 +213,7 @@ public async Task> GetAsync(string cacheKey) { var path = Path.Combine(DirectoryPath, manifestEntry.FileName); var value = await DeserializeFileAsync(path); - return new CacheEntry(value, manifestEntry.CachedAt, manifestEntry.TimeToLive); + return new CacheEntry(value, manifestEntry.Expiry); } } } @@ -248,9 +248,8 @@ public async Task SetAsync(string cacheKey, CacheEntry cacheEntry) FileName = GetFileName(cacheKey) }); - //Update the manifest entry with the new cache entry date/times - manifestEntry.CachedAt = cacheEntry.CachedAt; - manifestEntry.TimeToLive = cacheEntry.TimeToLive; + //Update the manifest entry with the new expiry + manifestEntry.Expiry = cacheEntry.Expiry; var lockObj = FileLock.GetOrAdd(manifestEntry.FileName, (name) => new AsyncReaderWriterLock()); diff --git a/src/CacheTower/Providers/FileSystem/IManifestEntry.cs b/src/CacheTower/Providers/FileSystem/IManifestEntry.cs index 7d71978b..ff8f6ccf 100644 --- a/src/CacheTower/Providers/FileSystem/IManifestEntry.cs +++ b/src/CacheTower/Providers/FileSystem/IManifestEntry.cs @@ -7,7 +7,6 @@ namespace CacheTower.Providers.FileSystem public interface IManifestEntry { string FileName { get; set; } - DateTime CachedAt { get; set; } - TimeSpan TimeToLive { get; set; } + DateTime Expiry { get; set; } } } diff --git a/src/CacheTower/Providers/FileSystem/ManifestEntry.cs b/src/CacheTower/Providers/FileSystem/ManifestEntry.cs index d0ff7892..4dad243b 100644 --- a/src/CacheTower/Providers/FileSystem/ManifestEntry.cs +++ b/src/CacheTower/Providers/FileSystem/ManifestEntry.cs @@ -7,7 +7,6 @@ namespace CacheTower.Providers.FileSystem public class ManifestEntry : IManifestEntry { public string FileName { get; set; } - public DateTime CachedAt { get; set; } - public TimeSpan TimeToLive { get; set; } + public DateTime Expiry { get; set; } } } diff --git a/src/CacheTower/Providers/Memory/MemoryCacheLayer.cs b/src/CacheTower/Providers/Memory/MemoryCacheLayer.cs index 24979410..ea15999d 100644 --- a/src/CacheTower/Providers/Memory/MemoryCacheLayer.cs +++ b/src/CacheTower/Providers/Memory/MemoryCacheLayer.cs @@ -22,11 +22,12 @@ public void Cleanup() { var keysToRemove = ArrayPool.Shared.Rent(Cache.Count); var index = 0; + var currentTime = DateTime.UtcNow; foreach (var cachePair in Cache) { var cacheEntry = cachePair.Value; - if (cacheEntry.HasElapsed(cacheEntry.TimeToLive)) + if (cacheEntry.Expiry < currentTime) { keysToRemove[index] = cachePair.Key; index++; diff --git a/tests/CacheTower.AlternativesBenchmark/CacheAlternatives_Memory_Benchmark.cs b/tests/CacheTower.AlternativesBenchmark/CacheAlternatives_Memory_Benchmark.cs index 8dd74d27..c3d07b20 100644 --- a/tests/CacheTower.AlternativesBenchmark/CacheAlternatives_Memory_Benchmark.cs +++ b/tests/CacheTower.AlternativesBenchmark/CacheAlternatives_Memory_Benchmark.cs @@ -40,13 +40,13 @@ public void CacheTower_MemoryCacheLayer_Direct() { LoopAction(Iterations, () => { - layer.Set("TestKey", new CacheEntry(123, DateTime.UtcNow, TimeSpan.FromDays(1))); + layer.Set("TestKey", new CacheEntry(123, DateTime.UtcNow + TimeSpan.FromDays(1))); layer.Get("TestKey"); var getOrSetResult = layer.Get("GetOrSet_TestKey"); if (getOrSetResult == null) { - layer.Set("GetOrSet_TestKey", new CacheEntry("Hello World", DateTime.UtcNow, TimeSpan.FromDays(1))); + layer.Set("GetOrSet_TestKey", new CacheEntry("Hello World", TimeSpan.FromDays(1))); } }); } diff --git a/tests/CacheTower.Benchmarks/CacheStackBenchmark.cs b/tests/CacheTower.Benchmarks/CacheStackBenchmark.cs index a7c146d4..47b34e34 100644 --- a/tests/CacheTower.Benchmarks/CacheStackBenchmark.cs +++ b/tests/CacheTower.Benchmarks/CacheStackBenchmark.cs @@ -110,7 +110,7 @@ public async Task GetOrSet() { await using (var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, Array.Empty())) { - await cacheStack.SetAsync("GetOrSet", new CacheEntry(15, DateTime.UtcNow.AddDays(-2), TimeSpan.FromDays(1))); + await cacheStack.SetAsync("GetOrSet", new CacheEntry(15, DateTime.UtcNow.AddDays(-1))); await cacheStack.GetOrSetAsync("GetOrSet", (old, context) => { return Task.FromResult(12); @@ -122,7 +122,7 @@ public async Task GetOrSet_TwoSimultaneous() { await using (var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, Array.Empty())) { - await cacheStack.SetAsync("GetOrSet", new CacheEntry(15, DateTime.UtcNow.AddDays(-2), TimeSpan.FromDays(1))); + await cacheStack.SetAsync("GetOrSet", new CacheEntry(15, DateTime.UtcNow.AddDays(-1))); var task1 = cacheStack.GetOrSetAsync("GetOrSet", async (old, context) => { await Task.Delay(50); @@ -143,7 +143,7 @@ public async Task GetOrSet_FourSimultaneous() { await using (var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, Array.Empty())) { - await cacheStack.SetAsync("GetOrSet", new CacheEntry(15, DateTime.UtcNow.AddDays(-2), TimeSpan.FromDays(1))); + await cacheStack.SetAsync("GetOrSet", new CacheEntry(15, DateTime.UtcNow.AddDays(-1))); var task1 = cacheStack.GetOrSetAsync("GetOrSet", async (old, context) => { await Task.Delay(50); diff --git a/tests/CacheTower.Benchmarks/Extensions/BaseRefreshWrapperExtensionsBenchmark.cs b/tests/CacheTower.Benchmarks/Extensions/BaseRefreshWrapperExtensionsBenchmark.cs index 3431b0a5..59fa2127 100644 --- a/tests/CacheTower.Benchmarks/Extensions/BaseRefreshWrapperExtensionsBenchmark.cs +++ b/tests/CacheTower.Benchmarks/Extensions/BaseRefreshWrapperExtensionsBenchmark.cs @@ -15,7 +15,7 @@ public async Task RefreshValue() extension.Register(CacheStack); await extension.RefreshValueAsync("RefreshValue", () => { - return new ValueTask>(new CacheEntry(5, DateTime.UtcNow, TimeSpan.FromDays(1))); + return new ValueTask>(new CacheEntry(5, TimeSpan.FromDays(1))); }, new CacheSettings(TimeSpan.FromDays(1))); await DisposeOf(extension); } diff --git a/tests/CacheTower.Benchmarks/Providers/BaseAsyncCacheLayerBenchmark.cs b/tests/CacheTower.Benchmarks/Providers/BaseAsyncCacheLayerBenchmark.cs index 1eec7ce5..dd9aa146 100644 --- a/tests/CacheTower.Benchmarks/Providers/BaseAsyncCacheLayerBenchmark.cs +++ b/tests/CacheTower.Benchmarks/Providers/BaseAsyncCacheLayerBenchmark.cs @@ -13,7 +13,7 @@ public async Task GetHitSimultaneous() { var cacheLayer = CacheLayerProvider.Invoke() as IAsyncCacheLayer; - await cacheLayer.SetAsync("GetHitSimultaneous", new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + await cacheLayer.SetAsync("GetHitSimultaneous", new CacheEntry(1, TimeSpan.FromDays(1))); var aTask = cacheLayer.GetAsync("GetHitSimultaneous"); var bTask = cacheLayer.GetAsync("GetHitSimultaneous"); @@ -29,10 +29,10 @@ public async Task SetExistingSimultaneous() { var cacheLayer = CacheLayerProvider.Invoke() as IAsyncCacheLayer; - await cacheLayer.SetAsync("SetExistingSimultaneous", new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + await cacheLayer.SetAsync("SetExistingSimultaneous", new CacheEntry(1, TimeSpan.FromDays(1))); - var aTask = cacheLayer.SetAsync("SetExistingSimultaneous", new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); - var bTask = cacheLayer.SetAsync("SetExistingSimultaneous", new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + var aTask = cacheLayer.SetAsync("SetExistingSimultaneous", new CacheEntry(1, TimeSpan.FromDays(1))); + var bTask = cacheLayer.SetAsync("SetExistingSimultaneous", new CacheEntry(1, TimeSpan.FromDays(1))); await aTask; await bTask; diff --git a/tests/CacheTower.Benchmarks/Providers/BaseCacheLayerBenchmark.cs b/tests/CacheTower.Benchmarks/Providers/BaseCacheLayerBenchmark.cs index 1d138629..09067f78 100644 --- a/tests/CacheTower.Benchmarks/Providers/BaseCacheLayerBenchmark.cs +++ b/tests/CacheTower.Benchmarks/Providers/BaseCacheLayerBenchmark.cs @@ -68,12 +68,12 @@ public async Task GetHit() var cacheLayer = CacheLayerProvider.Invoke(); if (cacheLayer is ISyncCacheLayer syncCacheLayer) { - syncCacheLayer.Set("GetHit", new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + syncCacheLayer.Set("GetHit", new CacheEntry(1, TimeSpan.FromDays(1))); syncCacheLayer.Get("GetHit"); } else if (cacheLayer is IAsyncCacheLayer asyncLayer) { - await asyncLayer.SetAsync("GetHit", new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + await asyncLayer.SetAsync("GetHit", new CacheEntry(1, TimeSpan.FromDays(1))); await asyncLayer.GetAsync("GetHit"); } await DisposeOf(cacheLayer); @@ -85,11 +85,11 @@ public async Task SetNew() var cacheLayer = CacheLayerProvider.Invoke(); if (cacheLayer is ISyncCacheLayer syncCacheLayer) { - syncCacheLayer.Set("SetNew", new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + syncCacheLayer.Set("SetNew", new CacheEntry(1, TimeSpan.FromDays(1))); } else if (cacheLayer is IAsyncCacheLayer asyncLayer) { - await asyncLayer.SetAsync("SetNew", new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + await asyncLayer.SetAsync("SetNew", new CacheEntry(1, TimeSpan.FromDays(1))); } await DisposeOf(cacheLayer); } @@ -99,13 +99,13 @@ public async Task SetExisting() var cacheLayer = CacheLayerProvider.Invoke(); if (cacheLayer is ISyncCacheLayer syncCacheLayer) { - syncCacheLayer.Set("SetExisting", new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); - syncCacheLayer.Set("SetExisting", new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + syncCacheLayer.Set("SetExisting", new CacheEntry(1, TimeSpan.FromDays(1))); + syncCacheLayer.Set("SetExisting", new CacheEntry(1, TimeSpan.FromDays(1))); } else if (cacheLayer is IAsyncCacheLayer asyncLayer) { - await asyncLayer.SetAsync("SetExisting", new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); - await asyncLayer.SetAsync("SetExisting", new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + await asyncLayer.SetAsync("SetExisting", new CacheEntry(1, TimeSpan.FromDays(1))); + await asyncLayer.SetAsync("SetExisting", new CacheEntry(1, TimeSpan.FromDays(1))); } await DisposeOf(cacheLayer); } @@ -118,14 +118,14 @@ public async Task SetMany() { for (var i = 0; i < 100; i++) { - syncCacheLayer.Set("SetMany_" + i, new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + syncCacheLayer.Set("SetMany_" + i, new CacheEntry(1, TimeSpan.FromDays(1))); } } else if (cacheLayer is IAsyncCacheLayer asyncLayer) { for (var i = 0; i < 100; i++) { - await asyncLayer.SetAsync("SetMany_" + i, new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + await asyncLayer.SetAsync("SetMany_" + i, new CacheEntry(1, TimeSpan.FromDays(1))); } } await DisposeOf(cacheLayer); diff --git a/tests/CacheTower.Benchmarks/Providers/CacheLayerComparisonBenchmark.cs b/tests/CacheTower.Benchmarks/Providers/CacheLayerComparisonBenchmark.cs index 0ee39010..18efd605 100644 --- a/tests/CacheTower.Benchmarks/Providers/CacheLayerComparisonBenchmark.cs +++ b/tests/CacheTower.Benchmarks/Providers/CacheLayerComparisonBenchmark.cs @@ -45,7 +45,7 @@ private void BenchmarkWork(ISyncCacheLayer cacheLayer) //Set first 100 (simple type) for (var i = 0; i < 100; i++) { - cacheLayer.Set("Comparison_" + i, new CacheEntry(1, startDate.AddDays(i), TimeSpan.FromDays(1))); + cacheLayer.Set("Comparison_" + i, new CacheEntry(1, startDate.AddDays(i) + TimeSpan.FromDays(1))); } //Set last 100 (complex type) for (var i = 100; i < 200; i++) @@ -56,7 +56,7 @@ private void BenchmarkWork(ISyncCacheLayer cacheLayer) ExampleNumber = 42, ExampleDate = new DateTime(2000, 1, 1), DictionaryOfNumbers = new Dictionary() { { "A", 1 }, { "B", 2 }, { "C", 3 } } - }, startDate.AddDays(i - 100), TimeSpan.FromDays(1))); + }, startDate.AddDays(i - 100) + TimeSpan.FromDays(1))); } //Get first 50 (simple type) @@ -92,7 +92,7 @@ private async Task BenchmarkWork(IAsyncCacheLayer cacheLayer) //Set first 100 (simple type) for (var i = 0; i < 100; i++) { - await cacheLayer.SetAsync("Comparison_" + i, new CacheEntry(1, startDate.AddDays(i), TimeSpan.FromDays(1))); + await cacheLayer.SetAsync("Comparison_" + i, new CacheEntry(1, startDate.AddDays(i) + TimeSpan.FromDays(1))); } //Set last 100 (complex type) for (var i = 100; i < 200; i++) @@ -103,7 +103,7 @@ private async Task BenchmarkWork(IAsyncCacheLayer cacheLayer) ExampleNumber = 42, ExampleDate = new DateTime(2000, 1, 1), DictionaryOfNumbers = new Dictionary() { { "A", 1 }, { "B", 2 }, { "C", 3 } } - }, startDate.AddDays(i - 100), TimeSpan.FromDays(1))); + }, startDate.AddDays(i - 100) + TimeSpan.FromDays(1))); } //Get first 50 (simple type) diff --git a/tests/CacheTower.Benchmarks/RealCostOfCacheStackBenchmark.cs b/tests/CacheTower.Benchmarks/RealCostOfCacheStackBenchmark.cs index 78251d12..290d3659 100644 --- a/tests/CacheTower.Benchmarks/RealCostOfCacheStackBenchmark.cs +++ b/tests/CacheTower.Benchmarks/RealCostOfCacheStackBenchmark.cs @@ -36,7 +36,7 @@ public void MemoryCacheLayer_Independent() //Set first 100 (simple type) for (var i = 0; i < 100; i++) { - cacheLayer.Set("Comparison_" + i, new CacheEntry(1, startDate.AddDays(i), TimeSpan.FromDays(1))); + cacheLayer.Set("Comparison_" + i, new CacheEntry(1, startDate.AddDays(i) + TimeSpan.FromDays(1))); } //Set last 100 (complex type) for (var i = 100; i < 200; i++) @@ -47,7 +47,7 @@ public void MemoryCacheLayer_Independent() ExampleNumber = 42, ExampleDate = new DateTime(2000, 1, 1), DictionaryOfNumbers = new Dictionary() { { "A", 1 }, { "B", 2 }, { "C", 3 } } - }, startDate.AddDays(i - 100), TimeSpan.FromDays(1))); + }, startDate.AddDays(i - 100) + TimeSpan.FromDays(1))); } //Get first 50 (simple type) @@ -88,7 +88,7 @@ public async Task MemoryCacheLayer_CacheStack() //Set first 100 (simple type) for (var i = 0; i < 100; i++) { - await cacheStack.SetAsync("Comparison_" + i, new CacheEntry(1, startDate.AddDays(i), TimeSpan.FromDays(1))); + await cacheStack.SetAsync("Comparison_" + i, new CacheEntry(1, startDate.AddDays(i) + TimeSpan.FromDays(1))); } //Set last 100 (complex type) for (var i = 100; i < 200; i++) @@ -99,7 +99,7 @@ public async Task MemoryCacheLayer_CacheStack() ExampleNumber = 42, ExampleDate = new DateTime(2000, 1, 1), DictionaryOfNumbers = new Dictionary() { { "A", 1 }, { "B", 2 }, { "C", 3 } } - }, startDate.AddDays(i - 100), TimeSpan.FromDays(1))); + }, startDate.AddDays(i - 100) + TimeSpan.FromDays(1))); } //Get first 50 (simple type) @@ -135,7 +135,7 @@ public void MemoryCacheLayer_Indepedent_GetOrSet() var result = cacheLayer.Get("Comparison_" + i); if (result == null) { - cacheLayer.Set("Comparison_" + i, new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + cacheLayer.Set("Comparison_" + i, new CacheEntry(1, TimeSpan.FromDays(1))); } } @@ -151,7 +151,7 @@ public void MemoryCacheLayer_Indepedent_GetOrSet() ExampleNumber = 42, ExampleDate = new DateTime(2000, 1, 1), DictionaryOfNumbers = new Dictionary() { { "A", 1 }, { "B", 2 }, { "C", 3 } } - }, DateTime.UtcNow, TimeSpan.FromDays(1))); + }, TimeSpan.FromDays(1))); } } } diff --git a/tests/CacheTower.Tests/CacheEntryTests.cs b/tests/CacheTower.Tests/CacheEntryTests.cs index 1e9177e3..f688bb02 100644 --- a/tests/CacheTower.Tests/CacheEntryTests.cs +++ b/tests/CacheTower.Tests/CacheEntryTests.cs @@ -10,61 +10,43 @@ namespace CacheTower.Tests [TestClass] public class CacheEntryTests { - [TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))] - public void ThrowsExceptionOnNegativeTimeSpan() - { - new CacheEntry(0, DateTime.UtcNow, TimeSpan.FromSeconds(-1)); - } - [TestMethod] - public void HasElapsed_NoOffset() + public void GetStaleDate() { - var entryInPast = new CacheEntry(0, DateTime.UtcNow.AddDays(-1), TimeSpan.Zero); - Assert.IsTrue(entryInPast.HasElapsed(TimeSpan.Zero)); - - var entryInFuture = new CacheEntry(0, DateTime.UtcNow.AddDays(1), TimeSpan.Zero); - Assert.IsFalse(entryInFuture.HasElapsed(TimeSpan.Zero)); - } - - [TestMethod] - public void HasElapsed_WithOffset() - { - var entryInPast1 = new CacheEntry(0, DateTime.UtcNow.AddDays(-2), TimeSpan.FromDays(1)); - Assert.IsTrue(entryInPast1.HasElapsed(TimeSpan.FromDays(1))); - - var entryInPast2 = new CacheEntry(0, DateTime.UtcNow.AddDays(-2), TimeSpan.FromDays(1)); - Assert.IsFalse(entryInPast2.HasElapsed(TimeSpan.FromDays(3))); + var expiry = DateTime.UtcNow; + var entry = new CacheEntry(0, expiry); + Assert.IsTrue(expiry - entry.GetStaleDate(new CacheSettings(TimeSpan.FromDays(3))) < TimeSpan.FromSeconds(1)); + Assert.IsFalse(expiry - entry.GetStaleDate(new CacheSettings(TimeSpan.FromDays(3), TimeSpan.FromDays(2))) < TimeSpan.FromSeconds(1)); + Assert.IsTrue(expiry.AddDays(-1) - entry.GetStaleDate(new CacheSettings(TimeSpan.FromDays(3), TimeSpan.FromDays(2))) < TimeSpan.FromSeconds(1)); } [TestMethod] public void EqualityTests_AreEqual() { var utcNow = DateTime.UtcNow; - Assert.AreEqual(new CacheEntry(0, utcNow, TimeSpan.Zero), new CacheEntry(0, utcNow, TimeSpan.Zero)); - Assert.AreEqual(new CacheEntry(string.Empty, utcNow, TimeSpan.Zero), new CacheEntry(string.Empty, utcNow, TimeSpan.Zero)); + Assert.AreEqual(new CacheEntry(0, utcNow), new CacheEntry(0, utcNow)); + Assert.AreEqual(new CacheEntry(string.Empty, utcNow), new CacheEntry(string.Empty, utcNow)); } [TestMethod] public void EqualityTests_AreNotEqual() { var utcNow = DateTime.UtcNow; - Assert.AreNotEqual(new CacheEntry(0, utcNow, TimeSpan.Zero), new CacheEntry(0, utcNow, TimeSpan.FromSeconds(1))); - Assert.AreNotEqual(new CacheEntry(0, utcNow, TimeSpan.Zero), new CacheEntry(0, utcNow.AddDays(1), TimeSpan.Zero)); - Assert.AreNotEqual(new CacheEntry(0, utcNow, TimeSpan.Zero), new CacheEntry(1, utcNow, TimeSpan.Zero)); + Assert.AreNotEqual(new CacheEntry(0, utcNow), new CacheEntry(0, utcNow.AddSeconds(1))); + Assert.AreNotEqual(new CacheEntry(0, utcNow), new CacheEntry(1, utcNow)); - Assert.IsFalse(new CacheEntry(0, utcNow, TimeSpan.Zero).Equals(null)); - Assert.IsFalse(new CacheEntry(0, utcNow, TimeSpan.Zero).Equals(string.Empty)); + Assert.IsFalse(new CacheEntry(0, utcNow).Equals(null)); + Assert.IsFalse(new CacheEntry(0, utcNow).Equals(string.Empty)); } [TestMethod] public void EqualityTests_HashCode() { var utcNow = DateTime.UtcNow; - Assert.AreEqual(new CacheEntry(0, utcNow, TimeSpan.Zero).GetHashCode(), new CacheEntry(0, utcNow, TimeSpan.Zero).GetHashCode()); - Assert.AreEqual(new CacheEntry(string.Empty, utcNow, TimeSpan.Zero).GetHashCode(), new CacheEntry(string.Empty, utcNow, TimeSpan.Zero).GetHashCode()); - Assert.AreNotEqual(new CacheEntry(0, utcNow, TimeSpan.Zero).GetHashCode(), new CacheEntry(0, utcNow, TimeSpan.FromSeconds(1)).GetHashCode()); - Assert.AreNotEqual(new CacheEntry(0, utcNow, TimeSpan.Zero).GetHashCode(), new CacheEntry(0, utcNow.AddDays(1), TimeSpan.Zero).GetHashCode()); - Assert.AreNotEqual(new CacheEntry(0, utcNow, TimeSpan.Zero).GetHashCode(), new CacheEntry(1, utcNow, TimeSpan.Zero).GetHashCode()); + Assert.AreEqual(new CacheEntry(0, utcNow).GetHashCode(), new CacheEntry(0, utcNow).GetHashCode()); + Assert.AreEqual(new CacheEntry(string.Empty, utcNow).GetHashCode(), new CacheEntry(string.Empty, utcNow).GetHashCode()); + Assert.AreNotEqual(new CacheEntry(0, utcNow).GetHashCode(), new CacheEntry(0, utcNow.AddSeconds(1)).GetHashCode()); + Assert.AreNotEqual(new CacheEntry(0, utcNow).GetHashCode(), new CacheEntry(1, utcNow).GetHashCode()); } } } diff --git a/tests/CacheTower.Tests/CacheStackTests.cs b/tests/CacheTower.Tests/CacheStackTests.cs index 3364f079..50546b90 100644 --- a/tests/CacheTower.Tests/CacheStackTests.cs +++ b/tests/CacheTower.Tests/CacheStackTests.cs @@ -36,7 +36,7 @@ public async Task Cleanup_CleansAllTheLayers() var cacheStack = new CacheStack(null, new[] { layer1, layer2 }, Array.Empty()); - var cacheEntry = new CacheEntry(42, DateTime.UtcNow.AddDays(-2), TimeSpan.FromDays(1)); + var cacheEntry = new CacheEntry(42, DateTime.UtcNow.AddDays(-1)); await cacheStack.SetAsync("Cleanup_CleansAllTheLayers", cacheEntry); Assert.AreEqual(cacheEntry, layer1.Get("Cleanup_CleansAllTheLayers")); @@ -49,6 +49,14 @@ public async Task Cleanup_CleansAllTheLayers() await DisposeOf(cacheStack); } + [TestMethod, ExpectedException(typeof(ObjectDisposedException))] + public async Task Cleanup_ThrowsOnUseAfterDisposal() + { + var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, null); + await DisposeOf(cacheStack); + + await cacheStack.CleanupAsync(); + } [TestMethod, ExpectedException(typeof(ArgumentNullException))] public async Task Evict_ThrowsOnNullKey() @@ -56,7 +64,6 @@ public async Task Evict_ThrowsOnNullKey() var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, Array.Empty()); await cacheStack.EvictAsync(null); } - [TestMethod] public async Task Evict_EvictsAllTheLayers() { @@ -76,6 +83,14 @@ public async Task Evict_EvictsAllTheLayers() await DisposeOf(cacheStack); } + [TestMethod, ExpectedException(typeof(ObjectDisposedException))] + public async Task Evict_ThrowsOnUseAfterDisposal() + { + var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, null); + await DisposeOf(cacheStack); + + await cacheStack.EvictAsync("KeyDoesntMatter"); + } [TestMethod, ExpectedException(typeof(ArgumentNullException))] public async Task Get_ThrowsOnNullKey() @@ -83,12 +98,20 @@ public async Task Get_ThrowsOnNullKey() var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, Array.Empty()); await cacheStack.GetAsync(null); } + [TestMethod, ExpectedException(typeof(ObjectDisposedException))] + public async Task Get_ThrowsOnUseAfterDisposal() + { + var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, null); + await DisposeOf(cacheStack); + + await cacheStack.GetAsync("KeyDoesntMatter"); + } [TestMethod, ExpectedException(typeof(ArgumentNullException))] public async Task Set_ThrowsOnNullKey() { var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, Array.Empty()); - await cacheStack.SetAsync(null, new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + await cacheStack.SetAsync(null, new CacheEntry(1, TimeSpan.FromDays(1))); } [TestMethod, ExpectedException(typeof(ArgumentNullException))] @@ -97,7 +120,22 @@ public async Task Set_ThrowsOnNullCacheEntry() var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, Array.Empty()); await cacheStack.SetAsync("MyCacheKey", (CacheEntry)null); } + [TestMethod, ExpectedException(typeof(ObjectDisposedException))] + public async Task Set_ThrowsOnUseAfterDisposal() + { + var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, null); + await DisposeOf(cacheStack); + + await cacheStack.SetAsync("KeyDoesntMatter", 1, TimeSpan.FromDays(1)); + } + [TestMethod, ExpectedException(typeof(ObjectDisposedException))] + public async Task Set_ThrowsOnUseAfterDisposal_CacheEntry() + { + var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, null); + await DisposeOf(cacheStack); + await cacheStack.SetAsync("KeyDoesntMatter", new CacheEntry(1, TimeSpan.FromDays(1))); + } [TestMethod] public async Task Set_SetsAllTheLayers() { @@ -119,14 +157,12 @@ public async Task GetOrSet_ThrowsOnNullKey() var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, Array.Empty()); await cacheStack.GetOrSetAsync(null, (old, context) => Task.FromResult(5), new CacheSettings(TimeSpan.FromDays(1))); } - [TestMethod, ExpectedException(typeof(ArgumentNullException))] public async Task GetOrSet_ThrowsOnNullGetter() { var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, Array.Empty()); await cacheStack.GetOrSetAsync("MyCacheKey", null, new CacheSettings(TimeSpan.FromDays(1))); } - [TestMethod] public async Task GetOrSet_CacheMiss() { @@ -140,7 +176,6 @@ public async Task GetOrSet_CacheMiss() await DisposeOf(cacheStack); } - [TestMethod] public async Task GetOrSet_CacheHit() { @@ -156,12 +191,11 @@ public async Task GetOrSet_CacheHit() await DisposeOf(cacheStack); } - [TestMethod] public async Task GetOrSet_CacheHitBackgroundRefresh() { var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, Array.Empty()); - var cacheEntry = new CacheEntry(17, DateTime.UtcNow.AddDays(-1), TimeSpan.FromDays(2)); + var cacheEntry = new CacheEntry(17, DateTime.UtcNow.AddDays(1)); await cacheStack.SetAsync("GetOrSet_CacheHitBackgroundRefresh", cacheEntry); var waitingOnBackgroundTask = new TaskCompletionSource(); @@ -182,7 +216,6 @@ public async Task GetOrSet_CacheHitBackgroundRefresh() await DisposeOf(cacheStack); } - [TestMethod] public async Task GetOrSet_BackPropagatesToEarlierCacheLayers() { @@ -191,7 +224,7 @@ public async Task GetOrSet_BackPropagatesToEarlierCacheLayers() var layer3 = new MemoryCacheLayer(); var cacheStack = new CacheStack(null, new[] { layer1, layer2, layer3 }, Array.Empty()); - var cacheEntry = new CacheEntry(42, DateTime.UtcNow, TimeSpan.FromDays(1)); + var cacheEntry = new CacheEntry(42, TimeSpan.FromDays(1)); layer2.Set("GetOrSet_BackPropagatesToEarlierCacheLayers", cacheEntry); var cacheEntryFromStack = await cacheStack.GetOrSetAsync("GetOrSet_BackPropagatesToEarlierCacheLayers", (old, context) => @@ -209,12 +242,11 @@ public async Task GetOrSet_BackPropagatesToEarlierCacheLayers() await DisposeOf(cacheStack); } - [TestMethod] public async Task GetOrSet_CacheHitButAllowedStalePoint() { var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, Array.Empty()); - var cacheEntry = new CacheEntry(17, DateTime.UtcNow.AddDays(-2), TimeSpan.FromDays(1)); + var cacheEntry = new CacheEntry(17, DateTime.UtcNow.AddDays(-1)); await cacheStack.SetAsync("GetOrSet_CacheHitButAllowedStalePoint", cacheEntry); var result = await cacheStack.GetOrSetAsync("GetOrSet_CacheHitButAllowedStalePoint", (oldValue, context) => @@ -225,12 +257,11 @@ public async Task GetOrSet_CacheHitButAllowedStalePoint() await DisposeOf(cacheStack); } - [TestMethod] public async Task GetOrSet_ConcurrentStaleCacheHits() { var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, Array.Empty()); - var cacheEntry = new CacheEntry(23, DateTime.UtcNow.AddDays(-3), TimeSpan.FromDays(1)); + var cacheEntry = new CacheEntry(23, DateTime.UtcNow.AddDays(-2)); await cacheStack.SetAsync("GetOrSet_ConcurrentStaleCacheHits", cacheEntry); ValueTask DoRequest() @@ -258,5 +289,13 @@ ValueTask DoRequest() await DisposeOf(cacheStack); } + [TestMethod, ExpectedException(typeof(ObjectDisposedException))] + public async Task GetOrSet_ThrowsOnUseAfterDisposal() + { + var cacheStack = new CacheStack(null, new[] { new MemoryCacheLayer() }, null); + await DisposeOf(cacheStack); + + await cacheStack.GetOrSetAsync("KeyDoesntMatter", (old, context) => Task.FromResult(1), new CacheSettings(TimeSpan.FromDays(1))); + } } } diff --git a/tests/CacheTower.Tests/Extensions/ExtensionContainerTests.cs b/tests/CacheTower.Tests/Extensions/ExtensionContainerTests.cs index cf758774..c153fdda 100644 --- a/tests/CacheTower.Tests/Extensions/ExtensionContainerTests.cs +++ b/tests/CacheTower.Tests/Extensions/ExtensionContainerTests.cs @@ -35,7 +35,7 @@ public async Task RefreshWrapperExtension() container.Register(cacheStackMock.Object); - var cacheEntry = new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1)); + var cacheEntry = new CacheEntry(1, TimeSpan.FromDays(1)); var refreshedValue = await container.RefreshValueAsync("WrapperTestCacheKey", () => { diff --git a/tests/CacheTower.Tests/Extensions/Redis/RedisLockExtensionTests.cs b/tests/CacheTower.Tests/Extensions/Redis/RedisLockExtensionTests.cs index 3c6b9f66..46400c54 100644 --- a/tests/CacheTower.Tests/Extensions/Redis/RedisLockExtensionTests.cs +++ b/tests/CacheTower.Tests/Extensions/Redis/RedisLockExtensionTests.cs @@ -52,7 +52,7 @@ public async Task CustomLockTimeout() { lockWaiterTask.SetResult(true); await refreshWaiterTask.Task; - return new CacheEntry(5, DateTime.UtcNow, TimeSpan.FromDays(1)); + return new CacheEntry(5, TimeSpan.FromDays(1)); }, new CacheSettings(TimeSpan.FromHours(3))); await lockWaiterTask.Task; @@ -95,7 +95,7 @@ await connection.GetSubscriber().SubscribeAsync("CacheTower.CacheLock", (channel var extension = new RedisLockExtension(connection); extension.Register(cacheStackMock.Object); - var cacheEntry = new CacheEntry(13, DateTime.UtcNow, TimeSpan.FromDays(1)); + var cacheEntry = new CacheEntry(13, TimeSpan.FromDays(1)); await extension.RefreshValueAsync("TestKey", () => new ValueTask>(cacheEntry), new CacheSettings(TimeSpan.FromDays(1))); @@ -121,7 +121,7 @@ public async Task WaitingTaskInSameInstanceUnlocksAndCompletes() var extension = new RedisLockExtension(connection); extension.Register(cacheStackMock.Object); - var cacheEntry = new CacheEntry(13, DateTime.UtcNow, TimeSpan.FromDays(1)); + var cacheEntry = new CacheEntry(13, TimeSpan.FromDays(1)); var secondaryTaskKickoff = new TaskCompletionSource(); var primaryTask = extension.RefreshValueAsync("TestKey", @@ -167,7 +167,7 @@ public async Task WaitingTaskInDifferentInstanceUnlocksAndCompletes() var extensionTwo = new RedisLockExtension(connection); extensionTwo.Register(cacheStackMockTwo.Object); - var cacheEntry = new CacheEntry(13, DateTime.UtcNow, TimeSpan.FromDays(1)); + var cacheEntry = new CacheEntry(13, TimeSpan.FromDays(1)); var secondaryTaskKickoff = new TaskCompletionSource(); var primaryTask = extensionOne.RefreshValueAsync("TestKey", diff --git a/tests/CacheTower.Tests/Providers/BaseCacheLayerTests.cs b/tests/CacheTower.Tests/Providers/BaseCacheLayerTests.cs index 8b3a42de..5730ce7c 100644 --- a/tests/CacheTower.Tests/Providers/BaseCacheLayerTests.cs +++ b/tests/CacheTower.Tests/Providers/BaseCacheLayerTests.cs @@ -13,7 +13,7 @@ public abstract class BaseCacheLayerTests : TestBase { protected static void AssertGetSetCache(ISyncCacheLayer cacheLayer) { - var cacheEntry = new CacheEntry(12, DateTime.UtcNow, TimeSpan.FromDays(1)); + var cacheEntry = new CacheEntry(12, TimeSpan.FromDays(1)); cacheLayer.Set("AssertGetSetCache", cacheEntry); var cacheEntryGet = cacheLayer.Get("AssertGetSetCache"); @@ -21,7 +21,7 @@ protected static void AssertGetSetCache(ISyncCacheLayer cacheLayer) } protected static async Task AssertGetSetCacheAsync(IAsyncCacheLayer cacheLayer) { - var cacheEntry = new CacheEntry(12, DateTime.UtcNow, TimeSpan.FromDays(1)); + var cacheEntry = new CacheEntry(12, TimeSpan.FromDays(1)); await cacheLayer.SetAsync("AssertGetSetCache", cacheEntry); var cacheEntryGet = await cacheLayer.GetAsync("AssertGetSetCache"); @@ -39,7 +39,7 @@ protected static async Task AssertCacheAvailabilityAsync(IAsyncCacheLayer cacheL protected static void AssertCacheEviction(ISyncCacheLayer cacheLayer) { - var cacheEntry = new CacheEntry(77, DateTime.UtcNow, TimeSpan.FromDays(1)); + var cacheEntry = new CacheEntry(77, TimeSpan.FromDays(1)); cacheLayer.Set("AssertCacheEviction-ToEvict", cacheEntry); cacheLayer.Set("AssertCacheEviction-ToKeep", cacheEntry); @@ -57,7 +57,7 @@ protected static void AssertCacheEviction(ISyncCacheLayer cacheLayer) } protected static async Task AssertCacheEvictionAsync(IAsyncCacheLayer cacheLayer) { - var cacheEntry = new CacheEntry(77, DateTime.UtcNow, TimeSpan.FromDays(1)); + var cacheEntry = new CacheEntry(77, TimeSpan.FromDays(1)); await cacheLayer.SetAsync("AssertCacheEviction-ToEvict", cacheEntry); await cacheLayer.SetAsync("AssertCacheEviction-ToKeep", cacheEntry); @@ -80,7 +80,7 @@ CacheEntry DoCleanupTest(DateTime dateTime) { var cacheKey = $"AssertCacheCleanup-(DateTime:{dateTime})"; - var cacheEntry = new CacheEntry(98, dateTime, TimeSpan.FromDays(1)); + var cacheEntry = new CacheEntry(98, dateTime); cacheLayer.Set(cacheKey, cacheEntry); cacheLayer.Cleanup(); @@ -88,8 +88,8 @@ CacheEntry DoCleanupTest(DateTime dateTime) return cacheLayer.Get(cacheKey); } - Assert.IsNotNull(DoCleanupTest(DateTime.UtcNow), "Cleanup removed entry that was still live"); - Assert.IsNull(DoCleanupTest(DateTime.UtcNow.AddDays(-2)), "Cleanup kept entry past the end of life"); + Assert.IsNotNull(DoCleanupTest(DateTime.UtcNow.AddDays(1)), "Cleanup removed entry that was still live"); + Assert.IsNull(DoCleanupTest(DateTime.UtcNow.AddDays(-1)), "Cleanup kept entry past the end of life"); } protected static async Task AssertCacheCleanupAsync(IAsyncCacheLayer cacheLayer) { @@ -97,7 +97,7 @@ async Task> DoCleanupTest(DateTime dateTime) { var cacheKey = $"AssertCacheCleanup-(DateTime:{dateTime})"; - var cacheEntry = new CacheEntry(98, dateTime, TimeSpan.FromDays(1)); + var cacheEntry = new CacheEntry(98, dateTime); await cacheLayer.SetAsync(cacheKey, cacheEntry); await cacheLayer.CleanupAsync(); @@ -105,8 +105,8 @@ async Task> DoCleanupTest(DateTime dateTime) return await cacheLayer.GetAsync(cacheKey); } - Assert.IsNotNull(await DoCleanupTest(DateTime.UtcNow), "Cleanup removed entry that was still live"); - Assert.IsNull(await DoCleanupTest(DateTime.UtcNow.AddDays(-2)), "Cleanup kept entry past the end of life"); + Assert.IsNotNull(await DoCleanupTest(DateTime.UtcNow.AddDays(1)), "Cleanup removed entry that was still live"); + Assert.IsNull(await DoCleanupTest(DateTime.UtcNow.AddDays(-1)), "Cleanup kept entry past the end of life"); } protected static void AssertComplexTypeCaching(ISyncCacheLayer cacheLayer) @@ -116,7 +116,7 @@ protected static void AssertComplexTypeCaching(ISyncCacheLayer cacheLayer) ExampleString = "Hello World", ExampleNumber = 99, ListOfNumbers = new List() { 1, 2, 4, 8 } - }, DateTime.UtcNow, TimeSpan.FromDays(1)); + }, TimeSpan.FromDays(1)); cacheLayer.Set("ComplexTypeOne", complexTypeOneEntry); var complexTypeOneEntryGet = cacheLayer.Get("ComplexTypeOne"); @@ -127,7 +127,7 @@ protected static void AssertComplexTypeCaching(ISyncCacheLayer cacheLayer) ExampleString = "Hello World", ArrayOfObjects = new[] { complexTypeOneEntry.Value }, DictionaryOfNumbers = new Dictionary() { { "A", 1 }, { "Z", 26 } } - }, DateTime.UtcNow, TimeSpan.FromDays(1)); + }, TimeSpan.FromDays(1)); cacheLayer.Set("ComplexTypeTwo", complexTypeTwoEntry); var complexTypeTwoEntryGet = cacheLayer.Get("ComplexTypeTwo"); @@ -140,7 +140,7 @@ protected static async Task AssertComplexTypeCachingAsync(IAsyncCacheLayer cache ExampleString = "Hello World", ExampleNumber = 99, ListOfNumbers = new List() { 1, 2, 4, 8 } - }, DateTime.UtcNow, TimeSpan.FromDays(1)); + }, TimeSpan.FromDays(1)); await cacheLayer.SetAsync("ComplexTypeOne", complexTypeOneEntry); var complexTypeOneEntryGet = await cacheLayer.GetAsync("ComplexTypeOne"); @@ -151,7 +151,7 @@ protected static async Task AssertComplexTypeCachingAsync(IAsyncCacheLayer cache ExampleString = "Hello World", ArrayOfObjects = new[] { complexTypeOneEntry.Value }, DictionaryOfNumbers = new Dictionary() { { "A", 1 }, { "Z", 26 } } - }, DateTime.UtcNow, TimeSpan.FromDays(1)); + }, TimeSpan.FromDays(1)); await cacheLayer.SetAsync("ComplexTypeTwo", complexTypeTwoEntry); var complexTypeTwoEntryGet = await cacheLayer.GetAsync("ComplexTypeTwo"); diff --git a/tests/CacheTower.Tests/Providers/Database/MongoDB/MongoDbCacheLayerTests.cs b/tests/CacheTower.Tests/Providers/Database/MongoDB/MongoDbCacheLayerTests.cs index 3b40f2c4..1af58a7e 100644 --- a/tests/CacheTower.Tests/Providers/Database/MongoDB/MongoDbCacheLayerTests.cs +++ b/tests/CacheTower.Tests/Providers/Database/MongoDB/MongoDbCacheLayerTests.cs @@ -8,6 +8,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using MongoDB.Driver; using MongoFramework; +using Moq; namespace CacheTower.Tests.Providers.Database.MongoDB { @@ -36,6 +37,11 @@ public async Task GetSetCache() public async Task IsCacheAvailable() { await AssertCacheAvailabilityAsync(new MongoDbCacheLayer(MongoDbHelper.GetConnection()), true); + + var connectionMock = new Mock(); + connectionMock.Setup(c => c.GetDatabase()).Throws(); + + await AssertCacheAvailabilityAsync(new MongoDbCacheLayer(connectionMock.Object), false); } [TestMethod] diff --git a/tests/CacheTower.Tests/Providers/FileSystem/FileCacheLayerBaseTests.cs b/tests/CacheTower.Tests/Providers/FileSystem/FileCacheLayerBaseTests.cs index 0881359f..7568f27a 100644 --- a/tests/CacheTower.Tests/Providers/FileSystem/FileCacheLayerBaseTests.cs +++ b/tests/CacheTower.Tests/Providers/FileSystem/FileCacheLayerBaseTests.cs @@ -77,7 +77,7 @@ private string GetMD5String(string text) public async Task NoFileExtension() { var cacheLayer = new TestFileCacheLayer(DirectoryPath, null); - await cacheLayer.SetAsync("NoFileExtension", new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + await cacheLayer.SetAsync("NoFileExtension", new CacheEntry(1, TimeSpan.FromDays(1))); await DisposeOf(cacheLayer); var md5String = GetMD5String("NoFileExtension"); @@ -88,7 +88,7 @@ public async Task NoFileExtension() public async Task CustomFileExtension() { var cacheLayer = new TestFileCacheLayer(DirectoryPath, ".mycustomfileextension"); - await cacheLayer.SetAsync("CustomFileExtension", new CacheEntry(1, DateTime.UtcNow, TimeSpan.FromDays(1))); + await cacheLayer.SetAsync("CustomFileExtension", new CacheEntry(1, TimeSpan.FromDays(1))); await DisposeOf(cacheLayer); var md5String = GetMD5String("CustomFileExtension"); diff --git a/tests/CacheTower.Tests/Providers/Redis/RedisCacheLayerTests.cs b/tests/CacheTower.Tests/Providers/Redis/RedisCacheLayerTests.cs index 07b7181c..d8371692 100644 --- a/tests/CacheTower.Tests/Providers/Redis/RedisCacheLayerTests.cs +++ b/tests/CacheTower.Tests/Providers/Redis/RedisCacheLayerTests.cs @@ -6,6 +6,7 @@ using CacheTower.Providers.Redis; using CacheTower.Tests.Utils; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; using StackExchange.Redis; namespace CacheTower.Tests.Providers.Redis @@ -29,6 +30,13 @@ public async Task GetSetCache() public async Task IsCacheAvailable() { await AssertCacheAvailabilityAsync(new RedisCacheLayer(RedisHelper.GetConnection()), true); + + var connectionMock = new Mock(); + var databaseMock = new Mock(); + connectionMock.Setup(cm => cm.GetDatabase(It.IsAny(), It.IsAny())).Returns(databaseMock.Object); + databaseMock.Setup(db => db.PingAsync(It.IsAny())).Throws(); + + await AssertCacheAvailabilityAsync(new RedisCacheLayer(connectionMock.Object), false); } [TestMethod]