Эх сурвалжийг харах

MemoryCopy instead of Marshal.Copy + easier connection reuse (#9983)

* MemoryCopy instead of Marshal.Copy

* Simplier connection reuse

* Faster MemoryCopy for all data access

---------

Co-authored-by: LLT21 <>
LLT21 2 долоо хоног өмнө
parent
commit
98cbbfde7b

+ 3 - 3
frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs

@@ -54,12 +54,12 @@ namespace appMpower.Orm.Data
          if (_keyed)
          {
             (_number, _odbcConnection, _keyedOdbcCommands) = 
-               DbConnectionsKeyed.GetConnectionBase(_connectionString).GetAwaiter().GetResult();
+               DbConnectionsKeyed.GetConnectionBase(_connectionString);
          }
          else
          {
-            (_number, _odbcConnection, _odbcCommands) = 
-               DbConnections.GetConnectionBase(_connectionString).GetAwaiter().GetResult();
+            (_number, _odbcConnection, _odbcCommands) =
+               DbConnections.GetConnectionBase(_connectionString);
          }
       }
 

+ 4 - 35
frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs

@@ -5,32 +5,18 @@ namespace appMpower.Orm.Data
 {
    internal static class DbConnections
    {
-      private static bool _maxConnectionsCreated = false;
       private static short _createdConnections = 0;
-      private static short _maxConnections = 500;
 
       private static ConcurrentStack<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)> _connectionsStack = new();
-      private static ConcurrentQueue<TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)>> _waitingQueue = new();
       
-      internal static async Task<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)> GetConnectionBase(string connectionString)
+      internal static (int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands) GetConnectionBase(string connectionString)
       {
          (int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands) dbConnectionBase;
 
          if (!_connectionsStack.TryPop(out dbConnectionBase))
          {
-            if (_maxConnectionsCreated)
-            {
-               dbConnectionBase = await GetDbConnectionBaseAsync();
-            }
-            else
-            {
-               _createdConnections++;
-               dbConnectionBase = (Number: _maxConnections, OdbcConnection: new OdbcConnection(connectionString), OdbcCommands: new ConcurrentStack<OdbcCommand>());
-
-               if (_createdConnections == _maxConnections) _maxConnectionsCreated = true;
-
-               //Console.WriteLine("opened connection number: " + dbConnectionBase._number);
-            }
+            _createdConnections++;
+            dbConnectionBase = (Number: _createdConnections, OdbcConnection: new OdbcConnection(connectionString), OdbcCommands: new ConcurrentStack<OdbcCommand>());
          }
 
          return dbConnectionBase;
@@ -38,24 +24,7 @@ namespace appMpower.Orm.Data
 
       internal static void Release((int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands) dbConnectionBase)
       {
-         TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)> taskCompletionSource;
-
-         if (_waitingQueue.TryDequeue(out taskCompletionSource))
-         {
-            taskCompletionSource.SetResult(dbConnectionBase);
-         }
-         else
-         {
-            _connectionsStack.Push(dbConnectionBase);
-         }
-      }
-
-      private static Task<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)> GetDbConnectionBaseAsync()
-      {
-         var taskCompletionSource = new TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)>(TaskCreationOptions.RunContinuationsAsynchronously);
-
-         _waitingQueue.Enqueue(taskCompletionSource);
-         return taskCompletionSource.Task;
+         _connectionsStack.Push(dbConnectionBase);
       }
    }
 }

+ 4 - 35
frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnectionsKeyed.cs

@@ -5,32 +5,18 @@ namespace appMpower.Orm.Data
 {
    internal static class DbConnectionsKeyed
    {
-      private static bool _maxConnectionsCreated = false;
       private static short _createdConnections = 0;
-      private static short _maxConnections = 500;
 
       private static ConcurrentStack<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)> _connectionsStack = new();
-      private static ConcurrentQueue<TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)>> _waitingQueue = new();
 
