Browse Source

[c#/beetlex] add caching sample (#5851)

* update beetlex 1.4.3

update beetlex 1.4.3

* docker add COMPlus_ReadyToRun variable
update beetlex

* update beetlex, enabled thread queue

* beetlex framework add db and queries cases

* add db code

* change result json data

* update query url

* beetlex framework add fortunes cases

* change Content-Type

* add beetlex core cases

* fix queries cases

* update config

* change try readline

* update benchmark config

* Update README.md

* Update README.md

* change versus property

* beetlex-core update .net core to v3.0

* change beetlex-core project file

* beetlex update raw db class

* beetlex update raw db

* beetlex debug plaintext

* change debug docker file

* update beetlex to 1.4.0

* update

* beetlex update core 3.1

* [c#/beetlex] add updates cases

* [c#/beetlex] change Server: TFB, change custom connection pool, add update docker

* fix errors

* change pool init

* change connection pool maxsize

* fix fortunes errors

* clear DBRaw _connectionString value.

* [c#beetlex] change update dbconnection pool size

* [c#/beetlex] udpate spanjson to v3.0.1, Npgsql v5.0.0

* [c#/beetlex] add caching sample

* set connectionstring multiplexing

* remove connection multiplexing setting
Henry 5 years ago
parent
commit
cc5643216a

+ 16 - 0
frameworks/CSharp/beetlex/PlatformBenchmarks/CachedWorld.cs

@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace PlatformBenchmarks
+{
+    public class CachedWorld
+    {
+        public int Id { get; set; }
+
+        public int RandomNumber { get; set; }
+
+        public static implicit operator World(CachedWorld world) => new World { Id = world.Id, RandomNumber = world.RandomNumber };
+        public static implicit operator CachedWorld(World world) => new CachedWorld { Id = world.Id, RandomNumber = world.RandomNumber };
+    }
+}

+ 43 - 0
frameworks/CSharp/beetlex/PlatformBenchmarks/Caching.cs

@@ -0,0 +1,43 @@
+using BeetleX;
+using BeetleX.Buffers;
+using SpanJson;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+
+namespace PlatformBenchmarks
+{
+    public partial class HttpHandler
+    {
+        public async void caching(string queryString, PipeStream stream, HttpToken token, ISession session)
+        {
+            int count = 1;
+            if (!string.IsNullOrEmpty(queryString))
+            {
+                var values = queryString.Split('=');
+                if (values.Length > 1)
+                {
+                    if (int.TryParse(values[1], out int size))
+                    {
+                        count = size;
+                    }
+                }
+            }
+            if (count > 500)
+                count = 500;
+            if (count < 1)
+                count = 1;
+            try
+            {
+                var data = await token.Db.LoadCachedQueries(count);
+                await JsonSerializer.NonGeneric.Utf8.SerializeAsync(data, stream);
+            }
+            catch (Exception e_)
+            {
+                stream.Write(e_.Message);
+            }
+            OnCompleted(stream, session, token);
+        }
+    }
+}

+ 85 - 0
frameworks/CSharp/beetlex/PlatformBenchmarks/DBRaw.cs

@@ -9,6 +9,7 @@ using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using System.Runtime.InteropServices.ComTypes;
 using System.Runtime.InteropServices.ComTypes;
 using BeetleX.EventArgs;
 using BeetleX.EventArgs;
+using Microsoft.Extensions.Caching.Memory;
 
 
 namespace PlatformBenchmarks
 namespace PlatformBenchmarks
 {
 {
@@ -19,6 +20,14 @@ namespace PlatformBenchmarks
 
 
         private readonly DbProviderFactory _dbProviderFactory;
         private readonly DbProviderFactory _dbProviderFactory;
 
 
+        private readonly static MemoryCache _cache = new MemoryCache(
+          new MemoryCacheOptions()
+          {
+              ExpirationScanFrequency = TimeSpan.FromMinutes(60)
+          });
+
+        private static readonly object[] _cacheKeys = Enumerable.Range(0, 10001).Select((i) => new CacheKey(i)).ToArray();
+
         public static string _connectionString = null;
         public static string _connectionString = null;
 
 
         public RawDb(ConcurrentRandom random, DbProviderFactory dbProviderFactory)
         public RawDb(ConcurrentRandom random, DbProviderFactory dbProviderFactory)
@@ -78,6 +87,61 @@ namespace PlatformBenchmarks
 
 
         }
         }
 
 
+
+        public Task<World[]> LoadCachedQueries(int count)
+        {
+            var result = new World[count];
+            var cacheKeys = _cacheKeys;
+            var cache = _cache;
+            var random = _random;
+            for (var i = 0; i < result.Length; i++)
+            {
+                var id = random.Next(1, 10001);
+                var key = cacheKeys[id];
+                var data = cache.Get<CachedWorld>(key);
+
+                if (data != null)
+                {
+                    result[i] = data;
+                }
+                else
+                {
+                    return LoadUncachedQueries(id, i, count, this, result);
+                }
+            }
+
+            return Task.FromResult(result);
+
+            static async Task<World[]> LoadUncachedQueries(int id, int i, int count, RawDb rawdb, World[] result)
+            {
+                using (var db = await DBConnectionGroupPool.Pop())
+                {
+                    Func<ICacheEntry, Task<CachedWorld>> create = async (entry) =>
+                    {
+                        return await rawdb.ReadSingleRow(db.Connection, rawdb.SingleCommand);
+                    };
+
+                    var cacheKeys = _cacheKeys;
+                    var key = cacheKeys[id];
+
+                    rawdb.SingleCommand.Connection = db.Connection;
+                    rawdb.SingleCommand.Parameters[0].Value = id;
+
+                    for (; i < result.Length; i++)
+                    {
+                        var data = await _cache.GetOrCreateAsync<CachedWorld>(key, create);
+                        result[i] = data;
+                        id = rawdb._random.Next(1, 10001);
+                        rawdb.SingleCommand.Connection = db.Connection;
+                        rawdb.SingleCommand.Parameters[0].Value = id;
+                        key = cacheKeys[id];
+                    }
+                }
+                return result;
+            }
+        }
+
+
         private async Task<World[]> LoadMultipleRows(int count, DbConnection db)
         private async Task<World[]> LoadMultipleRows(int count, DbConnection db)
         {
         {
             SingleCommand.Connection = db;
             SingleCommand.Connection = db;
@@ -155,6 +219,27 @@ namespace PlatformBenchmarks
         }
         }
     }
     }
 
 
+
+    public sealed class CacheKey : IEquatable<CacheKey>
+    {
+        private readonly int _value;
+
+        public CacheKey(int value)
+            => _value = value;
+
+        public bool Equals(CacheKey key)
+            => key._value == _value;
+
+        public override bool Equals(object obj)
+            => ReferenceEquals(obj, this);
+
+        public override int GetHashCode()
+            => _value;
+
+        public override string ToString()
+            => _value.ToString();
+    }
+
     internal class UpdateCommandsCached
     internal class UpdateCommandsCached
     {
     {
         private static System.Collections.Concurrent.ConcurrentStack<DbCommand>[] mCacheTable
         private static System.Collections.Concurrent.ConcurrentStack<DbCommand>[] mCacheTable

+ 12 - 2
frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.cs

@@ -43,6 +43,8 @@ namespace PlatformBenchmarks
 
 
         private static readonly AsciiString _result_plaintext = "Hello, World!";
         private static readonly AsciiString _result_plaintext = "Hello, World!";
 
 
+        private static readonly AsciiString _cached_worlds = "/cached-worlds";
+
         private static byte _Space = 32;
         private static byte _Space = 32;
 
 
         private static byte _question = 63;
         private static byte _question = 63;
@@ -150,7 +152,7 @@ namespace PlatformBenchmarks
             base.SessionReceive(server, e);
             base.SessionReceive(server, e);
             PipeStream pipeStream = e.Session.Stream.ToPipeStream();
             PipeStream pipeStream = e.Session.Stream.ToPipeStream();
             HttpToken token = (HttpToken)e.Session.Tag;
             HttpToken token = (HttpToken)e.Session.Tag;
-            if (Program.Debug)
+            if (Program.Debug || Program.UpDB)
             {
             {
                 RequestWork work = new RequestWork();
                 RequestWork work = new RequestWork();
                 work.Handler = this;
                 work.Handler = this;
@@ -173,7 +175,7 @@ namespace PlatformBenchmarks
             {
             {
                 UpdateCommandsCached.Init();
                 UpdateCommandsCached.Init();
                 if (Program.UpDB)
                 if (Program.UpDB)
-                    DBConnectionGroupPool.Init(32, RawDb._connectionString);
+                    DBConnectionGroupPool.Init(64, RawDb._connectionString);
                 else
                 else
                     DBConnectionGroupPool.Init(256, RawDb._connectionString);
                     DBConnectionGroupPool.Init(256, RawDb._connectionString);
             }
             }
@@ -214,6 +216,14 @@ namespace PlatformBenchmarks
                 OnWriteContentLength(stream, token);
                 OnWriteContentLength(stream, token);
                 queries(Encoding.ASCII.GetString(queryString), stream, token, session);
                 queries(Encoding.ASCII.GetString(queryString), stream, token, session);
             }
             }
+
+            else if (baseUrl.Length == _cached_worlds.Length && baseUrl.StartsWith(_cached_worlds))
+            {
+                stream.Write(_headerContentTypeJson.Data, 0, _headerContentTypeJson.Length);
+                OnWriteContentLength(stream, token);
+                caching(Encoding.ASCII.GetString(queryString), stream, token, session);
+            }
+
             else if (baseUrl.Length == _path_Updates.Length && baseUrl.StartsWith(_path_Updates))
             else if (baseUrl.Length == _path_Updates.Length && baseUrl.StartsWith(_path_Updates))
             {
             {
                 stream.Write(_headerContentTypeJson.Data, 0, _headerContentTypeJson.Length);
                 stream.Write(_headerContentTypeJson.Data, 0, _headerContentTypeJson.Length);

+ 4 - 4
frameworks/CSharp/beetlex/PlatformBenchmarks/HttpServer.cs

@@ -27,13 +27,13 @@ namespace PlatformBenchmarks
             ApiServer.Open();
             ApiServer.Open();
             if (!Program.UpDB)
             if (!Program.UpDB)
             {
             {
-                RawDb._connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3";
-               // RawDb._connectionString = "Server=192.168.2.19;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3";
+               RawDb._connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3";
+                //RawDb._connectionString = "Server=192.168.2.19;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3";
             }
             }
             else
             else
             {
             {
-                // RawDb._connectionString = "Server=192.168.2.19;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=32;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3";
-                RawDb._connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=64;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3";
+               // RawDb._connectionString = "Server=192.168.2.19;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=64;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3";
+               RawDb._connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=64;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3";
             }           
             }           
             ApiServer.Log(LogType.Info, null, $"Debug mode [{Program.Debug}]");
             ApiServer.Log(LogType.Info, null, $"Debug mode [{Program.Debug}]");
             return Task.CompletedTask;
             return Task.CompletedTask;

+ 2 - 1
frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj

@@ -4,11 +4,12 @@
     <OutputType>Exe</OutputType>
     <OutputType>Exe</OutputType>
     <TargetFramework>netcoreapp3.1</TargetFramework>
     <TargetFramework>netcoreapp3.1</TargetFramework>
     <ServerGarbageCollection>true</ServerGarbageCollection>
     <ServerGarbageCollection>true</ServerGarbageCollection>
-    <LangVersion>7.2</LangVersion>
+   
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="BeetleX" Version="1.4.0.1" />
     <PackageReference Include="BeetleX" Version="1.4.0.1" />
+    <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.5" />
     <PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" />
     <PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" />
     <PackageReference Include="Npgsql" Version="5.0.0-alpha1" />
     <PackageReference Include="Npgsql" Version="5.0.0-alpha1" />
     <PackageReference Include="SpanJson" Version="3.0.1" />
     <PackageReference Include="SpanJson" Version="3.0.1" />

+ 1 - 0
frameworks/CSharp/beetlex/benchmark_config.json

@@ -32,6 +32,7 @@
         "db_url": "/db",
         "db_url": "/db",
         "query_url": "/queries?queries=",
         "query_url": "/queries?queries=",
         "update_url": "/updates?queries=",
         "update_url": "/updates?queries=",
+        "cached_query_url": "/cached-worlds?queries=",
         "port": 8080,
         "port": 8080,
         "approach": "Realistic",
         "approach": "Realistic",
         "classification": "Platform",
         "classification": "Platform",