Skip to content

Commit 59ac3f4

Browse files
Mark YdbConnection.State as Broken when the underlying session is broken, including background deactivation (#523)
1 parent 69b5378 commit 59ac3f4

File tree

5 files changed

+45
-41
lines changed

5 files changed

+45
-41
lines changed

src/Ydb.Sdk/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
- Feat ADO.NET: Mark `YdbConnection.State` as `Broken` when the underlying session is broken, including background deactivation.
12
- Feat ADO.NET: Added YdbDataSource `ExecuteAsync` and `ExecuteInTransaction` convenience methods.
23
- **Breaking Change**: moved and renamed `Ydb.Sdk.Services.Query.TxMode` -> `Ydb.Sdk.Ado.TransactionMode`.
3-
- Feat ADO.NET: cache gRPC transport by `gRPCConnectionString` to reuse channels.
4+
- Feat ADO.NET: Cache gRPC transport by `gRPCConnectionString` to reuse channels.
45
- Fix bug wrap-around ADO.NET: Big parameterized Decimal — `((ulong)bits[1] << 32)` -> `((ulong)(uint)bits[1] << 32)`.
56
- Feat ADO.NET: Parameterized Decimal overflow check: `Precision` and `Scale`.
67
- Feat ADO.NET: Deleted support for `DateTimeOffset` was a mistake.

src/Ydb.Sdk/src/Ado/PoolManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ CancellationToken cancellationToken
5050

5151
internal static async Task ClearPool(string connectionString)
5252
{
53-
if (Pools.Remove(connectionString, out var sessionPool))
53+
if (Pools.TryRemove(connectionString, out var sessionPool))
5454
{
5555
try
5656
{

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

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -102,30 +102,38 @@ public override async Task OpenAsync(CancellationToken cancellationToken)
102102

103103
public override async Task CloseAsync()
104104
{
105-
if (State == ConnectionState.Closed)
105+
// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
106+
switch (State)
106107
{
107-
return;
108-
}
109-
110-
try
111-
{
112-
if (LastReader is { IsClosed: false })
113-
{
114-
await LastReader.CloseAsync();
115-
}
116-
117-
if (CurrentTransaction is { Completed: false })
118-
{
119-
await CurrentTransaction.RollbackAsync();
120-
}
121-
122-
OnStateChange(OpenToClosedEventArgs);
123-
124-
ConnectionState = ConnectionState.Closed;
125-
}
126-
finally
127-
{
128-
_session.Close();
108+
case ConnectionState.Closed:
109+
return;
110+
case ConnectionState.Broken:
111+
ConnectionState = ConnectionState.Closed;
112+
_session.Close();
113+
return;
114+
default:
115+
try
116+
{
117+
if (LastReader is { IsClosed: false })
118+
{
119+
await LastReader.CloseAsync();
120+
}
121+
122+
if (CurrentTransaction is { Completed: false })
123+
{
124+
await CurrentTransaction.RollbackAsync();
125+
}
126+
127+
OnStateChange(OpenToClosedEventArgs);
128+
129+
ConnectionState = ConnectionState.Closed;
130+
}
131+
finally
132+
{
133+
_session.Close();
134+
}
135+
136+
break;
129137
}
130138
}
131139

@@ -145,19 +153,14 @@ public override string ConnectionString
145153

146154
public override string Database => _connectionStringBuilder?.Database ?? string.Empty;
147155

148-
public override ConnectionState State => ConnectionState;
156+
public override ConnectionState State =>
157+
ConnectionState != ConnectionState.Closed && _session.IsBroken // maybe is updated asynchronously
158+
? ConnectionState.Broken
159+
: ConnectionState;
149160

150161
private ConnectionState ConnectionState { get; set; } = ConnectionState.Closed; // Invoke AsyncOpen()
151162

152-
internal void OnNotSuccessStatusCode(StatusCode code)
153-
{
154-
_session.OnNotSuccessStatusCode(code);
155-
156-
if (_session.IsBroken)
157-
{
158-
ConnectionState = ConnectionState.Broken;
159-
}
160-
}
163+
internal void OnNotSuccessStatusCode(StatusCode code) => _session.OnNotSuccessStatusCode(code);
161164

162165
internal YdbDataReader? LastReader { get; set; }
163166
internal string LastCommand { get; set; } = string.Empty;
@@ -203,15 +206,15 @@ public override Task<DataTable> GetSchemaAsync(
203206

204207
internal void ThrowIfConnectionClosed()
205208
{
206-
if (ConnectionState is ConnectionState.Closed or ConnectionState.Broken)
209+
if (State is ConnectionState.Closed or ConnectionState.Broken)
207210
{
208211
throw new InvalidOperationException("Connection is closed");
209212
}
210213
}
211214

212215
private void ThrowIfConnectionOpen()
213216
{
214-
if (ConnectionState == ConnectionState.Open)
217+
if (State == ConnectionState.Open)
215218
{
216219
throw new InvalidOperationException("Connection already open");
217220
}

src/Ydb.Sdk/src/IDriver.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,14 +210,14 @@ protected async ValueTask<CallOptions> GetCallOptions(GrpcRequestSettings settin
210210
}
211211

212212
public ILoggerFactory LoggerFactory { get; }
213-
public void RegisterOwner() => _ownerCount++;
213+
public void RegisterOwner() => ++_ownerCount;
214214
public bool IsDisposed => Disposed == 1;
215215

216216
public void Dispose() => DisposeAsync().AsTask().GetAwaiter().GetResult();
217217

218218
public async ValueTask DisposeAsync()
219219
{
220-
if (Interlocked.Decrement(ref _ownerCount) <= 0 && Interlocked.CompareExchange(ref Disposed, 1, 0) == 0)
220+
if (--_ownerCount <= 0 && Interlocked.CompareExchange(ref Disposed, 1, 0) == 0)
221221
{
222222
await ChannelPool.DisposeAsync();
223223

src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/PoolManagerTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public class PoolManagerTests
2828
public async Task PoolManager_CachingAndCleanup(string[] connectionStrings, int expectedDrivers, int expectedPools)
2929
{
3030
await YdbConnection.ClearAllPools();
31+
foreach (var (_, driver) in PoolManager.Drivers)
32+
Assert.True(driver.IsDisposed);
3133
PoolManager.Drivers.Clear();
3234

3335
var connections = connectionStrings
@@ -45,9 +47,7 @@ public async Task PoolManager_CachingAndCleanup(string[] connectionStrings, int
4547
await Task.WhenAll(parallelTasks);
4648

4749
foreach (var (_, driver) in PoolManager.Drivers)
48-
{
4950
Assert.False(driver.IsDisposed);
50-
}
5151

5252
Assert.Equal(expectedDrivers, PoolManager.Drivers.Count);
5353
Assert.Equal(expectedPools, PoolManager.Pools.Count);

0 commit comments

Comments
 (0)