From a47e77959dab5e4631d8a40f1975aa597870986c Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Fri, 11 Jun 2021 22:47:45 +0100 Subject: [PATCH 1/5] resolve conflicts --- .../src/Microsoft.Data.SqlClient.csproj | 7 +- .../ConcurrentQueueSemaphore.NetCoreApp.cs | 32 +++++ .../ConcurrentQueueSemaphore.NetStandard.cs | 24 ++++ .../SqlClient/SNI/ConcurrentQueueSemaphore.cs | 44 ++++++ .../SqlClient/SNI/SNIStreams.NetCoreApp.cs | 126 ++++++++++++++++++ .../SqlClient/SNI/SNIStreams.NetStandard.cs | 72 ++++++++++ .../Data/SqlClient/SNI/SNIStreams.cs | 60 +-------- .../src/Microsoft/Data/SqlClient/SqlUtil.cs | 54 +------- 8 files changed, 307 insertions(+), 112 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetCoreApp.cs create mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetStandard.cs create mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.cs create mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.NetCoreApp.cs create mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.NetStandard.cs 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 c5fa057a37..da2d1dcb1b 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -344,6 +344,8 @@ + + @@ -393,6 +395,8 @@ + + @@ -522,6 +526,7 @@ Common\CoreLib\System\Threading\Tasks\TaskToApm.cs + @@ -533,8 +538,8 @@ - + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetCoreApp.cs new file mode 100644 index 0000000000..871893bf58 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetCoreApp.cs @@ -0,0 +1,32 @@ +// 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.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Data.SqlClient.SNI +{ + internal sealed partial class ConcurrentQueueSemaphore + { + public ValueTask WaitAsync(CancellationToken cancellationToken) + { + // try sync wait with 0 which will not block to see if we need to do an async wait + if (_semaphore.Wait(0, cancellationToken)) + { + return new ValueTask(); + } + else + { + var tcs = new TaskCompletionSource(); + _queue.Enqueue(tcs); + _semaphore.WaitAsync().ContinueWith( + continuationAction: s_continuePop, + state: _queue, + cancellationToken: cancellationToken + ); + return new ValueTask(tcs.Task); + } + } + } +} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetStandard.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetStandard.cs new file mode 100644 index 0000000000..d22b1b9c8c --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetStandard.cs @@ -0,0 +1,24 @@ +// 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.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Data.SqlClient.SNI +{ + internal sealed partial class ConcurrentQueueSemaphore + { + public Task WaitAsync(CancellationToken cancellationToken) + { + var tcs = new TaskCompletionSource(); + _queue.Enqueue(tcs); + _semaphore.WaitAsync().ContinueWith( + continuationAction: s_continuePop, + state: _queue, + cancellationToken: cancellationToken + ); + return tcs.Task; + } + } +} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.cs new file mode 100644 index 0000000000..f328059d23 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.cs @@ -0,0 +1,44 @@ +// 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.Collections.Concurrent; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Data.SqlClient.SNI +{ + /// + /// This class implements a FIFO Queue with SemaphoreSlim for ordered execution of parallel tasks. + /// Currently used in Managed SNI (SNISslStream) to override SslStream's WriteAsync implementation. + /// + internal sealed partial class ConcurrentQueueSemaphore + { + private static readonly Action s_continuePop = ContinuePop; + + private readonly SemaphoreSlim _semaphore; + private readonly ConcurrentQueue> _queue = + new ConcurrentQueue>(); + + public ConcurrentQueueSemaphore(int initialCount) + { + _semaphore = new SemaphoreSlim(initialCount); + } + + public void Release() + { + _semaphore.Release(); + } + + private static void ContinuePop(Task task, object state) + { + ConcurrentQueue> queue = (ConcurrentQueue>)state; + if (queue.TryDequeue(out TaskCompletionSource popped)) + { + popped.SetResult(true); + } + } + } + +} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.NetCoreApp.cs new file mode 100644 index 0000000000..6a62e2b9ab --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.NetCoreApp.cs @@ -0,0 +1,126 @@ +// 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.Net.Security; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Net.Sockets; +using System; + +namespace Microsoft.Data.SqlClient.SNI +{ + + internal sealed partial class SNISslStream + { + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + ValueTask valueTask = ReadAsync(new Memory(buffer, offset, count), cancellationToken); + if (valueTask.IsCompletedSuccessfully) + { + return Task.FromResult(valueTask.Result); + } + else + { + return valueTask.AsTask(); + } + } + + public override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) + { + await _readAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { + return await base.ReadAsync(buffer, cancellationToken).ConfigureAwait(false); + } + finally + { + _readAsyncSemaphore.Release(); + } + } + + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + ValueTask valueTask = WriteAsync(new Memory(buffer, offset, count), cancellationToken); + if (valueTask.IsCompletedSuccessfully) + { + return Task.CompletedTask; + } + else + { + return valueTask.AsTask(); + } + } + + public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + await _writeAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { + await base.WriteAsync(buffer, cancellationToken).ConfigureAwait(false); + } + finally + { + _writeAsyncSemaphore.Release(); + } + } + } + + + internal sealed partial class SNINetworkStream + { + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + ValueTask valueTask = ReadAsync(new Memory(buffer, offset, count), cancellationToken); + if (valueTask.IsCompletedSuccessfully) + { + return Task.FromResult(valueTask.Result); + } + else + { + return valueTask.AsTask(); + } + } + + public override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) + { + await _readAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { + return await base.ReadAsync(buffer, cancellationToken).ConfigureAwait(false); + } + finally + { + _readAsyncSemaphore.Release(); + } + } + + // Prevent the WriteAsync collisions by running the task in a Semaphore Slim + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + ValueTask valueTask = WriteAsync(new Memory(buffer, offset, count), cancellationToken); + if (valueTask.IsCompletedSuccessfully) + { + return Task.CompletedTask; + } + else + { + return valueTask.AsTask(); + } + } + + public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + await _writeAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { + await base.WriteAsync(buffer, cancellationToken).ConfigureAwait(false); + } + finally + { + _writeAsyncSemaphore.Release(); + } + } + } +} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.NetStandard.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.NetStandard.cs new file mode 100644 index 0000000000..0a9ab39d7a --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.NetStandard.cs @@ -0,0 +1,72 @@ +// 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.Net.Security; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Net.Sockets; + +namespace Microsoft.Data.SqlClient.SNI +{ + internal sealed partial class SNISslStream + { + public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + await _readAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { + return await base.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + } + finally + { + _readAsyncSemaphore.Release(); + } + } + + public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + await _writeAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { + await base.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + } + finally + { + _writeAsyncSemaphore.Release(); + } + } + } + + internal sealed partial class SNINetworkStream + { + + public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + await _readAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { + return await base.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + } + finally + { + _readAsyncSemaphore.Release(); + } + } + + // Prevent the WriteAsync collisions by running the task in a Semaphore Slim + public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + await _writeAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { + await base.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + } + finally + { + _writeAsyncSemaphore.Release(); + } + } + } +} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.cs index eb8661d022..fbaef7b7ca 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.cs @@ -13,7 +13,7 @@ namespace Microsoft.Data.SqlClient.SNI /// /// This class extends SslStream to customize stream behavior for Managed SNI implementation. /// - internal class SNISslStream : SslStream + internal sealed partial class SNISslStream : SslStream { private readonly ConcurrentQueueSemaphore _writeAsyncSemaphore; private readonly ConcurrentQueueSemaphore _readAsyncSemaphore; @@ -24,40 +24,12 @@ public SNISslStream(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertifi _writeAsyncSemaphore = new ConcurrentQueueSemaphore(1); _readAsyncSemaphore = new ConcurrentQueueSemaphore(1); } - - // Prevent ReadAsync collisions by running the task in a Semaphore Slim - public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - await _readAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - return await base.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); - } - finally - { - _readAsyncSemaphore.Release(); - } - } - - // Prevent the WriteAsync collisions by running the task in a Semaphore Slim - public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - await _writeAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - await base.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); - } - finally - { - _writeAsyncSemaphore.Release(); - } - } } /// /// This class extends NetworkStream to customize stream behavior for Managed SNI implementation. /// - internal class SNINetworkStream : NetworkStream + internal sealed partial class SNINetworkStream : NetworkStream { private readonly ConcurrentQueueSemaphore _writeAsyncSemaphore; private readonly ConcurrentQueueSemaphore _readAsyncSemaphore; @@ -67,33 +39,5 @@ public SNINetworkStream(Socket socket, bool ownsSocket) : base(socket, ownsSocke _writeAsyncSemaphore = new ConcurrentQueueSemaphore(1); _readAsyncSemaphore = new ConcurrentQueueSemaphore(1); } - - // Prevent ReadAsync collisions by running the task in a Semaphore Slim - public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - await _readAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - return await base.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); - } - finally - { - _readAsyncSemaphore.Release(); - } - } - - // Prevent the WriteAsync collisions by running the task in a Semaphore Slim - public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - await _writeAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - await base.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); - } - finally - { - _writeAsyncSemaphore.Release(); - } - } } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs index 46c874ab80..595b9fe499 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs @@ -2164,56 +2164,4 @@ public static MethodInfo GetPromotedToken } } - /// - /// This class implements a FIFO Queue with SemaphoreSlim for ordered execution of parallel tasks. - /// Currently used in Managed SNI (SNISslStream) to override SslStream's WriteAsync implementation. - /// - internal class ConcurrentQueueSemaphore - { - private static readonly Action s_continuePop = ContinuePop; - - private readonly SemaphoreSlim _semaphore; - private readonly ConcurrentQueue> _queue = - new ConcurrentQueue>(); - - public ConcurrentQueueSemaphore(int initialCount) - { - _semaphore = new SemaphoreSlim(initialCount); - } - - public Task WaitAsync(CancellationToken cancellationToken) - { - // try sync wait with 0 which will not block to see if we need to do an async wait - if (_semaphore.Wait(0, cancellationToken)) - { - return Task.CompletedTask; - } - else - { - var tcs = new TaskCompletionSource(); - _queue.Enqueue(tcs); - _semaphore.WaitAsync().ContinueWith( - continuationAction: s_continuePop, - state: _queue, - cancellationToken: cancellationToken - ); - return tcs.Task; - } - } - - public void Release() - { - _semaphore.Release(); - } - - private static void ContinuePop(Task task, object state) - { - ConcurrentQueue> queue = (ConcurrentQueue>)state; - if (queue.TryDequeue(out TaskCompletionSource popped)) - { - popped.SetResult(true); - } - } - } - -}//namespace +} From d3d24c871207ca6583ae79cafdfea7d59734b4a1 Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Tue, 2 Mar 2021 20:42:03 +0000 Subject: [PATCH 2/5] remove ValueTask overrides on netcore2.1 --- .../src/Microsoft.Data.SqlClient.csproj | 4 +++- .../ConcurrentQueueSemaphore.NetStandard.cs | 24 ++++++++++++------- ...eams.NetStandard.cs => SNIStreams.Task.cs} | 9 ++++--- ....NetCoreApp.cs => SNIStreams.ValueTask.cs} | 4 ---- 4 files changed, 25 insertions(+), 16 deletions(-) rename src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/{SNIStreams.NetStandard.cs => SNIStreams.Task.cs} (86%) rename src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/{SNIStreams.NetCoreApp.cs => SNIStreams.ValueTask.cs} (98%) 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 da2d1dcb1b..a4801e0848 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -396,7 +396,8 @@ - + + @@ -831,6 +832,7 @@ + True True diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetStandard.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetStandard.cs index d22b1b9c8c..45b801af51 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetStandard.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetStandard.cs @@ -11,14 +11,22 @@ internal sealed partial class ConcurrentQueueSemaphore { public Task WaitAsync(CancellationToken cancellationToken) { - var tcs = new TaskCompletionSource(); - _queue.Enqueue(tcs); - _semaphore.WaitAsync().ContinueWith( - continuationAction: s_continuePop, - state: _queue, - cancellationToken: cancellationToken - ); - return tcs.Task; + // try sync wait with 0 which will not block to see if we need to do an async wait + if (_semaphore.Wait(0, cancellationToken)) + { + return Task.CompletedTask; + } + else + { + var tcs = new TaskCompletionSource(); + _queue.Enqueue(tcs); + _semaphore.WaitAsync().ContinueWith( + continuationAction: s_continuePop, + state: _queue, + cancellationToken: cancellationToken + ); + return tcs.Task; + } } } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.NetStandard.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.Task.cs similarity index 86% rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.NetStandard.cs rename to src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.Task.cs index 0a9ab39d7a..7ca2ee167e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.NetStandard.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.Task.cs @@ -2,14 +2,17 @@ // 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.Net.Security; -using System.IO; using System.Threading; using System.Threading.Tasks; -using System.Net.Sockets; + namespace Microsoft.Data.SqlClient.SNI { + // NetCore2.1: + // DO NOT OVERRIDE ValueTask versions of ReadAsync and WriteAsync because the underlying SslStream implements them + // by calling the Task versions which are already overridden meaning that if a caller uses Task WriteAsync this would + // call ValueTask WriteAsync which then called TaskWriteAsync introducing a lock cycle and never return + internal sealed partial class SNISslStream { public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.ValueTask.cs similarity index 98% rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.NetCoreApp.cs rename to src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.ValueTask.cs index 6a62e2b9ab..f4fa916d7c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.NetCoreApp.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.ValueTask.cs @@ -2,16 +2,12 @@ // 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.Net.Security; -using System.IO; using System.Threading; using System.Threading.Tasks; -using System.Net.Sockets; using System; namespace Microsoft.Data.SqlClient.SNI { - internal sealed partial class SNISslStream { public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) From 52ebec67cb6f0120824df1adf3c4542437610b92 Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Wed, 7 Apr 2021 19:17:26 +0100 Subject: [PATCH 3/5] fixup project file after rebase --- .../netcore/src/Microsoft.Data.SqlClient.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a4801e0848..9a09fbe986 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -345,7 +345,7 @@ - + From 001e995ee597fab103299fb862c21455b085057a Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Wed, 16 Jun 2021 21:05:28 +0100 Subject: [PATCH 4/5] address feedback --- .../netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.Task.cs | 2 -- .../netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.cs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.Task.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.Task.cs index 7ca2ee167e..74b1206fa5 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.Task.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.Task.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Threading.Tasks; - namespace Microsoft.Data.SqlClient.SNI { // NetCore2.1: @@ -44,7 +43,6 @@ public override async Task WriteAsync(byte[] buffer, int offset, int count, Canc internal sealed partial class SNINetworkStream { - public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { await _readAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.cs index fbaef7b7ca..389f25eeae 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.cs @@ -4,8 +4,6 @@ using System.Net.Security; using System.IO; -using System.Threading; -using System.Threading.Tasks; using System.Net.Sockets; namespace Microsoft.Data.SqlClient.SNI From 4d612cc78f1be08b270d8e12e55547f325764069 Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Thu, 17 Jun 2021 19:34:19 +0100 Subject: [PATCH 5/5] address feedback --- .../src/Microsoft.Data.SqlClient.csproj | 2 - .../ConcurrentQueueSemaphore.NetCoreApp.cs | 32 --------------- .../ConcurrentQueueSemaphore.NetStandard.cs | 32 --------------- .../SqlClient/SNI/ConcurrentQueueSemaphore.cs | 40 ++++++++++++------ .../SqlClient/SNI/SNIStreams.ValueTask.cs | 41 ++----------------- 5 files changed, 32 insertions(+), 115 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetCoreApp.cs delete mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetStandard.cs 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 9a09fbe986..c7aa33c85a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -344,7 +344,6 @@ - @@ -395,7 +394,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetCoreApp.cs deleted file mode 100644 index 871893bf58..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetCoreApp.cs +++ /dev/null @@ -1,32 +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.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Data.SqlClient.SNI -{ - internal sealed partial class ConcurrentQueueSemaphore - { - public ValueTask WaitAsync(CancellationToken cancellationToken) - { - // try sync wait with 0 which will not block to see if we need to do an async wait - if (_semaphore.Wait(0, cancellationToken)) - { - return new ValueTask(); - } - else - { - var tcs = new TaskCompletionSource(); - _queue.Enqueue(tcs); - _semaphore.WaitAsync().ContinueWith( - continuationAction: s_continuePop, - state: _queue, - cancellationToken: cancellationToken - ); - return new ValueTask(tcs.Task); - } - } - } -} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetStandard.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetStandard.cs deleted file mode 100644 index 45b801af51..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.NetStandard.cs +++ /dev/null @@ -1,32 +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.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Data.SqlClient.SNI -{ - internal sealed partial class ConcurrentQueueSemaphore - { - public Task WaitAsync(CancellationToken cancellationToken) - { - // try sync wait with 0 which will not block to see if we need to do an async wait - if (_semaphore.Wait(0, cancellationToken)) - { - return Task.CompletedTask; - } - else - { - var tcs = new TaskCompletionSource(); - _queue.Enqueue(tcs); - _semaphore.WaitAsync().ContinueWith( - continuationAction: s_continuePop, - state: _queue, - cancellationToken: cancellationToken - ); - return tcs.Task; - } - } - } -} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.cs index f328059d23..46d3b70a25 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/ConcurrentQueueSemaphore.cs @@ -15,29 +15,45 @@ namespace Microsoft.Data.SqlClient.SNI /// internal sealed partial class ConcurrentQueueSemaphore { - private static readonly Action s_continuePop = ContinuePop; - private readonly SemaphoreSlim _semaphore; - private readonly ConcurrentQueue> _queue = - new ConcurrentQueue>(); + private readonly ConcurrentQueue> _queue; public ConcurrentQueueSemaphore(int initialCount) { _semaphore = new SemaphoreSlim(initialCount); + _queue = new ConcurrentQueue>(); } - public void Release() + public Task WaitAsync(CancellationToken cancellationToken) { - _semaphore.Release(); + // try sync wait with 0 which will not block to see if we need to do an async wait + if (_semaphore.Wait(0, cancellationToken)) + { + return Task.CompletedTask; + } + else + { + var tcs = new TaskCompletionSource(); + _queue.Enqueue(tcs); + _semaphore.WaitAsync().ContinueWith( + continuationAction: static (Task task, object state) => + { + ConcurrentQueue> queue = (ConcurrentQueue>)state; + if (queue.TryDequeue(out TaskCompletionSource popped)) + { + popped.SetResult(true); + } + }, + state: _queue, + cancellationToken: cancellationToken + ); + return tcs.Task; + } } - private static void ContinuePop(Task task, object state) + public void Release() { - ConcurrentQueue> queue = (ConcurrentQueue>)state; - if (queue.TryDequeue(out TaskCompletionSource popped)) - { - popped.SetResult(true); - } + _semaphore.Release(); } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.ValueTask.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.ValueTask.cs index f4fa916d7c..5779304608 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.ValueTask.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.ValueTask.cs @@ -12,15 +12,7 @@ internal sealed partial class SNISslStream { public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - ValueTask valueTask = ReadAsync(new Memory(buffer, offset, count), cancellationToken); - if (valueTask.IsCompletedSuccessfully) - { - return Task.FromResult(valueTask.Result); - } - else - { - return valueTask.AsTask(); - } + return ReadAsync(new Memory(buffer, offset, count), cancellationToken).AsTask(); } public override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) @@ -38,15 +30,7 @@ public override async ValueTask ReadAsync(Memory buffer, Cancellation public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - ValueTask valueTask = WriteAsync(new Memory(buffer, offset, count), cancellationToken); - if (valueTask.IsCompletedSuccessfully) - { - return Task.CompletedTask; - } - else - { - return valueTask.AsTask(); - } + return WriteAsync(new Memory(buffer, offset, count), cancellationToken).AsTask(); } public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) @@ -63,20 +47,11 @@ public override async ValueTask WriteAsync(ReadOnlyMemory buffer, Cancella } } - internal sealed partial class SNINetworkStream { public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - ValueTask valueTask = ReadAsync(new Memory(buffer, offset, count), cancellationToken); - if (valueTask.IsCompletedSuccessfully) - { - return Task.FromResult(valueTask.Result); - } - else - { - return valueTask.AsTask(); - } + return ReadAsync(new Memory(buffer, offset, count), cancellationToken).AsTask(); } public override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) @@ -95,15 +70,7 @@ public override async ValueTask ReadAsync(Memory buffer, Cancellation // Prevent the WriteAsync collisions by running the task in a Semaphore Slim public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - ValueTask valueTask = WriteAsync(new Memory(buffer, offset, count), cancellationToken); - if (valueTask.IsCompletedSuccessfully) - { - return Task.CompletedTask; - } - else - { - return valueTask.AsTask(); - } + return WriteAsync(new Memory(buffer, offset, count), cancellationToken).AsTask(); } public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default)