Browse Source

[c#/BeetleX] add updates cases (#5717)

* 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
Henry 5 years ago
parent
commit
6239961fb9

+ 131 - 1
frameworks/CSharp/beetlex/Benchmarks/DBRaw.cs

@@ -5,6 +5,8 @@ using System.Data.Common;
 using System.Text;
 using System.Threading.Tasks;
 using System.Collections.Concurrent;
+using System.Linq;
+
 namespace Benchmarks
 {
     public class RawDb
@@ -21,7 +23,7 @@ namespace Benchmarks
             _random = random;
             _dbProviderFactory = dbProviderFactory;
             _connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3";
-            //_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";
+           // _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";
             OnCreateCommand();
         }
 
@@ -120,5 +122,133 @@ namespace Benchmarks
             result.Sort();
             return result;
         }
+
+        public async Task<World[]> LoadMultipleUpdatesRows(int count)
+        {
+            using (var db = _dbProviderFactory.CreateConnection())
+            {
+                db.ConnectionString = _connectionString;
+                await db.OpenAsync();
+
+                using (var updateCmd = db.CreateCommand())
+                using (var queryCmd = CreateReadCommand(db))
+                {
+                    var results = new World[count];
+                    for (int i = 0; i < count; i++)
+                    {
+                        results[i] = await ReadSingleRow(db, queryCmd);
+                        queryCmd.Parameters["@Id"].Value = _random.Next(1, 10001);
+                    }
+
+                    updateCmd.CommandText = BatchUpdateString.Query(count);
+
+                    for (int i = 0; i < count; i++)
+                    {
+                        var id = updateCmd.CreateParameter();
+                        id.ParameterName = $"@Id_{i}";
+                        id.DbType = DbType.Int32;
+                        updateCmd.Parameters.Add(id);
+
+                        var random = updateCmd.CreateParameter();
+                        random.ParameterName = $"@Random_{i}";
+                        random.DbType = DbType.Int32;
+                        updateCmd.Parameters.Add(random);
+
+                        var randomNumber = _random.Next(1, 10001);
+                        id.Value = results[i].Id;
+                        random.Value = randomNumber;
+                        results[i].RandomNumber = randomNumber;
+                    }
+
+                    await updateCmd.ExecuteNonQueryAsync();
+                    return results;
+                }
+            }
+        }
+
+        DbCommand CreateReadCommand(DbConnection connection)
+        {
+            var cmd = connection.CreateCommand();
+            cmd.CommandText = "SELECT id, randomnumber FROM world WHERE id = @Id";
+            var id = cmd.CreateParameter();
+            id.ParameterName = "@Id";
+            id.DbType = DbType.Int32;
+            id.Value = _random.Next(1, 10001);
+            cmd.Parameters.Add(id);
+            return cmd;
+        }
+    }
+
+    internal class BatchUpdateString
+    {
+        private const int MaxBatch = 500;
+
+        private static string[] _queries = new string[MaxBatch + 1];
+
+        public static string Query(int batchSize)
+        {
+            if (_queries[batchSize] != null)
+            {
+                return _queries[batchSize];
+            }
+
+            var lastIndex = batchSize - 1;
+            var sb = StringBuilderCache.Acquire();
+            sb.Append("UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES ");
+            Enumerable.Range(0, lastIndex).ToList().ForEach(i => sb.Append($"(@Id_{i}, @Random_{i}), "));
+            sb.Append($"(@Id_{lastIndex}, @Random_{lastIndex}) ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id");
+            return _queries[batchSize] = StringBuilderCache.GetStringAndRelease(sb);
+        }
+    }
+
+    internal static class StringBuilderCache
+    {
+        private const int DefaultCapacity = 1386;
+        private const int MaxBuilderSize = DefaultCapacity * 3;
+
+        [ThreadStatic]
+        private static StringBuilder t_cachedInstance;
+
+        /// <summary>Get a StringBuilder for the specified capacity.</summary>
+        /// <remarks>If a StringBuilder of an appropriate size is cached, it will be returned and the cache emptied.</remarks>
+        public static StringBuilder Acquire(int capacity = DefaultCapacity)
+        {
+            if (capacity <= MaxBuilderSize)
+            {
+                StringBuilder sb = t_cachedInstance;
+                if (capacity < DefaultCapacity)
+                {
+                    capacity = DefaultCapacity;
+                }
+
+                if (sb != null)
+                {
+                    // Avoid stringbuilder block fragmentation by getting a new StringBuilder
+                    // when the requested size is larger than the current capacity
+                    if (capacity <= sb.Capacity)
+                    {
+                        t_cachedInstance = null;
+                        sb.Clear();
+                        return sb;
+                    }
+                }
+            }
+            return new StringBuilder(capacity);
+        }
+
+        public static void Release(StringBuilder sb)
+        {
+            if (sb.Capacity <= MaxBuilderSize)
+            {
+                t_cachedInstance = sb;
+            }
+        }
+
+        public static string GetStringAndRelease(StringBuilder sb)
+        {
+            string result = sb.ToString();
+            Release(sb);
+            return result;
+        }
     }
 }

