From 34e8cc474bc57f9ec0db6a0f5a0d27739e14c2f5 Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Wed, 28 Jul 2021 21:53:15 +0100 Subject: [PATCH] cache delegates for non query and xml reader calls --- .../Microsoft/Data/SqlClient/SqlCommand.cs | 95 ++++++++++++------- .../Microsoft/Data/SqlClient/SqlCommand.cs | 89 +++++++++++------ 2 files changed, 124 insertions(+), 60 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs index 16d707f3fd..710c76dcf4 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -29,6 +29,8 @@ public sealed partial class SqlCommand : DbCommand, ICloneable private static int _objectTypeCount; // EventSource Counter internal readonly int ObjectID = Interlocked.Increment(ref _objectTypeCount); private string _commandText; + // these static delegates are used to avoid per-call instance delegate allocations. + // They work by storing a delegate to a static function which takes the instance as a parameter, unpacks it and makes the call. private static readonly Func s_beginExecuteReaderAsync = BeginExecuteReaderAsyncCallback; private static readonly Func s_endExecuteReaderAsync = EndExecuteReaderAsyncCallback; private static readonly Action> s_cleanupExecuteReaderAsync = CleanupExecuteReaderAsyncCallback; @@ -37,6 +39,10 @@ public sealed partial class SqlCommand : DbCommand, ICloneable private static readonly Func s_beginExecuteReaderInternal = BeginExecuteReaderInternalCallback; private static readonly Func s_beginExecuteXmlReaderInternal = BeginExecuteXmlReaderInternalCallback; private static readonly Func s_beginExecuteNonQueryInternal = BeginExecuteNonQueryInternalCallback; + private static readonly Func s_beginExecuteNonQueryAsync = BeginExecuteNonQueryAsyncCallback; + private static readonly Func s_endExecuteNonQueryAsync = EndExecuteNonQueryAsyncCallback; + private static readonly Func s_beginExecuteXmlReaderAsync = BeginExecuteXmlReaderAsyncCallback; + private static readonly Func s_endExecuteXmlReaderAsync = EndExecuteXmlReaderAsyncCallback; internal sealed class ExecuteReaderAsyncCallContext : AAsyncCallContext { @@ -1177,6 +1183,11 @@ public IAsyncResult BeginExecuteNonQuery(AsyncCallback callback, object stateObj return BeginExecuteNonQueryInternal(0, callback, stateObject, 0, inRetry: false); } + private static IAsyncResult BeginExecuteNonQueryAsyncCallback(AsyncCallback callback, object stateObject) + { + return ((SqlCommand)stateObject).BeginExecuteNonQueryAsync(callback, stateObject); + } + private IAsyncResult BeginExecuteNonQueryAsync(AsyncCallback callback, object stateObject) { SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlCommand.BeginExecuteNonQueryAsync | API | Correlation | Object Id {0}, Activity Id {1}, Client Connection Id {2}, Command Text '{3}'", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId, CommandText); @@ -1387,6 +1398,11 @@ private void ThrowIfReconnectionHasBeenCanceled() } } + private static int EndExecuteNonQueryAsyncCallback(IAsyncResult asyncResult) + { + return ((SqlCommand)asyncResult.AsyncState).EndExecuteNonQueryAsync(asyncResult); + } + /// public int EndExecuteNonQueryAsync(IAsyncResult asyncResult) { @@ -1684,6 +1700,10 @@ public IAsyncResult BeginExecuteXmlReader(AsyncCallback callback, object stateOb return BeginExecuteXmlReaderInternal(CommandBehavior.SequentialAccess, callback, stateObject, 0, inRetry: false); } + private static IAsyncResult BeginExecuteXmlReaderAsyncCallback(AsyncCallback callback, object stateObject) + { + return ((SqlCommand)stateObject).BeginExecuteXmlReaderAsync(callback, stateObject); + } private IAsyncResult BeginExecuteXmlReaderAsync(AsyncCallback callback, object stateObject) { SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlCommand.BeginExecuteXmlReaderAsync | API | Correlation | Object Id {0}, Activity Id {1}, Client Connection Id {2}, Command Text '{3}'", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId, CommandText); @@ -1809,6 +1829,11 @@ public XmlReader EndExecuteXmlReader(IAsyncResult asyncResult) } } + private static XmlReader EndExecuteXmlReaderAsyncCallback(IAsyncResult asyncResult) + { + return ((SqlCommand)asyncResult.AsyncState).EndExecuteXmlReaderAsync(asyncResult); + } + private XmlReader EndExecuteXmlReaderAsync(IAsyncResult asyncResult) { SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlCommand.EndExecuteXmlReaderAsync | API | Correlation | Object Id {0}, Activity Id {1}, Client Connection Id {2}, Command Text '{3}'", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId, CommandText); @@ -2478,28 +2503,31 @@ private Task InternalExecuteNonQueryAsync(CancellationToken cancellationTok { returnedTask = RegisterForConnectionCloseNotification(returnedTask); - Task.Factory.FromAsync(BeginExecuteNonQueryAsync, EndExecuteNonQueryAsync, null).ContinueWith((t) => - { - registration.Dispose(); - if (t.IsFaulted) - { - Exception e = t.Exception.InnerException; - _diagnosticListener.WriteCommandError(operationId, this, _transaction, e); - source.SetException(e); - } - else + Task.Factory.FromAsync(s_beginExecuteNonQueryAsync, s_endExecuteNonQueryAsync, this).ContinueWith( + (Task t) => { - if (t.IsCanceled) + registration.Dispose(); + if (t.IsFaulted) { - source.SetCanceled(); + Exception e = t.Exception.InnerException; + _diagnosticListener.WriteCommandError(operationId, this, _transaction, e); + source.SetException(e); } else { - source.SetResult(t.Result); + if (t.IsCanceled) + { + source.SetCanceled(); + } + else + { + source.SetResult(t.Result); + } + _diagnosticListener.WriteCommandAfter(operationId, this, _transaction); } - _diagnosticListener.WriteCommandAfter(operationId, this, _transaction); - } - }, TaskScheduler.Default); + }, + TaskScheduler.Default + ); } catch (Exception e) { @@ -2755,28 +2783,31 @@ private Task InternalExecuteXmlReaderAsync(CancellationToken cancella { returnedTask = RegisterForConnectionCloseNotification(returnedTask); - Task.Factory.FromAsync(BeginExecuteXmlReaderAsync, EndExecuteXmlReaderAsync, null).ContinueWith((t) => - { - registration.Dispose(); - if (t.IsFaulted) + Task.Factory.FromAsync(s_beginExecuteXmlReaderAsync, s_endExecuteXmlReaderAsync, this).ContinueWith( + (Task t) => { - Exception e = t.Exception.InnerException; - _diagnosticListener.WriteCommandError(operationId, this, _transaction, e); - source.SetException(e); - } - else - { - if (t.IsCanceled) + registration.Dispose(); + if (t.IsFaulted) { - source.SetCanceled(); + Exception e = t.Exception.InnerException; + _diagnosticListener.WriteCommandError(operationId, this, _transaction, e); + source.SetException(e); } else { - source.SetResult(t.Result); + if (t.IsCanceled) + { + source.SetCanceled(); + } + else + { + source.SetResult(t.Result); + } + _diagnosticListener.WriteCommandAfter(operationId, this, _transaction); } - _diagnosticListener.WriteCommandAfter(operationId, this, _transaction); - } - }, TaskScheduler.Default); + }, + TaskScheduler.Default + ); } catch (Exception e) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs index a4de7ead2b..f5ba19a598 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -40,6 +40,13 @@ public sealed class SqlCommand : DbCommand, ICloneable private static int _objectTypeCount; // EventSource Counter internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); + // these static delegates are used to avoid per-call instance delegate allocations. + // They work by storing a delegate to a static function which takes the instance as a parameter, unpacks it and makes the call. + private static readonly Func s_beginExecuteNonQueryAsync = BeginExecuteNonQueryAsyncCallback; + private static readonly Func s_endExecuteNonQueryAsync = EndExecuteNonQueryAsyncCallback; + private static readonly Func s_beginExecuteXmlReaderAsync = BeginExecuteXmlReaderAsyncCallback; + private static readonly Func s_endExecuteXmlReaderAsync = EndExecuteXmlReaderAsyncCallback; + private string _commandText; private CommandType _commandType; private int? _commandTimeout; @@ -1511,6 +1518,11 @@ public IAsyncResult BeginExecuteNonQuery(AsyncCallback callback, object stateObj return BeginExecuteNonQueryInternal(0, callback, stateObject, 0, inRetry: false); } + private static IAsyncResult BeginExecuteNonQueryAsyncCallback(AsyncCallback callback, object stateObject) + { + return ((SqlCommand)stateObject).BeginExecuteNonQueryAsync(callback, stateObject); + } + private IAsyncResult BeginExecuteNonQueryAsync(AsyncCallback callback, object stateObject) { return BeginExecuteNonQueryInternal(0, callback, stateObject, CommandTimeout, inRetry: false, asyncWrite: true); @@ -1745,6 +1757,11 @@ private void ThrowIfReconnectionHasBeenCanceled() } } + private static int EndExecuteNonQueryAsyncCallback(IAsyncResult asyncResult) + { + return ((SqlCommand)asyncResult.AsyncState).EndExecuteNonQueryAsync(asyncResult); + } + private int EndExecuteNonQueryAsync(IAsyncResult asyncResult) { SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); @@ -2106,6 +2123,11 @@ public IAsyncResult BeginExecuteXmlReader(AsyncCallback callback, object stateOb return BeginExecuteXmlReaderInternal(CommandBehavior.SequentialAccess, callback, stateObject, 0, inRetry: false); } + private static IAsyncResult BeginExecuteXmlReaderAsyncCallback(AsyncCallback callback, object stateObject) + { + return ((SqlCommand)stateObject).BeginExecuteXmlReaderAsync(callback, stateObject); + } + private IAsyncResult BeginExecuteXmlReaderAsync(AsyncCallback callback, object stateObject) { return BeginExecuteXmlReaderInternal(CommandBehavior.SequentialAccess, callback, stateObject, CommandTimeout, inRetry: false, asyncWrite: true); @@ -2258,6 +2280,11 @@ public XmlReader EndExecuteXmlReader(IAsyncResult asyncResult) } } + private static XmlReader EndExecuteXmlReaderAsyncCallback(IAsyncResult asyncResult) + { + return ((SqlCommand)asyncResult.AsyncState).EndExecuteXmlReaderAsync(asyncResult); + } + private XmlReader EndExecuteXmlReaderAsync(IAsyncResult asyncResult) { SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); @@ -2953,26 +2980,29 @@ private Task InternalExecuteNonQueryAsync(CancellationToken cancellationTok { RegisterForConnectionCloseNotification(ref returnedTask); - Task.Factory.FromAsync(BeginExecuteNonQueryAsync, EndExecuteNonQueryAsync, null).ContinueWith((t) => - { - registration.Dispose(); - if (t.IsFaulted) - { - Exception e = t.Exception.InnerException; - source.SetException(e); - } - else + Task.Factory.FromAsync(s_beginExecuteNonQueryAsync, s_endExecuteNonQueryAsync, this).ContinueWith( + (Task t) => { - if (t.IsCanceled) + registration.Dispose(); + if (t.IsFaulted) { - source.SetCanceled(); + Exception e = t.Exception.InnerException; + source.SetException(e); } else { - source.SetResult(t.Result); + if (t.IsCanceled) + { + source.SetCanceled(); + } + else + { + source.SetResult(t.Result); + } } - } - }, TaskScheduler.Default); + }, + TaskScheduler.Default + ); } catch (Exception e) { @@ -3200,26 +3230,29 @@ private Task InternalExecuteXmlReaderAsync(CancellationToken cancella { RegisterForConnectionCloseNotification(ref returnedTask); - Task.Factory.FromAsync(BeginExecuteXmlReaderAsync, EndExecuteXmlReaderAsync, null).ContinueWith((t) => - { - registration.Dispose(); - if (t.IsFaulted) - { - Exception e = t.Exception.InnerException; - source.SetException(e); - } - else + Task.Factory.FromAsync(s_beginExecuteXmlReaderAsync, s_endExecuteXmlReaderAsync, this).ContinueWith( + (Task t) => { - if (t.IsCanceled) + registration.Dispose(); + if (t.IsFaulted) { - source.SetCanceled(); + Exception e = t.Exception.InnerException; + source.SetException(e); } else { - source.SetResult(t.Result); + if (t.IsCanceled) + { + source.SetCanceled(); + } + else + { + source.SetResult(t.Result); + } } - } - }, TaskScheduler.Default); + }, + TaskScheduler.Default + ); } catch (Exception e) {