-      internal static async Task<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand> KeyedOdbcCommands)> GetConnectionBase(string connectionString)
+      internal static (int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand> KeyedOdbcCommands) GetConnectionBase(string connectionString)
       {
          (int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand> KeyedOdbcCommands) dbConnectionBase;
 
          if (!_connectionsStack.TryPop(out dbConnectionBase))
          {
-            if (_maxConnectionsCreated)
-            {
-               dbConnectionBase = await GetDbConnectionBaseAsync();
-            }
-            else
-            {
-               _createdConnections++;
-               dbConnectionBase = (Number: _maxConnections, OdbcConnection: new OdbcConnection(connectionString), KeyedOdbcCommands: new Dictionary<string, OdbcCommand>());
-
-               if (_createdConnections == _maxConnections) _maxConnectionsCreated = true;
-
-               //Console.WriteLine("opened connection number: " + dbConnectionBase._number);
-            }
+            _createdConnections++;
+            dbConnectionBase = (Number: _createdConnections, OdbcConnection: new OdbcConnection(connectionString), KeyedOdbcCommands: new Dictionary<string, OdbcCommand>());
          }
 
          return dbConnectionBase;
@@ -38,24 +24,7 @@ namespace appMpower.Orm.Data
 
       internal static void Release((int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand> KeyedOdbcCommands) dbConnectionBase)
       {
-         TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)> taskCompletionSource;
-
-         if (_waitingQueue.TryDequeue(out taskCompletionSource))
-         {
-            taskCompletionSource.SetResult(dbConnectionBase);
-         }
-         else
-         {
-            _connectionsStack.Push(dbConnectionBase);
-         }
-      }
-
-      private static Task<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)> GetDbConnectionBaseAsync()
-      {
-         var taskCompletionSource = new TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)>(TaskCreationOptions.RunContinuationsAsynchronously);
-
-         _waitingQueue.Enqueue(taskCompletionSource);
-         return taskCompletionSource.Task;
+         _connectionsStack.Push(dbConnectionBase);
       }
    }
 }

+ 14 - 2
frameworks/CSharp/appmpower/src/appMpower/Middleware/CachingMiddelware.cs

@@ -46,7 +46,13 @@ public class CachingMiddleware
             {
                bytePointer = NativeMethods.DbById(i, out payloadLength, out handlePointer);
                json = new byte[payloadLength];
-               Marshal.Copy(bytePointer, json, 0, payloadLength);
+               //Marshal.Copy(bytePointer, json, 0, payloadLength);
+
+               fixed (byte* dest = json)
+               {
+                  Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength);
+               }
+
                NativeMethods.FreeHandlePointer(handlePointer);
                _cache.Add(i, json);
             }
@@ -72,7 +78,13 @@ public class CachingMiddleware
             {
                bytePointer = NativeMethods.DbById(keys[i], out payloadLength, out handlePointer);
                json = new byte[payloadLength];
-               Marshal.Copy(bytePointer, json, 0, payloadLength);
+               //Marshal.Copy(bytePointer, json, 0, payloadLength);
+
+               fixed (byte* dest = json)
+               {
+                  Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength);
+               }
+
                NativeMethods.FreeHandlePointer(handlePointer);
                _cache.Add(keys[i], json);
             }

+ 6 - 1
frameworks/CSharp/appmpower/src/appMpower/Middleware/FortunesMiddleware.cs

@@ -70,7 +70,12 @@ public class FortunesMiddleware
             */
 
             byte[] byteArray = new byte[payloadLength];
-            Marshal.Copy(bytePointer, byteArray, 0, payloadLength);
+            //Marshal.Copy(bytePointer, json, 0, payloadLength);
+
+            fixed (byte* dest = byteArray)
+            {
+                Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength);
+            }
 
             List<Fortune> fortunes = new List<Fortune>();
 

+ 7 - 1
frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleQueriesMiddleware.cs

@@ -40,7 +40,13 @@ public class MultipleQueriesMiddleware
 
          IntPtr bytePointer = NativeMethods.Query(queries, out payloadLength, out handlePointer);
          byte[] json = new byte[payloadLength];
-         Marshal.Copy(bytePointer, json, 0, payloadLength);
+         //Marshal.Copy(bytePointer, json, 0, payloadLength);
+
+         fixed (byte* dest = json)
+         {
+               Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength);
+         }
+
          NativeMethods.FreeHandlePointer(handlePointer);
 
          response.Headers.Add(

+ 7 - 1
frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleUpdatesMiddleware.cs

@@ -40,7 +40,13 @@ public class MultipleUpdatesMiddelware
 
          IntPtr bytePointer = NativeMethods.Updates(count, out payloadLength, out handlePointer);
          byte[] json = new byte[payloadLength];
-         Marshal.Copy(bytePointer, json, 0, payloadLength);
+         //Marshal.Copy(bytePointer, json, 0, payloadLength);
+
+         fixed (byte* dest = json)
+         {
+               Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength);
+         }
+
          NativeMethods.FreeHandlePointer(handlePointer);
 
          response.Headers.Add(

+ 7 - 1
frameworks/CSharp/appmpower/src/appMpower/Middleware/SingleQueryMiddleware.cs

@@ -35,7 +35,13 @@ public class SingleQueryMiddleware
 
             IntPtr bytePointer = NativeMethods.Db(out payloadLength, out handlePointer);
             byte[] json = new byte[payloadLength];
-            Marshal.Copy(bytePointer, json, 0, payloadLength);
+            //Marshal.Copy(bytePointer, json, 0, payloadLength);
+
+            fixed (byte* dest = json)
+            {
+                Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength);
+            }
+
             NativeMethods.FreeHandlePointer(handlePointer);
 
             response.Headers.Add(