+ 13 - 4
frameworks/CSharp/beetlex/Benchmarks/Program.cs

@@ -60,12 +60,18 @@ namespace Benchmarks
         }
 
 
-      
+        public async Task<object> updates(int queries, IHttpContext context)
+        {
+            queries = queries < 1 ? 1 : queries > 500 ? 500 : queries;
+            var result= await GetDB(context).LoadMultipleUpdatesRows(queries);
+            return new SpanJsonResult(result);
+        }
+
 
         [NotAction]
         public void Init(HttpApiServer server, string path)
         {
-           
+
         }
     }
 
@@ -91,7 +97,8 @@ namespace Benchmarks
             mApiServer.Options.LogToConsole = true;
             mApiServer.Options.PrivateBufferPool = true;
             mApiServer.Register(typeof(Program).Assembly);
-            mApiServer.HttpConnected += (o, e) => {
+            mApiServer.HttpConnected += (o, e) =>
+            {
                 e.Session["DB"] = new RawDb(new ConcurrentRandom(), Npgsql.NpgsqlFactory.Instance);
             };
             mApiServer.Open();
@@ -100,7 +107,7 @@ namespace Benchmarks
             mApiServer.BaseServer.Log(LogType.Info, null, $"Get josn {response.StatusCode}");
             response = await client.GetAsync("http://localhost:8080/plaintext");
             mApiServer.BaseServer.Log(LogType.Info, null, $"Get plaintext {response.StatusCode}");
-          
+
         }
 
         public virtual Task StopAsync(CancellationToken cancellationToken)
@@ -131,5 +138,7 @@ namespace Benchmarks
         {
             JsonSerializer.NonGeneric.Utf8.SerializeAsync(Data, stream);
         }
+
+
     }
 }

+ 130 - 2
frameworks/CSharp/beetlex/PlatformBenchmarks/DBRaw.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Data;
 using System.Data.Common;
+using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 
@@ -20,8 +21,8 @@ namespace PlatformBenchmarks
         {
             _random = random;
             _dbProviderFactory = dbProviderFactory;
-           _connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3";
-            //_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";
+            _connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3";
+           // _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";
             OnCreateCommand();
         }
 
@@ -120,5 +121,132 @@ namespace PlatformBenchmarks
             result.Sort();
             return result;
         }
