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

Commit da8a105

Browse files
author
Gene Lee
authored
Fixed ReadAsync blocking issue (#26595)
1 parent 4852538 commit da8a105

File tree

2 files changed

+77
-70
lines changed

2 files changed

+77
-70
lines changed

src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs

-3
Original file line numberDiff line numberDiff line change
@@ -2499,9 +2499,6 @@ private bool TryProcessDone(SqlCommand cmd, SqlDataReader reader, ref RunBehavio
24992499
ushort status;
25002500
int count;
25012501

2502-
// Can't retry TryProcessDone
2503-
stateObj._syncOverAsync = true;
2504-
25052502
// status
25062503
// command
25072504
// rowcount (valid only if DONE_COUNT bit is set)

src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTest.cs

+77-67
Original file line numberDiff line numberDiff line change
@@ -2,94 +2,104 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System.Diagnostics;
56
using System.Threading.Tasks;
67
using Xunit;
78

89
namespace System.Data.SqlClient.ManualTesting.Tests
910
{
1011
public static class AsyncTest
1112
{
12-
private const int TaskTimeout = 5000;
13-
1413
[CheckConnStrSetupFact]
15-
public static void ExecuteTest()
14+
public static void TestReadAsyncTimeConsumed()
1615
{
17-
SqlCommand com = new SqlCommand("select * from Orders");
18-
SqlConnection con = new SqlConnection(DataTestUtility.TcpConnStr);
19-
20-
com.Connection = con;
21-
22-
con.Open();
23-
24-
Task<SqlDataReader> readerTask = com.ExecuteReaderAsync();
25-
bool taskCompleted = readerTask.Wait(TaskTimeout);
26-
Assert.True(taskCompleted, "FAILED: ExecuteReaderAsync Task did not complete successfully.");
27-
28-
SqlDataReader reader = readerTask.Result;
29-
30-
int rows;
31-
for (rows = 0; reader.Read(); rows++) ;
32-
33-
Assert.True(rows == 830, string.Format("FAILED: ExecuteTest reader had wrong number of rows. Expected: {0}. Actual: {1}", 830, rows));
34-
35-
reader.Dispose();
36-
con.Close();
16+
const string sql = "SET NOCOUNT ON"
17+
+ " SELECT 'a'"
18+
+ " DECLARE @t DATETIME = SYSDATETIME()"
19+
+ " WHILE DATEDIFF(s, @t, SYSDATETIME()) < 20 BEGIN"
20+
+ " SELECT 2 x INTO #y"
21+
+ " DROP TABLE #y"
22+
+ " END"
23+
+ " SELECT 'b'";
24+
Task<double> t = RunReadAsync(sql);
25+
double elapsedSync = RunReadSync(sql);
26+
t.Wait();
27+
double elapsedAsync = t.Result;
28+
Assert.True(elapsedAsync < elapsedSync, "Asynchronous operation should be finished quicker than synchronous one");
29+
int limit = 100;
30+
Assert.True(elapsedAsync < limit, $"Asynchronous operation should be finished within {limit}ms");
3731
}
3832

39-
[CheckConnStrSetupFact]
40-
public static void FailureTest()
33+
private static async Task<double> RunReadAsync(string sql)
4134
{
42-
bool failure = false;
43-
bool taskCompleted = false;
44-
45-
SqlCommand com = new SqlCommand("select * from Orders");
46-
SqlConnection con = new SqlConnection((new SqlConnectionStringBuilder(DataTestUtility.TcpConnStr) { Pooling = false }).ConnectionString);
47-
com.Connection = con;
48-
con.Open();
49-
50-
Task<int> nonQueryTask = com.ExecuteNonQueryAsync();
51-
try
35+
double maxElapsedTimeMillisecond = 0;
36+
using (SqlConnection connection = new SqlConnection(DataTestUtility.TcpConnStr))
5237
{
53-
com.ExecuteNonQueryAsync().Wait(TaskTimeout);
54-
}
55-
catch (AggregateException agrEx)
56-
{
57-
agrEx.Handle(
58-
(ex) =>
38+
await connection.OpenAsync();
39+
using (SqlCommand command = connection.CreateCommand())
40+
{
41+
command.CommandText = sql;
42+
using (SqlDataReader reader = await command.ExecuteReaderAsync())
5943
{
60-
Assert.True(ex is InvalidOperationException, "FAILED: Thrown exception for ExecuteNonQueryAsync was not an InvalidOperationException");
61-
failure = true;
62-
return true;
63-
});
44+
Task<bool> t;
45+
Stopwatch stopwatch = new Stopwatch();
46+
do
47+
{
48+
do
49+
{
50+
stopwatch.Start();
51+
t = reader.ReadAsync();
52+
stopwatch.Stop();
53+
double elased = stopwatch.Elapsed.TotalMilliseconds;
54+
if (maxElapsedTimeMillisecond < elased)
55+
{
56+
maxElapsedTimeMillisecond = elased;
57+
}
58+
}
59+
while (await t);
60+
}
61+
while (reader.NextResult());
62+
}
63+
}
6464
}
65-
Assert.True(failure, "FAILED: No exception thrown after trying second ExecuteNonQueryAsync.");
66-
failure = false;
6765

68-
taskCompleted = nonQueryTask.Wait(TaskTimeout);
69-
Assert.True(taskCompleted, "FAILED: ExecuteNonQueryAsync Task did not complete successfully.");
66+
return maxElapsedTimeMillisecond;
67+
}
7068

71-
Task<SqlDataReader> readerTask = com.ExecuteReaderAsync();
72-
try
73-
{
74-
com.ExecuteReaderAsync().Wait(TaskTimeout);
75-
}
76-
catch (AggregateException agrEx)
69+
private static double RunReadSync(string sql)
70+
{
71+
double maxElapsedTimeMillisecond = 0;
72+
using (SqlConnection connection = new SqlConnection(DataTestUtility.TcpConnStr))
7773
{
78-
agrEx.Handle(
79-
(ex) =>
74+
connection.Open();
75+
using (SqlCommand command = connection.CreateCommand())
76+
{
77+
command.CommandText = sql;
78+
using (SqlDataReader reader = command.ExecuteReader())
8079
{
81-
Assert.True(ex is InvalidOperationException, "FAILED: Thrown exception for ExecuteReaderAsync was not an InvalidOperationException: " + ex);
82-
failure = true;
83-
return true;
84-
});
80+
bool result;
81+
Stopwatch stopwatch = new Stopwatch();
82+
do
83+
{
84+
do
85+
{
86+
stopwatch.Start();
87+
result = reader.Read();
88+
stopwatch.Stop();
89+
double elased = stopwatch.Elapsed.TotalMilliseconds;
90+
if (maxElapsedTimeMillisecond < elased)
91+
{
92+
maxElapsedTimeMillisecond = elased;
93+
}
94+
}
95+
while (result);
96+
}
97+
while (reader.NextResult());
98+
}
99+
}
85100
}
86-
Assert.True(failure, "FAILED: No exception thrown after trying second ExecuteReaderAsync.");
87-
88-
taskCompleted = readerTask.Wait(TaskTimeout);
89-
Assert.True(taskCompleted, "FAILED: ExecuteReaderAsync Task did not complete successfully.");
90101

91-
readerTask.Result.Dispose();
92-
con.Close();
102+
return maxElapsedTimeMillisecond;
93103
}
94104
}
95105
}

0 commit comments

Comments
 (0)