diff --git a/Benchmarks.md b/Benchmarks.md index a7321c58..1a41ae32 100644 --- a/Benchmarks.md +++ b/Benchmarks.md @@ -10,15 +10,13 @@ All CacheManager instances used in the benchmarks have only one cache handle con We are using the same configuration for all benchmarks and running two jobs each, one for x86 and one for x64. Regarding the different platforms, the conclusion is obviously that x64 is always faster than the x86 platform, but x64 consumes slightly more memory of course. ```ini -BenchmarkDotNet=v0.9.1.0 -OS=Microsoft Windows NT 6.2.9200.0 -Processor=Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz, ProcessorCount=8 -Frequency=3328117 ticks, Resolution=300.4702 ns -HostCLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE - -Type=PutWithRegionSingleBenchmark Mode=Throughput Platform=X64 -Jit=RyuJit LaunchCount=1 WarmupCount=2 -TargetCount=100 +BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.3194) +12th Gen Intel Core i7-12700KF, 1 CPU, 20 logical and 12 physical cores +.NET SDK 9.0.200 + [Host] : .NET 8.0.13 (8.0.1325.6609), X64 RyuJIT AVX2 + Job-BIBDFC : .NET 8.0.13 (8.0.1325.6609), X64 RyuJIT AVX2 + +IterationCount=10 LaunchCount=1 WarmupCount=2 ``` ### Add @@ -27,73 +25,47 @@ TargetCount=100 Redis will be a lot slower in this scenario because CacheManager waits for the response to be able to return the `bool` value if the key has been added or not. In general, it is good to see how fast the Dictionary handle is compared to the `System.Runtime` one. One thing you cannot see here is that also the memory footprint of the Dictionary handle is much lower. -Method | Platform | Median | StdDev | Scaled | ------------: |:-----------: |-----------: |----------: |-------: | -Dictionary | X64 | 1.7254 us | 0.0511 us | 1.00 | -Dictionary | X86 | 1.9563 us | 0.0399 us | 1.00 | -Runtime | X64 | 4.9839 us | 0.0778 us | 2.89 | -Runtime | X86 | 7.0324 us | 0.2012 us | 3.59 | -Redis | X64 | 56.6671 us | 1.7202 us | 32.84 | -Redis | X86 | 58.0775 us | 0.9517 us | 29.69 | + +| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Allocated | Alloc Ratio | +|----------- |-------------:|------------:|------------:|-------:|--------:|-------:|-------:|----------:|------------:| +| Dictionary | 121.0 ns | 2.00 ns | 1.04 ns | 1.00 | 0.01 | 0.0153 | - | 200 B | 1.00 | +| Runtime | 637.2 ns | 28.46 ns | 16.94 ns | 5.27 | 0.14 | 0.2384 | 0.0010 | 3120 B | 15.60 | +| MsMemory | 198.8 ns | 4.59 ns | 3.04 ns | 1.64 | 0.03 | 0.0260 | - | 340 B | 1.70 | +| Redis | 105,395.6 ns | 3,758.09 ns | 2,485.74 ns | 871.20 | 20.86 | - | - | 1256 B | 6.28 | *Adding one item per run with using region* -Method | Platform | Median | StdDev | Scaled | ------------: |:-----------: |-----------: |----------: |-------: | -Dictionary | X64 | 1.8094 us | 0.0386 us | 1.00 | -Dictionary | X86 | 2.5029 us | 0.1179 us | 1.00 | -Runtime | X64 | 6.6934 us | 0.1275 us | 3.70 | -Runtime | X86 | 9.2334 us | 0.1637 us | 3.69 | -Redis | X64 | 58.5355 us | 1.7054 us | 32.35 | -Redis | X86 | 61.0272 us | 1.4178 us | 24.38 | +| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio | +|----------- |-------------:|------------:|------------:|-------:|--------:|-------:|----------:|------------:| +| Dictionary | 144.2 ns | 4.65 ns | 3.07 ns | 1.00 | 0.03 | 0.0231 | 304 B | 1.00 | +| Runtime | 342.6 ns | 18.01 ns | 11.91 ns | 2.38 | 0.09 | 0.0610 | 800 B | 2.63 | +| MsMemory | 164.1 ns | 5.74 ns | 3.80 ns | 1.14 | 0.03 | 0.0231 | 304 B | 1.00 | +| Redis | 139,200.0 ns | 4,863.92 ns | 2,894.44 ns | 966.01 | 27.25 | - | 1528 B | 5.03 | + ### Put *Put 1 item per run* Redis is as fast as the other handles in this scenario because CacheManager uses fire and forget for those operations. For Put it doesn't matter to know if the item has been added or updated... -Method | Platform | Median | StdDev | Scaled | ------------: |:-----------: |-----------: |----------: |-------: | -Dictionary | X64 | 1.6802 us | 0.0235 us | 1.00 | -Dictionary | X86 | 1.9445 us | 0.0341 us | 1.00 | -Runtime | X64 | 4.4431 us | 0.0651 us | 2.64 | -Runtime | X86 | 6.5231 us | 0.1063 us | 3.35 | -Redis | X64 | 2.6869 us | 0.0934 us | 1.60 | -Redis | X86 | 3.5490 us | 0.0848 us | 1.83 | - -*Put 1 item per run with region* - -Method | Platform | Median | StdDev | Scaled | ------------: |:-----------: |-----------: |----------: |-------: | -Dictionary | X64 | 1.7401 us | 0.0365 us | 1.00 | -Dictionary | X86 | 2.4589 us | 0.1022 us | 1.00 | -Runtime | X64 | 6.1772 us | 0.3683 us | 3.55 | -Runtime | X86 | 9.9298 us | 0.5574 us | 4.04 | -Redis | X64 | 3.0807 us | 0.0906 us | 1.77 | -Redis | X86 | 3.6385 us | 0.2123 us | 1.48 | +| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Allocated | Alloc Ratio | +|----------- |------------:|-----------:|-----------:|------:|--------:|-------:|-------:|----------:|------------:| +| Dictionary | 95.01 ns | 1.888 ns | 1.249 ns | 1.00 | 0.02 | 0.0122 | - | 160 B | 1.00 | +| Runtime | 887.35 ns | 19.929 ns | 13.181 ns | 9.34 | 0.18 | 0.4263 | 0.0095 | 5576 B | 34.85 | +| MsMemory | 172.40 ns | 5.030 ns | 3.327 ns | 1.81 | 0.04 | 0.0336 | - | 440 B | 2.75 | +| Redis | 4,136.37 ns | 301.420 ns | 199.371 ns | 43.54 | 2.07 | 0.0839 | 0.0610 | 1095 B | 6.84 | + ### Get *Get 1 item per run* With `Get` operations we can clearly see how much faster an in-memory cache is, compared to the distributed variant. That's why it makes so much sense to use CacheManager with a first and secondary cache layer. -Method | Platform | Median | StdDev | Scaled | ------------: |:-----------: |-----------: |----------: |-------: | -Dictionary | X64 | 169.8708 ns | 4.6186 ns | 1.00 | -Dictionary | X86 | 540.0879 ns | 8.9363 ns | 1.00 | -Runtime | X64 | 310.4025 ns | 8.2928 ns | 1.83 | -Runtime | X86 | 1,030.5911 ns | 8.0532 ns | 1.91 | -Redis | X64 | 56,917.3537 ns | 2,035.4765 ns | 335.06 | -Redis | X86 | 59,519.5459 ns | 1,527.9613 ns | 110.20 | - -*Get 1 item per run with region* -Method | Platform | Median | StdDev | Scaled | ------------: |:-----------: |-----------: |----------: |-------: | -Dictionary | X64 | 234.9676 ns | 7.9172 ns | 1.00 | -Dictionary | X86 | 600.0429 ns | 13.7090 ns | 1.00 | -Runtime | X64 | 497.4116 ns | 15.6998 ns | 2.12 | -Runtime | X86 | 1,191.6452 ns | 19.8484 ns | 1.99 | -Redis | X64 | 57,257.9868 ns | 1,705.0148 ns | 243.68 | -Redis | X86 | 61,789.3944 ns | 1,775.6064 ns | 102.97 | +| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio | +|----------- |-------------:|-------------:|-------------:|---------:|--------:|-------:|----------:|------------:| +| Dictionary | 34.97 ns | 0.532 ns | 0.317 ns | 1.00 | 0.01 | - | - | NA | +| Runtime | 179.45 ns | 2.104 ns | 1.392 ns | 5.13 | 0.06 | 0.0153 | 200 B | NA | +| MsMemory | 75.12 ns | 0.338 ns | 0.201 ns | 2.15 | 0.02 | - | - | NA | +| Redis | 75,534.71 ns | 5,303.351 ns | 3,507.838 ns | 2,160.12 | 97.47 | 0.1221 | 2008 B | NA | ### Serializer comparison @@ -149,12 +121,14 @@ Pretty simple but large enough to analyze the performance. **Results:** -Method | Platform | Median | StdDev | Scaled | Scaled-SD | ------: |:-------: |-----------: |----------: |-------: |-------: | -BinarySerializer | X64 | 62.4158 ms | 1.8668 ms | 2.20 | 0.07 | -JsonSerializer | X64 | 28.5521 ms | 0.4633 ms | 1.00 | 0.00 | -JsonGzSerializer | X64 | 102.5552 ms | 4.8584 ms | 3.60 | 0.18 | -ProtoBufSerializer | X64 | 11.1276 ms | 0.1252 ms | 0.39 | 0.01 | +| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Allocated | Alloc Ratio | +|------------------------- |----------:|---------:|---------:|------:|--------:|--------:|-------:|----------:|------------:| +| JsonSerializer | 83.21 us | 1.163 us | 0.769 us | 1.00 | 0.01 | 14.8926 | 2.4414 | 191.16 KB | 1.00 | +| JsonGzSerializer | 346.37 us | 4.785 us | 3.165 us | 4.16 | 0.05 | 21.9727 | 2.9297 | 280.75 KB | 1.47 | +| ProtoBufSerializer | 39.18 us | 0.701 us | 0.463 us | 0.47 | 0.01 | 8.6060 | 1.0986 | 110.7 KB | 0.58 | +| BondBinarySerializer | 19.03 us | 0.398 us | 0.263 us | 0.23 | 0.00 | 4.7302 | 0.6714 | 60.53 KB | 0.32 | +| BondFastBinarySerializer | 19.42 us | 0.431 us | 0.285 us | 0.23 | 0.00 | 4.7607 | 0.7324 | 60.84 KB | 0.32 | +| BondSimpleJsonSerializer | 63.56 us | 1.132 us | 0.748 us | 0.76 | 0.01 | 11.9629 | 1.9531 | 153.35 KB | 0.80 | As expected the protobuf serialization outperforms everything else by a huge margin! diff --git a/benchmarks/CacheManager.Benchmarks/CacheManager.Benchmarks.csproj b/benchmarks/CacheManager.Benchmarks/CacheManager.Benchmarks.csproj index dfcff79b..2fb0efd3 100644 --- a/benchmarks/CacheManager.Benchmarks/CacheManager.Benchmarks.csproj +++ b/benchmarks/CacheManager.Benchmarks/CacheManager.Benchmarks.csproj @@ -19,6 +19,7 @@ + true diff --git a/benchmarks/CacheManager.Benchmarks/Program.cs b/benchmarks/CacheManager.Benchmarks/Program.cs index 4076da50..c0f3a11f 100644 --- a/benchmarks/CacheManager.Benchmarks/Program.cs +++ b/benchmarks/CacheManager.Benchmarks/Program.cs @@ -1,33 +1,53 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Net; using System.Reflection; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Jobs; using BenchmarkDotNet.Running; +using Garnet; +using Garnet.server; +using Microsoft.Extensions.Logging; -namespace CacheManager.Benchmarks +namespace CacheManager.Benchmarks; + +[ExcludeFromCodeCoverage] +public class Program { - [ExcludeFromCodeCoverage] - public class Program + public static GarnetServer StartServer(ILoggerFactory loggerFactory = null) + { + var server = new GarnetServer(new GarnetServerOptions() + { + EnableLua = true, + LuaOptions = new LuaOptions(LuaMemoryManagementMode.Native, string.Empty, TimeSpan.FromSeconds(5)), + EndPoint = new IPEndPoint(IPAddress.Loopback, 6379) + }, + loggerFactory: loggerFactory); + + server.Start(); + + return server; + } + + public static void Main(string[] args) { - public static void Main(string[] args) + StartServer(); + + do { - do - { - var config = ManualConfig.CreateMinimumViable() - .AddJob(Job.Default - .WithIterationCount(10) - .WithWarmupCount(2) - .WithLaunchCount(1)) - .AddDiagnoser(BenchmarkDotNet.Diagnosers.MemoryDiagnoser.Default); - - BenchmarkSwitcher - .FromAssembly(typeof(Program).GetTypeInfo().Assembly) - .Run(args, config); - - Console.WriteLine("done!"); - Console.WriteLine("Press escape to exit or any key to continue..."); - } while (Console.ReadKey().Key != ConsoleKey.Escape); - } + var config = ManualConfig.CreateMinimumViable() + .AddJob(Job.Default + .WithIterationCount(10) + .WithWarmupCount(2) + .WithLaunchCount(1)) + .AddDiagnoser(BenchmarkDotNet.Diagnosers.MemoryDiagnoser.Default); + + BenchmarkSwitcher + .FromAssembly(typeof(Program).GetTypeInfo().Assembly) + .Run(args, config); + + Console.WriteLine("done!"); + Console.WriteLine("Press escape to exit or any key to continue..."); + } while (Console.ReadKey().Key != ConsoleKey.Escape); } } diff --git a/samples/OutputCacheExample/App_Start/BundleConfig.cs b/samples/OutputCacheExample/App_Start/BundleConfig.cs deleted file mode 100644 index f96a9e99..00000000 --- a/samples/OutputCacheExample/App_Start/BundleConfig.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Web.Optimization; - -namespace OutputCacheExample -{ - public class BundleConfig - { - // For more information on bundling, visit https://go.microsoft.com/fwlink/?LinkId=301862 - public static void RegisterBundles(BundleCollection bundles) - { - bundles.Add(new StyleBundle("~/Content/css").Include( - "~/Content/site.css")); - } - } -} \ No newline at end of file diff --git a/samples/OutputCacheExample/App_Start/FilterConfig.cs b/samples/OutputCacheExample/App_Start/FilterConfig.cs deleted file mode 100644 index e3b01602..00000000 --- a/samples/OutputCacheExample/App_Start/FilterConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Web; -using System.Web.Mvc; - -namespace OutputCacheExample -{ - public class FilterConfig - { - public static void RegisterGlobalFilters(GlobalFilterCollection filters) - { - filters.Add(new HandleErrorAttribute()); - } - } -} diff --git a/samples/OutputCacheExample/App_Start/RouteConfig.cs b/samples/OutputCacheExample/App_Start/RouteConfig.cs deleted file mode 100644 index 055e8aa6..00000000 --- a/samples/OutputCacheExample/App_Start/RouteConfig.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.Mvc; -using System.Web.Routing; - -namespace OutputCacheExample -{ - public class RouteConfig - { - public static void RegisterRoutes(RouteCollection routes) - { - routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); - - routes.MapRoute( - name: "Default", - url: "{controller}/{action}/{id}", - defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } - ); - } - } -} diff --git a/samples/OutputCacheExample/Content/Site.css b/samples/OutputCacheExample/Content/Site.css deleted file mode 100644 index 6ea5d8f6..00000000 --- a/samples/OutputCacheExample/Content/Site.css +++ /dev/null @@ -1,24 +0,0 @@ -body { - padding-top: 50px; - padding-bottom: 20px; -} - -/* Set padding to keep content from hitting the edges */ -.body-content { - padding-left: 15px; - padding-right: 15px; -} - -/* Override the default bootstrap behavior where horizontal description lists - will truncate terms that are too long to fit in the left column -*/ -.dl-horizontal dt { - white-space: normal; -} - -/* Set width on the form input elements since they're 100% wide by default */ -input, -select, -textarea { - max-width: 280px; -} diff --git a/samples/OutputCacheExample/Controllers/HomeController.cs b/samples/OutputCacheExample/Controllers/HomeController.cs deleted file mode 100644 index f6e02784..00000000 --- a/samples/OutputCacheExample/Controllers/HomeController.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web.Mvc; -using System.Web.UI; -using CacheManager.Core.Internal; - -namespace OutputCacheExample.Controllers -{ - [OutputCache(Location = OutputCacheLocation.ServerAndClient, Duration = 0)] - public class HomeController : Controller - { - public ActionResult Index() - { - var cache = CacheManager.Web.CacheManagerOutputCacheProvider.Cache; - - var model = new CacheInfoModel() - { - }; - - foreach (var handle in cache.CacheHandles) - { - model.Layers.Add(handle.Configuration.Name); - model.CacheCount.Add(handle.Configuration.Name, handle.Count); - - var stats = new Dictionary(); - - stats.Add(CacheStatsCounterType.AddCalls, handle.Stats.GetStatistic(CacheStatsCounterType.AddCalls)); - stats.Add(CacheStatsCounterType.PutCalls, handle.Stats.GetStatistic(CacheStatsCounterType.PutCalls)); - stats.Add(CacheStatsCounterType.GetCalls, handle.Stats.GetStatistic(CacheStatsCounterType.GetCalls)); - stats.Add(CacheStatsCounterType.Hits, handle.Stats.GetStatistic(CacheStatsCounterType.Hits)); - stats.Add(CacheStatsCounterType.Misses, handle.Stats.GetStatistic(CacheStatsCounterType.Misses)); - model.Stats.Add(handle.Configuration.Name, stats); - } - - return View(model); - } - - [OutputCache(Location = OutputCacheLocation.Server, Duration = 2)] - public ActionResult PageA() - { - return View(); - } - - [OutputCache(Location = OutputCacheLocation.Server, Duration = 10)] - public ActionResult PageB() - { - return View(); - } - - [OutputCache(Location = OutputCacheLocation.Server, Duration = 30)] - public ActionResult PageC() - { - return View(); - } - } - - public class CacheInfoModel - { - public CacheInfoModel() - { - } - - public List Layers { get; } = new List(); - - public Dictionary CacheCount { get; } = new Dictionary(); - - public Dictionary> Stats { get; } = new Dictionary>(); - } -} \ No newline at end of file diff --git a/samples/OutputCacheExample/Global.asax b/samples/OutputCacheExample/Global.asax deleted file mode 100644 index 12f62ef3..00000000 --- a/samples/OutputCacheExample/Global.asax +++ /dev/null @@ -1 +0,0 @@ -<%@ Application Codebehind="Global.asax.cs" Inherits="OutputCacheExample.MvcApplication" Language="C#" %> diff --git a/samples/OutputCacheExample/Global.asax.cs b/samples/OutputCacheExample/Global.asax.cs deleted file mode 100644 index 32fdb40d..00000000 --- a/samples/OutputCacheExample/Global.asax.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.Mvc; -using System.Web.Optimization; -using System.Web.Routing; - -namespace OutputCacheExample -{ - public class MvcApplication : System.Web.HttpApplication - { - protected void Application_Start() - { - AreaRegistration.RegisterAllAreas(); - FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); - RouteConfig.RegisterRoutes(RouteTable.Routes); - BundleConfig.RegisterBundles(BundleTable.Bundles); - } - } -} diff --git a/samples/OutputCacheExample/OutputCacheExample.csproj b/samples/OutputCacheExample/OutputCacheExample.csproj deleted file mode 100644 index c8bbc374..00000000 --- a/samples/OutputCacheExample/OutputCacheExample.csproj +++ /dev/null @@ -1,214 +0,0 @@ - - - - - - - Debug - AnyCPU - - - 2.0 - {38C26AA8-EA36-4BD3-ADB1-693AA91A11C5} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - OutputCacheExample - OutputCacheExample - v4.6.2 - false - true - - - - - - - - - - true - full - false - bin\ - DEBUG;TRACE - prompt - 4 - - - true - pdbonly - true - bin\ - TRACE - prompt - 4 - - - - ..\..\packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll - - - ..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.5\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll - - - - ..\..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll - - - - - - - - - - - - - - - - - - - - - True - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - - True - ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - - - True - ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - - - ..\..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll - - - True - ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - - - True - ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - - - True - ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - - - True - ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - - - ..\..\packages\WebGrease.1.6.0\lib\WebGrease.dll - - - - - - - - - Global.asax - - - - - - - - - - Web.config - - - Web.config - - - - - - - - - - - - - - - - - {c9b4e53b-15fc-42af-9107-0c2e52e8680b} - CacheManager.Core - - - {3f3a3386-dfed-489c-a97d-541d43aa6c12} - CacheManager.Serialization.Json - - - {ba03975e-39cd-4318-8ed3-239aa399dc87} - CacheManager.StackExchange.Redis - - - {4fbe8026-2fae-462c-9446-33b49ca5a25d} - CacheManager.Web - - - - - - - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - - True - True - 30320 - / - http://localhost:30320/ - False - False - - - False - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - \ No newline at end of file diff --git a/samples/OutputCacheExample/Properties/AssemblyInfo.cs b/samples/OutputCacheExample/Properties/AssemblyInfo.cs deleted file mode 100644 index e83878c4..00000000 --- a/samples/OutputCacheExample/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OutputCacheExample")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("OutputCacheExample")] -[assembly: AssemblyCopyright("Copyright © 2017")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("4651c41f-c5b9-48c8-8796-b2de9e7c0da1")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/OutputCacheExample/Views/Home/Index.cshtml b/samples/OutputCacheExample/Views/Home/Index.cshtml deleted file mode 100644 index 6ec66d30..00000000 --- a/samples/OutputCacheExample/Views/Home/Index.cshtml +++ /dev/null @@ -1,71 +0,0 @@ -@{ - ViewBag.Title = "Home"; -} -@model OutputCacheExample.Controllers.CacheInfoModel -Home - - - Description - - This is a sample page to showcase the usage of CacheManager's OutputCache attribute. - - - - The Homepage doesn't get cached via OutputCache - - - Page A has a 2 second TTL - - - Page B has a 10 second TTL - - - Page C has a 30 second TTL - - - - - - - Cache Handles: - - The following list are the cache handles and cache item counts per handle. - - - @foreach (var cachename in Model.Layers) - { - int count = 0; - Model.CacheCount.TryGetValue(cachename, out count); - - @cachename (@count) - } - - - - - - - Cache Statistics: - - Statistics per Handle - - - @foreach (var cachename in Model.Layers) - { - int count = 0; - if (Model.Stats.ContainsKey(cachename)) - { - var stats = Model.Stats[cachename]; - - @cachename: - - @foreach (var stat in stats) - { - @stat.Key: @stat.Value - } - - } - } - - - \ No newline at end of file diff --git a/samples/OutputCacheExample/Views/Home/PageA.cshtml b/samples/OutputCacheExample/Views/Home/PageA.cshtml deleted file mode 100644 index d871a0d9..00000000 --- a/samples/OutputCacheExample/Views/Home/PageA.cshtml +++ /dev/null @@ -1,6 +0,0 @@ -@{ - ViewBag.Title = "Page A"; -} -Page A - -Last Refresh @DateTime.Now.ToString() \ No newline at end of file diff --git a/samples/OutputCacheExample/Views/Home/PageB.cshtml b/samples/OutputCacheExample/Views/Home/PageB.cshtml deleted file mode 100644 index f81b75fa..00000000 --- a/samples/OutputCacheExample/Views/Home/PageB.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@{ - ViewBag.Title = "Page B"; -} -Page B -Last Refresh @DateTime.Now.ToString() \ No newline at end of file diff --git a/samples/OutputCacheExample/Views/Home/PageC.cshtml b/samples/OutputCacheExample/Views/Home/PageC.cshtml deleted file mode 100644 index 267a2d00..00000000 --- a/samples/OutputCacheExample/Views/Home/PageC.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@{ - ViewBag.Title = "Page C"; -} -Page C -Last Refresh @DateTime.Now.ToString() \ No newline at end of file diff --git a/samples/OutputCacheExample/Views/Shared/Error.cshtml b/samples/OutputCacheExample/Views/Shared/Error.cshtml deleted file mode 100644 index 4c9a28a2..00000000 --- a/samples/OutputCacheExample/Views/Shared/Error.cshtml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Error - - - - Error. - An error occurred while processing your request. - - - diff --git a/samples/OutputCacheExample/Views/Shared/_Layout.cshtml b/samples/OutputCacheExample/Views/Shared/_Layout.cshtml deleted file mode 100644 index 4a2853ee..00000000 --- a/samples/OutputCacheExample/Views/Shared/_Layout.cshtml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - @ViewBag.Title - My ASP.NET Application - - - - - @Styles.Render("~/Content/css") - - - - - - - - - - - @Html.ActionLink("OutputCache Testing", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" }) - - - - @Html.ActionLink("PageA", "PageA", "Home") - @Html.ActionLink("PageB", "PageB", "Home") - @Html.ActionLink("PageC", "PageC", "Home") - - - - - - @RenderBody() - - - - - - - @RenderSection("scripts", required: false) - - \ No newline at end of file diff --git a/samples/OutputCacheExample/Views/Web.config b/samples/OutputCacheExample/Views/Web.config deleted file mode 100644 index cb1edccf..00000000 --- a/samples/OutputCacheExample/Views/Web.config +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/OutputCacheExample/Views/_ViewStart.cshtml b/samples/OutputCacheExample/Views/_ViewStart.cshtml deleted file mode 100644 index 2de62418..00000000 --- a/samples/OutputCacheExample/Views/_ViewStart.cshtml +++ /dev/null @@ -1,3 +0,0 @@ -@{ - Layout = "~/Views/Shared/_Layout.cshtml"; -} diff --git a/samples/OutputCacheExample/Web.Debug.config b/samples/OutputCacheExample/Web.Debug.config deleted file mode 100644 index d7712aaf..00000000 --- a/samples/OutputCacheExample/Web.Debug.config +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - diff --git a/samples/OutputCacheExample/Web.Release.config b/samples/OutputCacheExample/Web.Release.config deleted file mode 100644 index 28a4d5fc..00000000 --- a/samples/OutputCacheExample/Web.Release.config +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - diff --git a/samples/OutputCacheExample/Web.config b/samples/OutputCacheExample/Web.config deleted file mode 100644 index 4ae46988..00000000 --- a/samples/OutputCacheExample/Web.config +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/OutputCacheExample/favicon.ico b/samples/OutputCacheExample/favicon.ico deleted file mode 100644 index a3a79998..00000000 Binary files a/samples/OutputCacheExample/favicon.ico and /dev/null differ diff --git a/samples/OutputCacheExample/packages.config b/samples/OutputCacheExample/packages.config deleted file mode 100644 index 0ce1f544..00000000 --- a/samples/OutputCacheExample/packages.config +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/CacheManager.Core/Utility/Clock.cs b/src/CacheManager.Core/Utility/Clock.cs deleted file mode 100644 index 337a2f16..00000000 --- a/src/CacheManager.Core/Utility/Clock.cs +++ /dev/null @@ -1,72 +0,0 @@ -////using System; -////using System.Runtime.CompilerServices; - -////namespace CacheManager.Core.Utility -////{ -//// /// -//// /// Time related helper. -//// /// -//// internal static class Clock -//// { -//// /// -//// /// Number of ticks per millisecond. -//// /// -//// public const long TicksPerMillisecond = 10000; - -//// /// -//// /// Ticks since 1970. -//// /// -//// public const long UnixEpochTicks = TimeSpan.TicksPerDay * DaysTo1970; - -//// /// -//// /// Seconds since 1970. -//// /// -//// public const long UnixEpochSeconds = UnixEpochTicks / TimeSpan.TicksPerSecond; - -//// // Number of days in a non-leap year -//// private const int DaysPerYear = 365; - -//// // Number of days in 4 years -//// private const int DaysPer4Years = DaysPerYear * 4 + 1; // 1461 - -//// // Number of days in 100 years -//// private const int DaysPer100Years = DaysPer4Years * 25 - 1; // 36524 - -//// // Number of days in 400 years -//// private const int DaysPer400Years = DaysPer100Years * 4 + 1; // 146097 - -//// // Number of days from 1/1/0001 to 12/31/1969 -//// private const int DaysTo1970 = DaysPer400Years * 4 + DaysPer100Years * 3 + DaysPer4Years * 17 + DaysPerYear; // 719,162 - -//// /// -//// /// Computes a timestamp representing milliseconds since 1970. -//// /// -//// /// The milliseconds. -//// [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] -//// public static long GetUnixTimestampMillis() -//// { -//// return (DateTime.UtcNow.Ticks - UnixEpochTicks) / TicksPerMillisecond; -//// } - -//// /// -//// /// Computes a timestamp representing ticks since 1970. -//// /// -//// /// The ticks. -//// [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] -//// public static long GetUnixTimestampTicks() -//// { -//// return DateTime.UtcNow.Ticks - UnixEpochTicks; -//// } - -//// /// -//// /// Computes the milliseconds since 1970 up to the given . -//// /// -//// /// The base. -//// /// The milliseconds since 1970. -//// [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] -//// public static long ToUnixTimestampMillis(DateTime date) -//// { -//// return (date.Ticks - UnixEpochTicks) / TicksPerMillisecond; -//// } -//// } -////} diff --git a/src/CacheManager.Core/Utility/Guard.cs b/src/CacheManager.Core/Utility/Guard.cs index 8f48a087..33d82e33 100644 --- a/src/CacheManager.Core/Utility/Guard.cs +++ b/src/CacheManager.Core/Utility/Guard.cs @@ -149,7 +149,7 @@ public static T EnsureNotNull([ValidatedNotNull]T value, string message, para /// Indicates to Code Analysis that a method validates a particular parameter. /// [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] - public sealed class ValidatedNotNullAttribute : Attribute + internal sealed class ValidatedNotNullAttribute : Attribute { /// /// Initializes a new instance of the class. diff --git a/src/CacheManager.Core/Utility/ObjectPool.cs b/src/CacheManager.Core/Utility/ObjectPool.cs deleted file mode 100644 index d3ebacf7..00000000 --- a/src/CacheManager.Core/Utility/ObjectPool.cs +++ /dev/null @@ -1,96 +0,0 @@ -////using System; -////using System.Linq; -////using System.Threading; - -////namespace CacheManager.Core.Utility -////{ -//// /// -//// /// Contract used by to define how to create and return instances to a pool. -//// /// -//// /// The type of objects of the pool. -//// public interface IObjectPoolPolicy -//// { -//// /// -//// /// Creates a new instance of . -//// /// -//// /// The new instance. -//// T CreateNew(); - -//// /// -//// /// Checks if the instance can be returned and may reset the instance to a state which can be reused. -//// /// -//// /// The instance which should be returned. -//// /// True if the instance can be returned, False otherwise. -//// bool Return(T value); -//// } - -//// /// -//// /// Simple policy based pool for objects. -//// /// -//// /// The object type to pool. -//// public class ObjectPool where T : class -//// { -//// private readonly T[] _items; -//// private readonly IObjectPoolPolicy _policy; - -//// /// -//// /// Initializes a new instance of the class. -//// /// -//// /// The object pool policy. -//// /// Number of items to keep, defaults to number of processors * 2. -//// public ObjectPool(IObjectPoolPolicy policy, int? maxItems = null) -//// { -//// if (policy == null) -//// { -//// throw new ArgumentNullException(nameof(policy)); -//// } - -//// if (maxItems == null || maxItems <= 0) -//// { -//// maxItems = Environment.ProcessorCount * 2; -//// } - -//// _policy = policy; -//// _items = new T[maxItems.Value]; -//// } - -//// /// -//// /// Returns either a pooled or new instance of . -//// /// -//// /// The pooled or new instance. -//// public T Lease() -//// { -//// for (var i = 0; i < _items.Length; i++) -//// { -//// var item = _items[i]; -//// if (item != null && Interlocked.CompareExchange(ref _items[i], null, item) == item) -//// { -//// return item; -//// } -//// } - -//// return _policy.CreateNew(); -//// } - -//// /// -//// /// Returns the instance to the pool (if possible). -//// /// -//// /// The instance to return to the pool. -//// public void Return(T value) -//// { -//// if (!_policy.Return(value)) -//// { -//// return; -//// } - -//// for (var i = 0; i < _items.Length; i++) -//// { -//// if (_items[i] == null) -//// { -//// _items[i] = value; -//// return; -//// } -//// } -//// } -//// } -////} diff --git a/test/CacheManager.Tests/RedisTestFixture.cs b/test/CacheManager.Tests/RedisTestFixture.cs index c81452cb..dfdf78f0 100644 --- a/test/CacheManager.Tests/RedisTestFixture.cs +++ b/test/CacheManager.Tests/RedisTestFixture.cs @@ -20,13 +20,13 @@ public class RedisTestFixture : IDisposable private static int InstanceCount = 0; - public static GarnetServer StartServer(ILoggerFactory loggerFactory = null) + public static GarnetServer StartServer(int port = 6379, ILoggerFactory loggerFactory = null) { var server = new GarnetServer(new GarnetServerOptions() { EnableLua = true, LuaOptions = new LuaOptions(LuaMemoryManagementMode.Native, string.Empty, TimeSpan.FromSeconds(20)), - EndPoint = new IPEndPoint(IPAddress.Loopback, 6379), + EndPoint = new IPEndPoint(IPAddress.Loopback, port), }, loggerFactory: loggerFactory); try @@ -51,6 +51,7 @@ public RedisTestFixture() public void Dispose() { + Task.Delay(5000).GetAwaiter().GetResult(); var current = Interlocked.Decrement(ref InstanceCount); // Console.WriteLine($"Disposing... {current}"); diff --git a/test/CacheManager.Tests/RedisTests.cs b/test/CacheManager.Tests/RedisTests.cs index 5d7fe8e3..89d6dba1 100644 --- a/test/CacheManager.Tests/RedisTests.cs +++ b/test/CacheManager.Tests/RedisTests.cs @@ -31,6 +31,68 @@ private enum CacheEvent OnClearRegion } + [Fact] + [Trait("category", "Redis")] + [Trait("category", "Unreliable")] + public void Redis_TwoServerSetup_ClearWorks() + { + using var server1 = RedisTestFixture.StartServer(7001); + using var server2 = RedisTestFixture.StartServer(7002); + + var cache1 = new BaseCacheManager(CacheConfigurationBuilder + .BuildConfiguration(a => + { + a.WithRedisCacheHandle("redis1"); + a.WithRedisConfiguration("redis1", c => c.WithEndpoint("localhost", 7001).WithAllowAdmin()); + a.WithJsonSerializer(); + })); + + var cache2 = new BaseCacheManager(CacheConfigurationBuilder + .BuildConfiguration(a => + { + a.WithRedisCacheHandle("redis2"); + a.WithRedisConfiguration("redis2", c => c.WithEndpoint("localhost", 7002).WithAllowAdmin()); + a.WithJsonSerializer(); + })); + + var cacheBoth = new BaseCacheManager(CacheConfigurationBuilder + .BuildConfiguration(a => + { + a.WithRedisCacheHandle("redis"); + a.WithJsonSerializer(); + a.WithRedisConfiguration("redis", c => c + .WithEndpoint("localhost", 7001) + .WithEndpoint("localhost", 7002) + .WithAllowAdmin()); + })); + + + var testKey = Guid.NewGuid().ToString(); + var value = Guid.NewGuid().ToString(); + + cacheBoth.Add(testKey, value); + + var exists1 = cache1.Exists(testKey); + var exists2 = cache2.Exists(testKey); + + Assert.True(exists1 || exists2); + + if (!exists1) + { + cache1[testKey] = "other value"; + } + else + { + Assert.False(exists2); + cache2[testKey] = "other value"; + } + + cacheBoth.Clear(); + + Assert.False(cache1.Exists(testKey)); + Assert.False(cache2.Exists(testKey)); + } + [Fact] public void Redis_WithoutSerializer_ShouldThrow() { diff --git a/tools/clear_packages.cmd b/tools/clear_packages.cmd deleted file mode 100644 index 5e9b7d45..00000000 --- a/tools/clear_packages.cmd +++ /dev/null @@ -1,3 +0,0 @@ -@rmdir /S /Q packages -rmdir /S /Q %USERPROFILE%\.dnx\packages -rmdir /S /Q %USERPROFILE%\.nuget\packages \ No newline at end of file
OutputCache
- The following list are the cache handles and cache item counts per handle. -
- Statistics per Handle -