Skip to content

Commit 97a05c5

Browse files
feat: fix NPE on Describe method & invoke onStatus on !Success (#175)
1 parent 0c6702c commit 97a05c5

File tree

7 files changed

+64
-21
lines changed

7 files changed

+64
-21
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
- Check status of the transport or server for an invalidated session
2+
- Fixed NPE in DescribeTable
3+
14
## v0.6.0
25
- ADO.NET over query-service
36
- Add EndpointPool

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,9 @@ protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBeha
175175
? new ExecuteQuerySettings { TransportTimeout = TimeSpan.FromSeconds(CommandTimeout) }
176176
: ExecuteQuerySettings.DefaultInstance;
177177

178-
var ydbDataReader = await YdbDataReader.CreateYdbDataReader(YdbConnection.Session.ExecuteQuery(_commandText,
179-
DbParameterCollection.YdbParameters, execSettings, Transaction?.TransactionControl), Transaction);
178+
var ydbDataReader = await YdbDataReader.CreateYdbDataReader(YdbConnection.Session.ExecuteQuery(
179+
_commandText, DbParameterCollection.YdbParameters, execSettings, Transaction?.TransactionControl),
180+
YdbConnection.Session.OnStatus, Transaction);
180181

181182
YdbConnection.LastReader = ydbDataReader;
182183
YdbConnection.LastCommand = CommandText;

src/Ydb.Sdk/src/Ado/YdbDataReader.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public sealed class YdbDataReader : DbDataReader, IAsyncEnumerable<YdbDataRecord
1111
private readonly IAsyncEnumerator<ExecuteQueryResponsePart> _stream;
1212
private readonly YdbTransaction? _ydbTransaction;
1313
private readonly RepeatedField<IssueMessage> _issueMessagesInStream = new();
14+
private readonly Action<Status> _onStatus;
1415

1516
private int _currentRowIndex = -1;
1617
private long _resultSetIndex = -1;
@@ -48,17 +49,22 @@ private interface IMetadata
4849
private Value.ResultSet.Row CurrentRow => CurrentResultSet.Rows[_currentRowIndex];
4950
private int RowsCount => ReaderMetadata.RowsCount;
5051

51-
private YdbDataReader(IAsyncEnumerator<ExecuteQueryResponsePart> resultSetStream, YdbTransaction? ydbTransaction)
52+
private YdbDataReader(
53+
IAsyncEnumerator<ExecuteQueryResponsePart> resultSetStream,
54+
Action<Status> onStatus,
55+
YdbTransaction? ydbTransaction)
5256
{
5357
_stream = resultSetStream;
58+
_onStatus = onStatus;
5459
_ydbTransaction = ydbTransaction;
5560
}
5661

5762
internal static async Task<YdbDataReader> CreateYdbDataReader(
5863
IAsyncEnumerator<ExecuteQueryResponsePart> resultSetStream,
64+
Action<Status> onStatus,
5965
YdbTransaction? ydbTransaction = null)
6066
{
61-
var ydbDataReader = new YdbDataReader(resultSetStream, ydbTransaction);
67+
var ydbDataReader = new YdbDataReader(resultSetStream, onStatus, ydbTransaction);
6268
await ydbDataReader.Init();
6369

6470
return ydbDataReader;
@@ -474,7 +480,11 @@ private async Task<State> NextExecPart()
474480
_issueMessagesInStream.AddRange(_stream.Current.Issues);
475481
}
476482

477-
throw new YdbException(Status.FromProto(part.Status, _issueMessagesInStream));
483+
var status = Status.FromProto(part.Status, _issueMessagesInStream);
484+
485+
_onStatus(status);
486+
487+
throw new YdbException(status);
478488
}
479489

