From da8a105c39ce4b10406c2da5dfce19269293942b Mon Sep 17 00:00:00 2001 From: Gene Lee Date: Tue, 30 Jan 2018 20:26:44 -0800 Subject: [PATCH] Fixed ReadAsync blocking issue (#26595) --- .../src/System/Data/SqlClient/TdsParser.cs | 3 - .../ManualTests/SQL/AsyncTest/AsyncTest.cs | 144 ++++++++++-------- 2 files changed, 77 insertions(+), 70 deletions(-) diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs index 16e03ce9922c..c1fe67f607b1 100644 --- a/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs +++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs @@ -2499,9 +2499,6 @@ private bool TryProcessDone(SqlCommand cmd, SqlDataReader reader, ref RunBehavio ushort status; int count; - // Can't retry TryProcessDone - stateObj._syncOverAsync = true; - // status // command // rowcount (valid only if DONE_COUNT bit is set) diff --git a/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTest.cs b/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTest.cs index d96fcf493aa2..1c47a5cd3291 100644 --- a/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTest.cs +++ b/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTest.cs @@ -2,6 +2,7 @@ // 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.Diagnostics; using System.Threading.Tasks; using Xunit; @@ -9,87 +10,96 @@ namespace System.Data.SqlClient.ManualTesting.Tests { public static class AsyncTest { - private const int TaskTimeout = 5000; - [CheckConnStrSetupFact] - public static void ExecuteTest() + public static void TestReadAsyncTimeConsumed() { - SqlCommand com = new SqlCommand("select * from Orders"); - SqlConnection con = new SqlConnection(DataTestUtility.TcpConnStr); - - com.Connection = con; - - con.Open(); - - Task readerTask = com.ExecuteReaderAsync(); - bool taskCompleted = readerTask.Wait(TaskTimeout); - Assert.True(taskCompleted, "FAILED: ExecuteReaderAsync Task did not complete successfully."); - - SqlDataReader reader = readerTask.Result; - - int rows; - for (rows = 0; reader.Read(); rows++) ; - - Assert.True(rows == 830, string.Format("FAILED: ExecuteTest reader had wrong number of rows. Expected: {0}. Actual: {1}", 830, rows)); - - reader.Dispose(); - con.Close(); + const string sql = "SET NOCOUNT ON" + + " SELECT 'a'" + + " DECLARE @t DATETIME = SYSDATETIME()" + + " WHILE DATEDIFF(s, @t, SYSDATETIME()) < 20 BEGIN" + + " SELECT 2 x INTO #y" + + " DROP TABLE #y" + + " END" + + " SELECT 'b'"; + Task t = RunReadAsync(sql); + double elapsedSync = RunReadSync(sql); + t.Wait(); + double elapsedAsync = t.Result; + Assert.True(elapsedAsync < elapsedSync, "Asynchronous operation should be finished quicker than synchronous one"); + int limit = 100; + Assert.True(elapsedAsync < limit, $"Asynchronous operation should be finished within {limit}ms"); } - [CheckConnStrSetupFact] - public static void FailureTest() + private static async Task RunReadAsync(string sql) { - bool failure = false; - bool taskCompleted = false; - - SqlCommand com = new SqlCommand("select * from Orders"); - SqlConnection con = new SqlConnection((new SqlConnectionStringBuilder(DataTestUtility.TcpConnStr) { Pooling = false }).ConnectionString); - com.Connection = con; - con.Open(); - - Task nonQueryTask = com.ExecuteNonQueryAsync(); - try + double maxElapsedTimeMillisecond = 0; + using (SqlConnection connection = new SqlConnection(DataTestUtility.TcpConnStr)) { - com.ExecuteNonQueryAsync().Wait(TaskTimeout); - } - catch (AggregateException agrEx) - { - agrEx.Handle( - (ex) => + await connection.OpenAsync(); + using (SqlCommand command = connection.CreateCommand()) + { + command.CommandText = sql; + using (SqlDataReader reader = await command.ExecuteReaderAsync()) { - Assert.True(ex is InvalidOperationException, "FAILED: Thrown exception for ExecuteNonQueryAsync was not an InvalidOperationException"); - failure = true; - return true; - }); + Task t; + Stopwatch stopwatch = new Stopwatch(); + do + { + do + { + stopwatch.Start(); + t = reader.ReadAsync(); + stopwatch.Stop(); + double elased = stopwatch.Elapsed.TotalMilliseconds; + if (maxElapsedTimeMillisecond < elased) + { + maxElapsedTimeMillisecond = elased; + } + } + while (await t); + } + while (reader.NextResult()); + } + } } - Assert.True(failure, "FAILED: No exception thrown after trying second ExecuteNonQueryAsync."); - failure = false; - taskCompleted = nonQueryTask.Wait(TaskTimeout); - Assert.True(taskCompleted, "FAILED: ExecuteNonQueryAsync Task did not complete successfully."); + return maxElapsedTimeMillisecond; + } - Task readerTask = com.ExecuteReaderAsync(); - try - { - com.ExecuteReaderAsync().Wait(TaskTimeout); - } - catch (AggregateException agrEx) + private static double RunReadSync(string sql) + { + double maxElapsedTimeMillisecond = 0; + using (SqlConnection connection = new SqlConnection(DataTestUtility.TcpConnStr)) { - agrEx.Handle( - (ex) => + connection.Open(); + using (SqlCommand command = connection.CreateCommand()) + { + command.CommandText = sql; + using (SqlDataReader reader = command.ExecuteReader()) { - Assert.True(ex is InvalidOperationException, "FAILED: Thrown exception for ExecuteReaderAsync was not an InvalidOperationException: " + ex); - failure = true; - return true; - }); + bool result; + Stopwatch stopwatch = new Stopwatch(); + do + { + do + { + stopwatch.Start(); + result = reader.Read(); + stopwatch.Stop(); + double elased = stopwatch.Elapsed.TotalMilliseconds; + if (maxElapsedTimeMillisecond < elased) + { + maxElapsedTimeMillisecond = elased; + } + } + while (result); + } + while (reader.NextResult()); + } + } } - Assert.True(failure, "FAILED: No exception thrown after trying second ExecuteReaderAsync."); - - taskCompleted = readerTask.Wait(TaskTimeout); - Assert.True(taskCompleted, "FAILED: ExecuteReaderAsync Task did not complete successfully."); - readerTask.Result.Dispose(); - con.Close(); + return maxElapsedTimeMillisecond; } } } \ No newline at end of file