+        public async Task<World[]> LoadMultipleUpdatesRows(int count)
+        {
+            using (var db = _dbProviderFactory.CreateConnection())
+            {
+                db.ConnectionString = _connectionString;
+                await db.OpenAsync();
+
+                using (var updateCmd = db.CreateCommand())
+                using (var queryCmd = CreateReadCommand(db))
+                {
+                    var results = new World[count];
+                    for (int i = 0; i < count; i++)
+                    {
+                        results[i] = await ReadSingleRow(db, queryCmd);
+                        queryCmd.Parameters["@Id"].Value = _random.Next(1, 10001);
+                    }
+
+                    updateCmd.CommandText = BatchUpdateString.Query(count);
+
+                    for (int i = 0; i < count; i++)
+                    {
+                        var id = updateCmd.CreateParameter();
+                        id.ParameterName = $"@Id_{i}";
+                        id.DbType = DbType.Int32;
+                        updateCmd.Parameters.Add(id);
+
+                        var random = updateCmd.CreateParameter();
+                        random.ParameterName = $"@Random_{i}";
+                        random.DbType = DbType.Int32;
+                        updateCmd.Parameters.Add(random);
+
+                        var randomNumber = _random.Next(1, 10001);
+                        id.Value = results[i].Id;
+                        random.Value = randomNumber;
+                        results[i].RandomNumber = randomNumber;
+                    }
+
+                    await updateCmd.ExecuteNonQueryAsync();
+                    return results;
+                }
+            }
+        }
+
+        DbCommand CreateReadCommand(DbConnection connection)
+        {
+            var cmd = connection.CreateCommand();
+            cmd.CommandText = "SELECT id, randomnumber FROM world WHERE id = @Id";
+            var id = cmd.CreateParameter();
+            id.ParameterName = "@Id";
+            id.DbType = DbType.Int32;
+            id.Value = _random.Next(1, 10001);
+            cmd.Parameters.Add(id);
+            return cmd;
+        }
+    }
+
+    internal class BatchUpdateString
+    {
+        private const int MaxBatch = 500;
+
+        private static string[] _queries = new string[MaxBatch + 1];
+
+        public static string Query(int batchSize)
+        {
+            if (_queries[batchSize] != null)
+            {
+                return _queries[batchSize];
+            }
+
+            var lastIndex = batchSize - 1;
+            var sb = StringBuilderCache.Acquire();
+            sb.Append("UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES ");
+            Enumerable.Range(0, lastIndex).ToList().ForEach(i => sb.Append($"(@Id_{i}, @Random_{i}), "));
+            sb.Append($"(@Id_{lastIndex}, @Random_{lastIndex}) ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id");
+            return _queries[batchSize] = StringBuilderCache.GetStringAndRelease(sb);
+        }
+    }
+
+    internal static class StringBuilderCache
+    {
+        private const int DefaultCapacity = 1386;
+        private const int MaxBuilderSize = DefaultCapacity * 3;
+
+        [ThreadStatic]
+        private static StringBuilder t_cachedInstance;
+
+        /// <summary>Get a StringBuilder for the specified capacity.</summary>
+        /// <remarks>If a StringBuilder of an appropriate size is cached, it will be returned and the cache emptied.</remarks>
+        public static StringBuilder Acquire(int capacity = DefaultCapacity)
+        {
+            if (capacity <= MaxBuilderSize)
+            {
+                StringBuilder sb = t_cachedInstance;
+                if (capacity < DefaultCapacity)
+                {
+                    capacity = DefaultCapacity;
+                }
+
+                if (sb != null)
+                {
+                    // Avoid stringbuilder block fragmentation by getting a new StringBuilder
+                    // when the requested size is larger than the current capacity
+                    if (capacity <= sb.Capacity)
+                    {
+                        t_cachedInstance = null;
+                        sb.Clear();
+                        return sb;
+                    }
+                }
+            }
+            return new StringBuilder(capacity);
+        }
+
+        public static void Release(StringBuilder sb)
+        {
+            if (sb.Capacity <= MaxBuilderSize)
+            {
+                t_cachedInstance = sb;
+            }
+        }
+
+        public static string GetStringAndRelease(StringBuilder sb)
+        {
+            string result = sb.ToString();
+            Release(sb);
+            return result;
+        }
     }
 }

+ 8 - 0
frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.cs

@@ -37,6 +37,8 @@ namespace PlatformBenchmarks
 
         private static readonly AsciiString _path_Plaintext = "/plaintext";
 
+        private static readonly AsciiString _path_Updates = "/updates";
+
         private static readonly AsciiString _path_Fortunes = "/fortunes";
 
         private static readonly AsciiString _result_plaintext = "Hello, World!";
@@ -204,6 +206,12 @@ namespace PlatformBenchmarks
                 OnWriteContentLength(stream, token);
                 queries(Encoding.ASCII.GetString(queryString), stream, token, session);
             }
+            else if (baseUrl.Length == _path_Updates.Length && baseUrl.StartsWith(_path_Updates))
+            {
+                stream.Write(_headerContentTypeJson.Data, 0, _headerContentTypeJson.Length);
+                OnWriteContentLength(stream, token);
+                updates(Encoding.ASCII.GetString(queryString), stream, token, session);
+            }
             else if (baseUrl.Length == _path_Fortunes.Length && baseUrl.StartsWith(_path_Fortunes))
             {
                 stream.Write(_headerContentTypeHtml.Data, 0, _headerContentTypeHtml.Length);

+ 42 - 0
frameworks/CSharp/beetlex/PlatformBenchmarks/updates.cs

@@ -0,0 +1,42 @@
+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 updates(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.LoadMultipleUpdatesRows(count);
+                await JsonSerializer.NonGeneric.Utf8.SerializeAsync(data, stream);
+            }
+            catch (Exception e_)
+            {
+                stream.Write(e_.Message);
+            }
+            OnCompleted(stream, session, token);
+        }
+    }
+}

+ 4 - 2
frameworks/CSharp/beetlex/benchmark_config.json

@@ -2,12 +2,13 @@
   "framework": "beetlex",
   "tests": [
     {
-      "default": {      
+      "default": {
         "fortune_url": "/fortunes",
         "plaintext_url": "/plaintext",
         "json_url": "/json",
         "db_url": "/db",
-        "query_url": "/queries?queries=",   
+        "query_url": "/queries?queries=",
+        "update_url": "/updates?queries=",
         "port": 8080,
         "approach": "Realistic",
         "classification": "Fullstack",
@@ -30,6 +31,7 @@
         "json_url": "/json",
         "db_url": "/db",
         "query_url": "/queries?queries=",
+        "update_url": "/updates?queries=",
         "port": 8080,
         "approach": "Realistic",
         "classification": "Platform",