480490
_currentResultSet = part.ResultSet?.FromProto();
@@ -498,6 +508,8 @@ private async Task<State> NextExecPart()
498508
{
499509
OnFailReadStream();
500510

511+
_onStatus(e.Status);
512+
501513
throw new YdbException(e.Status);
502514
}
503515
}

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

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,26 @@ internal async Task<T> ExecOnSession<T>(Func<TSession, Task<T>> onSession, Retry
8080
}
8181
catch (Exception e)
8282
{
83-
if (attempt == retrySettings.MaxAttempts - 1)
84-
{
85-
throw;
86-
}
87-
8883
var statusErr = e switch
8984
{
9085
Driver.TransportException transportException => transportException.Status,
9186
StatusUnsuccessfulException unsuccessfulException => unsuccessfulException.Status,
9287
_ => null
9388
};
9489

90+
if (attempt == retrySettings.MaxAttempts - 1)
91+
{
92+
if (statusErr != null)
93+
{
94+
session?.OnStatus(statusErr);
95+
}
96+
97+
throw;
98+
}
99+
95100
if (statusErr != null)
96101
{
102+
session?.OnStatus(statusErr);
97103
var retryRule = retrySettings.GetRetryRule(statusErr.StatusCode);
98104

99105
if (retryRule.Policy == RetryPolicy.None ||
@@ -103,8 +109,10 @@ internal async Task<T> ExecOnSession<T>(Func<TSession, Task<T>> onSession, Retry
103109
}
104110

105111
Logger.LogTrace(
106-
"Retry: attempt {attempt}, Session ${session?.SessionId}, idempotent error {status} retrying",
112+
"Retry: attempt {attempt}, Session ${session.SessionId}, idempotent error {status} retrying",
107113
attempt, session?.SessionId, statusErr);
114+
115+
108116
await Task.Delay(retryRule.BackoffSettings.CalcBackoff(attempt));
109117
}
110118
else

src/Ydb.Sdk/src/Services/Table/DescribeTable.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public class TableStats
6565
public ulong StoreSize { get; }
6666
public ulong Partitions { get; }
6767
public DateTime CreationTime { get; }
68-
public DateTime ModificationTime { get; }
68+
public DateTime? ModificationTime { get; }
6969

7070
internal TableStats(Ydb.Table.TableStats? proto)
7171
{
@@ -79,7 +79,7 @@ internal TableStats(Ydb.Table.TableStats? proto)
7979
StoreSize = proto.StoreSize;
8080
Partitions = proto.Partitions;
8181
CreationTime = proto.CreationTime.ToDateTime();
82-
ModificationTime = proto.ModificationTime.ToDateTime();
82+
ModificationTime = proto.ModificationTime?.ToDateTime();
8383
}
8484
}
8585

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

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ public class YdbDataReaderTests
1111
[Fact]
1212
public async Task BasedIteration_WhenNotCallMethodRead_ThrowException()
1313
{
14-
var reader = await YdbDataReader.CreateYdbDataReader(EnumeratorSuccess());
14+
var statuses = new List<Status>();
15+
var reader = await YdbDataReader.CreateYdbDataReader(EnumeratorSuccess(), statuses.Add);
1516

1617
// Read first metadata
1718
Assert.True(reader.HasRows);
@@ -36,19 +37,25 @@ public async Task BasedIteration_WhenNotCallMethodRead_ThrowException()
3637

3738
Assert.Equal("The reader is closed",
3839
Assert.Throws<InvalidOperationException>(() => reader.GetValue(0)).Message);
40+
Assert.Empty(statuses);
3941
}
4042

4143
[Fact]
4244
public void CreateYdbDataReader_WhenAbortedStatus_ThrowException()
4345
{
46+
var statuses = new List<Status>();
4447
Assert.Equal("Status: Aborted", Assert.Throws<YdbException>(
45-
() => YdbDataReader.CreateYdbDataReader(SingleEnumeratorFailed).GetAwaiter().GetResult()).Message);
48+
() => YdbDataReader.CreateYdbDataReader(SingleEnumeratorFailed, statuses.Add).GetAwaiter().GetResult())
49+
.Message);
50+
Assert.Single(statuses);
51+
Assert.Equal(StatusCode.Aborted, statuses[0].StatusCode);
4652
}
4753

4854
[Fact]
4955
public async Task NextResult_WhenNextResultSkipResultSet_ReturnNextResultSet()
5056
{
51-
var reader = await YdbDataReader.CreateYdbDataReader(EnumeratorSuccess(2));
57+
var statuses = new List<Status>();
58+
var reader = await YdbDataReader.CreateYdbDataReader(EnumeratorSuccess(2), statuses.Add);
5259

5360
Assert.True(reader.NextResult());
5461
Assert.True(reader.NextResult());
@@ -57,12 +64,14 @@ public async Task NextResult_WhenNextResultSkipResultSet_ReturnNextResultSet()
5764

5865
Assert.False(reader.Read());
5966
Assert.False(reader.NextResult());
67+
Assert.Empty(statuses);
6068
}
6169

