Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Fixed ReadAsync blocking issue (#26595)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gene Lee committed Jan 31, 2018
1 parent 4852538 commit da8a105
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
144 changes: 77 additions & 67 deletions src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,94 +2,104 @@
// 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;

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<SqlDataReader> 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<double> 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<double> 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<int> 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<bool> 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<SqlDataReader> 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;
}
}
}

0 comments on commit da8a105

Please sign in to comment.