Skip to content

Commit bbdef73

Browse files
- ADO.NET: session is now deactivated when cancelled.
- Fixed bug ADO.NET: throws an `InvalidOperationException` if the connection is broken during the next invocation.
1 parent 1bbcd9b commit bbdef73

File tree

6 files changed

+53
-28
lines changed

6 files changed

+53
-28
lines changed

.github/workflows/slo.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
matrix:
3232
workload:
3333
- AdoNet
34-
# - EF
34+
- EF
3535

3636
concurrency:
3737
group: slo-${{ github.ref }}-${{ matrix.workload }}

src/Ydb.Sdk/src/Ado/YdbCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBeha
174174
throw new YdbOperationInProgressException(YdbConnection);
175175
}
176176

177-
YdbConnection.EnsureConnectionOpen();
177+
YdbConnection.ThrowIfConnectionClosed();
178178

179179
var ydbParameters = DbParameterCollection.YdbParameters;
180180
var (sql, paramNames) = SqlParser.Parse(

src/Ydb.Sdk/src/Ado/YdbConnection.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ internal Session Session
2828
{
2929
get
3030
{
31-
EnsureConnectionOpen();
31+
ThrowIfConnectionClosed();
3232

3333
return _session;
3434
}
@@ -53,7 +53,7 @@ public YdbConnection(YdbConnectionStringBuilder connectionStringBuilder)
5353

5454
protected override YdbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
5555
{
56-
EnsureConnectionOpen();
56+
ThrowIfConnectionClosed();
5757

5858
return BeginTransaction(isolationLevel switch
5959
{
@@ -66,7 +66,7 @@ protected override YdbTransaction BeginDbTransaction(IsolationLevel isolationLev
6666

6767
public YdbTransaction BeginTransaction(TxMode txMode = TxMode.SerializableRw)
6868
{
69-
EnsureConnectionOpen();
69+
ThrowIfConnectionClosed();
7070

7171
if (CurrentTransaction is { Completed: false })
7272
{
@@ -90,7 +90,7 @@ public override void ChangeDatabase(string databaseName)
9090

9191
public override async Task OpenAsync(CancellationToken cancellationToken)
9292
{
93-
EnsureConnectionClosed();
93+
ThrowIfConnectionOpen();
9494

9595
try
9696
{
@@ -152,7 +152,7 @@ public override string ConnectionString
152152
set
153153
#pragma warning restore CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes).
154154
{
155-
EnsureConnectionClosed();
155+
ThrowIfConnectionOpen();
156156

157157
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
158158
_connectionStringBuilder = value != null ? new YdbConnectionStringBuilder(value) : null;
@@ -186,7 +186,7 @@ public override string ServerVersion
186186
{
187187
get
188188
{
189-
EnsureConnectionOpen();
189+
ThrowIfConnectionClosed();
190190

191191
return string.Empty; // TODO ServerVersion
192192
}
@@ -217,17 +217,17 @@ public override Task<DataTable> GetSchemaAsync(
217217
CancellationToken cancellationToken = default
218218
) => YdbSchema.GetSchemaAsync(this, collectionName, restrictionValues, cancellationToken);
219219

220-
internal void EnsureConnectionOpen()
220+
internal void ThrowIfConnectionClosed()
221221
{
222-
if (ConnectionState == ConnectionState.Closed)
222+
if (ConnectionState is ConnectionState.Closed or ConnectionState.Broken)
223223
{
224224
throw new InvalidOperationException("Connection is closed");
225225
}
226226
}
227227

228-
private void EnsureConnectionClosed()
228+
private void ThrowIfConnectionOpen()
229229
{
230-
if (ConnectionState != ConnectionState.Closed)
230+
if (ConnectionState == ConnectionState.Open)
231231
{
232232
throw new InvalidOperationException("Connection already open");
233233
}

src/Ydb.Sdk/src/Pool/SessionPool.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ internal void OnStatus(Status status)
225225
{
226226
// ReSharper disable once InvertIf
227227
if (status.StatusCode is
228+
StatusCode.Cancelled or
228229
StatusCode.BadSession or
229230
StatusCode.SessionBusy or
230231
StatusCode.InternalError or

src/Ydb.Sdk/tests/Ado/Specification/YdbConnectionTests.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using AdoNet.Specification.Tests;
22
using Xunit;
3+
using Ydb.Sdk.Ado;
34

45
namespace Ydb.Sdk.Tests.Ado.Specification;
56

@@ -33,11 +34,12 @@ public override void ServerVersion_returns_value()
3334
base.ServerVersion_returns_value();
3435
}
3536

36-
#pragma warning disable xUnit1004
37-
[Fact(Skip = "TODO Supported cancel OpenAsync.")]
38-
#pragma warning restore xUnit1004
39-
public override Task OpenAsync_is_canceled()
37+
public override async Task OpenAsync_is_canceled()
4038
{
41-
return base.OpenAsync_is_canceled();
39+
await using var connection = CreateConnection();
40+
connection.ConnectionString = ConnectionString;
41+
var task = connection.OpenAsync(CanceledToken);
42+
await Assert.ThrowsAnyAsync<YdbException>(() => task);
43+
Assert.True(task.IsFaulted);
4244
}
4345
}

src/Ydb.Sdk/tests/Ado/YdbConnectionTests.cs

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,11 @@ public async Task OpenAsync_WhenCancelTokenIsCanceled_ThrowYdbException()
222222
Assert.Equal("The connection pool has been exhausted, either raise 'MaxSessionPool' (currently 10) " +
223223
"or 'CreateSessionTimeout' (currently 5 seconds) in your connection string.",
224224
(await Assert.ThrowsAsync<YdbException>(async () => await connection.OpenAsync(cts.Token))).Message);
225+
Assert.Equal(ConnectionState.Closed, connection.State);
225226
}
226227

227228
[Fact]
228-
public async Task YdbCommand_WhenCancelTokenIsCanceled_ThrowYdbException()
229+
public async Task YdbDataReader_WhenCancelTokenIsCanceled_ThrowYdbException()
229230
{
230231
await using var connection = await CreateOpenConnectionAsync();
231232
var command = new YdbCommand(connection) { CommandText = "SELECT 1; SELECT 1; SELECT 1;" };
@@ -236,16 +237,13 @@ public async Task YdbCommand_WhenCancelTokenIsCanceled_ThrowYdbException()
236237
await ydbDataReader.ReadAsync(cts.Token); // first part in memory
237238
Assert.False(ydbDataReader.IsClosed);
238239
Assert.Equal(1, ydbDataReader.GetValue(0));
239-
240+
Assert.Equal(ConnectionState.Open, connection.State);
240241
Assert.Equal(StatusCode.Cancelled, (await Assert.ThrowsAsync<YdbException>(
241242
async () => await ydbDataReader.NextResultAsync(cts.Token))).Code);
242243
Assert.True(ydbDataReader.IsClosed);
243-
Assert.Equal(StatusCode.Cancelled, (await Assert.ThrowsAsync<YdbException>(
244-
async () => await command.ExecuteReaderAsync(cts.Token))).Code);
245-
Assert.Equal(StatusCode.Cancelled, (await Assert.ThrowsAsync<YdbException>(
246-
async () => await command.ExecuteScalarAsync(cts.Token))).Code);
247-
Assert.Equal(StatusCode.Cancelled, (await Assert.ThrowsAsync<YdbException>(
248-
async () => await command.ExecuteNonQueryAsync(cts.Token))).Code);
244+
Assert.Equal(ConnectionState.Broken, connection.State);
245+
// ReSharper disable once MethodSupportsCancellation
246+
await connection.OpenAsync();
249247

250248
// ReSharper disable once MethodSupportsCancellation
251249
ydbDataReader = await command.ExecuteReaderAsync();
@@ -259,16 +257,40 @@ public async Task YdbCommand_WhenCancelTokenIsCanceled_ThrowYdbException()
259257
Assert.Equal(StatusCode.Cancelled, (await Assert.ThrowsAsync<YdbException>(
260258
async () => await ydbDataReader.NextResultAsync(cts.Token))).Code);
261259
Assert.True(ydbDataReader.IsClosed);
260+
Assert.Equal(ConnectionState.Broken, connection.State);
262261
}
263262

264263
[Fact]
265-
public async Task ExecuteMethods_WhenExecutedYdbDataReaderThenCancelTokenIsCanceled_ReturnValues()
264+
public async Task ExecuteMethods_WhenCancelTokenIsCanceled_ConnectionIsBroken()
266265
{
267266
await using var connection = await CreateOpenConnectionAsync();
268-
var ydbCommand = new YdbCommand(connection) { CommandText = "SELECT 1; SELECT 1; "};
267+
var command = new YdbCommand(connection) { CommandText = "SELECT 1; SELECT 1; SELECT 1;" };
268+
using var cts = new CancellationTokenSource();
269+
cts.Cancel();
270+
271+
Assert.Equal(StatusCode.Cancelled, (await Assert.ThrowsAsync<YdbException>(
272+
async () => await command.ExecuteReaderAsync(cts.Token))).Code);
273+
Assert.Equal(ConnectionState.Broken, connection.State);
274+
// ReSharper disable once MethodSupportsCancellation
275+
await connection.OpenAsync();
276+
Assert.Equal(StatusCode.Cancelled, (await Assert.ThrowsAsync<YdbException>(
277+
async () => await command.ExecuteScalarAsync(cts.Token))).Code);
278+
Assert.Equal(ConnectionState.Broken, connection.State);
279+
// ReSharper disable once MethodSupportsCancellation
280+
await connection.OpenAsync();
281+
Assert.Equal(StatusCode.Cancelled, (await Assert.ThrowsAsync<YdbException>(
282+
async () => await command.ExecuteNonQueryAsync(cts.Token))).Code);
283+
Assert.Equal(ConnectionState.Broken, connection.State);
284+
}
285+
286+
[Fact]
287+
public async Task ExecuteReaderAsync_WhenExecutedYdbDataReaderThenCancelTokenIsCanceled_ReturnValues()
288+
{
289+
await using var connection = await CreateOpenConnectionAsync();
290+
var ydbCommand = new YdbCommand(connection) { CommandText = "SELECT 1; SELECT 1; " };
269291
var cts = new CancellationTokenSource();
270292
var ydbDataReader = await ydbCommand.ExecuteReaderAsync(cts.Token);
271-
293+
272294
await ydbDataReader.ReadAsync(cts.Token);
273295
Assert.Equal(1, ydbDataReader.GetValue(0));
274296
Assert.True(await ydbDataReader.NextResultAsync(cts.Token));

0 commit comments

Comments
 (0)