From f6233e4ca716dfd06c34aae30d4b697966084575 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Wed, 12 Feb 2020 12:19:13 -0800 Subject: [PATCH 1/3] [Release 1.1] Revert Async changes to SNIPacket to fix deadlock issues + Update SNI Reference --- README.md | 4 - .../src/Microsoft.Data.SqlClient.csproj | 2 - .../SqlClient/SNI/SNIPacket.NetCoreApp.cs | 125 ------------------ .../SqlClient/SNI/SNIPacket.NetStandard.cs | 120 ----------------- .../Microsoft/Data/SqlClient/SNI/SNIPacket.cs | 71 +++++++++- .../netfx/src/Microsoft.Data.SqlClient.csproj | 2 +- tools/specs/Microsoft.Data.SqlClient.nuspec | 5 +- 7 files changed, 72 insertions(+), 257 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.NetCoreApp.cs delete mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.NetStandard.cs diff --git a/README.md b/README.md index d03249aeab..ff01c4bf76 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,6 @@ For the .NET Framework driver on Windows, a package reference to [Microsoft.Data For the .NET Core driver on Windows, a package reference to [runtime.native.System.Data.SqlClient.sni](https://www.nuget.org/packages/runtime.native.System.Data.SqlClient.sni/) loads `arm64`, `x64` and `x86` native `SNI.dll` libraries into the client's build directories. -**Note** -When referencing the native `SNI.dll` on Windows, the Microsoft Visual C++ Redistributable is required to be installed: [The latest supported Visual C++ downloads](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads) - - ## Helpful Links | Topic | Link to File | diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index b0a0b70040..481308bd83 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -44,7 +44,6 @@ - @@ -56,7 +55,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.NetCoreApp.cs deleted file mode 100644 index e6a35caeda..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.NetCoreApp.cs +++ /dev/null @@ -1,125 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Data.SqlClient.SNI -{ - internal partial class SNIPacket - { - /// - /// Read data from a stream asynchronously - /// - /// Stream to read from - /// Completion callback - public void ReadFromStreamAsync(Stream stream, SNIAsyncCallback callback) - { - // Treat local function as a static and pass all params otherwise as async will allocate - async Task ReadFromStreamAsync(SNIPacket packet, SNIAsyncCallback cb, ValueTask valueTask) - { - bool error = false; - try - { - packet._length = await valueTask.ConfigureAwait(false); - if (packet._length == 0) - { - SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, 0, SNICommon.ConnTerminatedError, string.Empty); - error = true; - } - } - catch (Exception ex) - { - SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, SNICommon.InternalExceptionError, ex); - error = true; - } - - if (error) - { - packet.Release(); - } - - cb(packet, error ? TdsEnums.SNI_ERROR : TdsEnums.SNI_SUCCESS); - } - - ValueTask vt = stream.ReadAsync(new Memory(_data, 0, _capacity), CancellationToken.None); - - if (vt.IsCompletedSuccessfully) - { - _length = vt.Result; - // Zero length to go via async local function as is error condition - if (_length > 0) - { - callback(this, TdsEnums.SNI_SUCCESS); - - // Completed - return; - } - else - { - // Avoid consuming the same instance twice. - vt = new ValueTask(_length); - } - } - - // Not complete or error call the async local function to complete - _ = ReadFromStreamAsync(this, callback, vt); - } - - /// - /// Write data to a stream asynchronously - /// - /// Stream to write to - /// - /// - /// - public void WriteToStreamAsync(Stream stream, SNIAsyncCallback callback, SNIProviders provider, bool disposeAfterWriteAsync = false) - { - // Treat local function as a static and pass all params otherwise as async will allocate - async Task WriteToStreamAsync(SNIPacket packet, SNIAsyncCallback cb, SNIProviders providers, bool disposeAfter, ValueTask valueTask) - { - uint status = TdsEnums.SNI_SUCCESS; - try - { - await valueTask.ConfigureAwait(false); - } - catch (Exception e) - { - SNILoadHandle.SingletonInstance.LastError = new SNIError(providers, SNICommon.InternalExceptionError, e); - status = TdsEnums.SNI_ERROR; - } - - cb(packet, status); - - if (disposeAfter) - { - packet.Dispose(); - } - } - - ValueTask vt = stream.WriteAsync(new Memory(_data, 0, _length), CancellationToken.None); - - if (vt.IsCompletedSuccessfully) - { - // Read the result to register as complete for the ValueTask - vt.GetAwaiter().GetResult(); - - callback(this, TdsEnums.SNI_SUCCESS); - - if (disposeAfterWriteAsync) - { - Dispose(); - } - - // Completed - return; - } - - // Not complete or error call the async local function to complete - _ = WriteToStreamAsync(this, callback, provider, disposeAfterWriteAsync, vt); - } - } -} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.NetStandard.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.NetStandard.cs deleted file mode 100644 index 2a3cf12670..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.NetStandard.cs +++ /dev/null @@ -1,120 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Data.SqlClient.SNI -{ - internal partial class SNIPacket - { - /// - /// Read data from a stream asynchronously - /// - /// Stream to read from - /// Completion callback - public void ReadFromStreamAsync(Stream stream, SNIAsyncCallback callback) - { - // Treat local function as a static and pass all params otherwise as async will allocate - async Task ReadFromStreamAsync(SNIPacket packet, SNIAsyncCallback cb, Task task) - { - bool error = false; - try - { - packet._length = await task.ConfigureAwait(false); - if (packet._length == 0) - { - SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, 0, SNICommon.ConnTerminatedError, string.Empty); - error = true; - } - } - catch (Exception ex) - { - SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, SNICommon.InternalExceptionError, ex); - error = true; - } - - if (error) - { - packet.Release(); - } - - cb(packet, error ? TdsEnums.SNI_ERROR : TdsEnums.SNI_SUCCESS); - } - - Task t = stream.ReadAsync(_data, 0, _capacity, CancellationToken.None); - - if ((t.Status & TaskStatus.RanToCompletion) != 0) - { - _length = t.Result; - // Zero length to go via async local function as is error condition - if (_length > 0) - { - callback(this, TdsEnums.SNI_SUCCESS); - - // Completed - return; - } - } - - // Not complete or error call the async local function to complete - _ = ReadFromStreamAsync(this, callback, t); - } - - /// - /// Write data to a stream asynchronously - /// - /// Stream to write to - /// - /// - /// - public void WriteToStreamAsync(Stream stream, SNIAsyncCallback callback, SNIProviders provider, bool disposeAfterWriteAsync = false) - { - // Treat local function as a static and pass all params otherwise as async will allocate - async Task WriteToStreamAsync(SNIPacket packet, SNIAsyncCallback cb, SNIProviders providers, bool disposeAfter, Task task) - { - uint status = TdsEnums.SNI_SUCCESS; - try - { - await task.ConfigureAwait(false); - } - catch (Exception e) - { - SNILoadHandle.SingletonInstance.LastError = new SNIError(providers, SNICommon.InternalExceptionError, e); - status = TdsEnums.SNI_ERROR; - } - - cb(packet, status); - - if (disposeAfter) - { - packet.Dispose(); - } - } - - Task t = stream.WriteAsync(_data, 0, _length, CancellationToken.None); - - if ((t.Status & TaskStatus.RanToCompletion) != 0) - { - // Read the result to register as complete for the Task - t.GetAwaiter().GetResult(); - - callback(this, TdsEnums.SNI_SUCCESS); - - if (disposeAfterWriteAsync) - { - Dispose(); - } - - // Completed - return; - } - - // Not complete or error call the async local function to complete - _ = WriteToStreamAsync(this, callback, provider, disposeAfterWriteAsync, t); - } - } -} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.cs index 17437880a2..4467f9b9d5 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.cs @@ -5,13 +5,15 @@ using System; using System.Buffers; using System.IO; +using System.Threading; +using System.Threading.Tasks; namespace Microsoft.Data.SqlClient.SNI { /// /// SNI Packet /// - internal partial class SNIPacket : IDisposable, IEquatable + internal class SNIPacket : IDisposable, IEquatable { private byte[] _data; private int _length; @@ -251,6 +253,46 @@ public void ReadFromStream(Stream stream) _length = stream.Read(_data, 0, _capacity); } + /// + /// Read data from a stream asynchronously + /// + /// Stream to read from + /// Completion callback + public void ReadFromStreamAsync(Stream stream, SNIAsyncCallback callback) + { + bool error = false; + + stream.ReadAsync(_data, 0, _capacity, CancellationToken.None).ContinueWith(t => + { + Exception e = t.Exception?.InnerException; + if (e != null) + { + SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, SNICommon.InternalExceptionError, e); + error = true; + } + else + { + _length = t.Result; + + if (_length == 0) + { + SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, 0, SNICommon.ConnTerminatedError, string.Empty); + error = true; + } + } + + if (error) + { + Release(); + } + + callback(this, error ? TdsEnums.SNI_ERROR : TdsEnums.SNI_SUCCESS); + }, + CancellationToken.None, + TaskContinuationOptions.DenyChildAttach, + TaskScheduler.Default); + } + /// /// Write data to a stream synchronously /// @@ -260,6 +302,33 @@ public void WriteToStream(Stream stream) stream.Write(_data, 0, _length); } + /// + /// Write data to a stream asynchronously + /// + /// Stream to write to + /// SNI Asynchronous Callback + /// SNI provider identifier + /// Bool flag to decide whether or not to dispose after Write Async operation + public async void WriteToStreamAsync(Stream stream, SNIAsyncCallback callback, SNIProviders provider, bool disposeAfterWriteAsync = false) + { + uint status = TdsEnums.SNI_SUCCESS; + try + { + await stream.WriteAsync(_data, 0, _length, CancellationToken.None).ConfigureAwait(false); + } + catch (Exception e) + { + SNILoadHandle.SingletonInstance.LastError = new SNIError(provider, SNICommon.InternalExceptionError, e); + status = TdsEnums.SNI_ERROR; + } + callback(this, status); + + if (disposeAfterWriteAsync) + { + Dispose(); + } + } + /// /// Get hash code /// diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index f6571605f5..428b43aeeb 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -341,7 +341,7 @@ - 1.1.0 + 1.1.* 3.0.8 diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index 7444bcbeb4..02bf9e60f7 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -21,9 +21,6 @@ Microsoft.Data.SqlClient.SqlTransaction Microsoft.Data.SqlClient.SqlParameterCollection Microsoft.Data.SqlClient.SqlClientFactory -When running on Windows, this library has a dependency on Microsoft.Data.SqlClient.SNI on .NET Framework and runtime.native.System.Data.SqlClient.sni on .NET Core, which requires the Microsoft Visual C++ Redistributable to be installed: -https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads - When using NuGet 3.x this package requires at least version 3.4. https://go.microsoft.com/fwlink/?linkid=2090501 © Microsoft Corporation. All rights reserved. @@ -31,7 +28,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + From 7124835a605a4b41aae4cf16a2c22efc9874ee50 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Wed, 12 Feb 2020 15:53:21 -0800 Subject: [PATCH 2/3] No upper bound needed --- tools/specs/Microsoft.Data.SqlClient.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index 02bf9e60f7..bcb7291e8b 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -28,7 +28,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + From d0aa486d3ea49f170d0a240d2409df2e21553afb Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Thu, 13 Feb 2020 10:44:16 -0800 Subject: [PATCH 3/3] Update versions range + remove packages.config to avoid duplicated references. --- .../netfx/src/Microsoft.Data.SqlClient.csproj | 9 +++++++-- src/Microsoft.Data.SqlClient/netfx/src/packages.config | 6 ------ tools/specs/Microsoft.Data.SqlClient.nuspec | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/netfx/src/packages.config diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 428b43aeeb..d768d13a1f 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -84,7 +84,6 @@ - @@ -340,8 +339,14 @@ + + 4.3.1 + + + 4.3.0 + - 1.1.* + [1.1.0,1.2.0) 3.0.8 diff --git a/src/Microsoft.Data.SqlClient/netfx/src/packages.config b/src/Microsoft.Data.SqlClient/netfx/src/packages.config deleted file mode 100644 index fe599d2346..0000000000 --- a/src/Microsoft.Data.SqlClient/netfx/src/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index bcb7291e8b..c9c12b4a5a 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -28,7 +28,7 @@ When using NuGet 3.x this package requires at least version 3.4. - +