6270
[Fact]
6371
public async Task NextResult_WhenFirstRead_ReturnResultSet()
6472
{
65-
var reader = await YdbDataReader.CreateYdbDataReader(EnumeratorSuccess(2));
73+
var statuses = new List<Status>();
74+
var reader = await YdbDataReader.CreateYdbDataReader(EnumeratorSuccess(2), statuses.Add);
6675

6776
Assert.True(reader.Read());
6877
Assert.True((bool)reader.GetValue(0));
@@ -74,12 +83,14 @@ public async Task NextResult_WhenFirstRead_ReturnResultSet()
7483

7584
Assert.False(reader.NextResult());
7685
Assert.False(reader.Read());
86+
Assert.Empty(statuses);
7787
}
7888

7989
[Fact]
8090
public async Task NextResult_WhenLongResultSet_ReturnResultSet()
8191
{
82-
var reader = await YdbDataReader.CreateYdbDataReader(EnumeratorSuccess(2, true));
92+
var statuses = new List<Status>();
93+
var reader = await YdbDataReader.CreateYdbDataReader(EnumeratorSuccess(2, true), statuses.Add);
8394

8495
Assert.True(reader.Read());
8596
Assert.True((bool)reader.GetValue(0));
@@ -93,11 +104,13 @@ public async Task NextResult_WhenLongResultSet_ReturnResultSet()
93104

94105
Assert.False(reader.NextResult());
95106
Assert.False(reader.Read());
107+
Assert.Empty(statuses);
96108
}
97109

98110
[Fact]
99111
public async Task Read_WhenReadAsyncThrowException_AggregateIssuesBeforeErrorAndAfter()
100112
{
113+
var statuses = new List<Status>();
101114
var result = ResultSet.Parser.ParseJson(
102115
"{ \"columns\": [ { \"name\": \"column0\", " +
103116
"\"type\": { \"typeId\": \"BOOL\" } } ], " +
@@ -116,7 +129,7 @@ public async Task Read_WhenReadAsyncThrowException_AggregateIssuesBeforeErrorAnd
116129
nextFailPart.Issues.Add(new IssueMessage { Message = "Some message 3" });
117130

118131
var reader = await YdbDataReader.CreateYdbDataReader(new MockAsyncEnumerator<ExecuteQueryResponsePart>(
119-
new List<ExecuteQueryResponsePart> { successPart, failPart, nextFailPart }));
132+
new List<ExecuteQueryResponsePart> { successPart, failPart, nextFailPart }), statuses.Add);
120133

121134
Assert.True(reader.Read());
122135
Assert.Equal(@"Status: Aborted, Issues:
@@ -125,6 +138,8 @@ public async Task Read_WhenReadAsyncThrowException_AggregateIssuesBeforeErrorAnd
125138
[0] Fatal: Some message 2
126139
[0] Fatal: Some message 3
127140
", Assert.Throws<YdbException>(() => reader.Read()).Message);
141+
Assert.Single(statuses);
142+
Assert.Equal(StatusCode.Aborted, statuses[0].StatusCode);
128143
}
129144

130145
private static MockAsyncEnumerator<ExecuteQueryResponsePart> EnumeratorSuccess(int size = 1,

src/Ydb.Sdk/tests/Table/DescribeTableTests.cs renamed to src/Ydb.Sdk/tests/DescribeTableTests.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
using Xunit;
2+
using Ydb.Sdk.Services.Table;
23
using Ydb.Sdk.Tests.Fixture;
34

4-
namespace Ydb.Sdk.Tests.Table;
5+
namespace Ydb.Sdk.Tests;
56

67
[Trait("Category", "Integration")]
78
public class DescribeTableTests : IClassFixture<TableClientFixture>
@@ -29,7 +30,10 @@ public async Task CreateAndDescribe()
2930

3031
await Utils.CreateSimpleTable(_tableClientFixture.TableClient, tablePath, columnName);
3132

32-
var describeResponse = await _tableClientFixture.TableClient.DescribeTable(tablePath);
33+
var describeResponse = await _tableClientFixture.TableClient.DescribeTable(tablePath, new DescribeTableSettings
34+
{
35+
OperationTimeout = TimeSpan.FromSeconds(5)
36+
}.WithTableStats());
3337
describeResponse.Status.EnsureSuccess();
3438
Assert.True(describeResponse.Result.PrimaryKey.SequenceEqual(new[] { columnName }));
3539

0 commit comments

Comments
 (0)