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

Commit 1922660

Browse files
committed
Optimize SNIPacket async paths
1 parent 24ecf91 commit 1922660

File tree

1 file changed

+69
-31
lines changed
  • src/System.Data.SqlClient/src/System/Data/SqlClient/SNI

1 file changed

+69
-31
lines changed

src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIPacket.cs

Lines changed: 69 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ internal class SNIPacket : IDisposable, IEquatable<SNIPacket>
2323

2424
private ArrayPool<byte> _arrayPool = ArrayPool<byte>.Shared;
2525
private bool _isBufferFromArrayPool = false;
26+
private ValueTask _asyncOperation;
2627

2728
public SNIPacket() { }
2829

@@ -238,6 +239,7 @@ public void Reset()
238239
_offset = 0;
239240
_description = null;
240241
_completionCallback = null;
242+
_asyncOperation = default;
241243
}
242244

243245
/// <summary>
@@ -247,37 +249,50 @@ public void Reset()
247249
/// <param name="callback">Completion callback</param>
248250
public void ReadFromStreamAsync(Stream stream, SNIAsyncCallback callback)
249251
{
250-
bool error = false;
251-
252-
stream.ReadAsync(_data, 0, _capacity, CancellationToken.None).ContinueWith(t =>
252+
// Treat local function as a static and pass all params otherwise as async will allocate
253+
async ValueTask ReadFromStreamAsync(SNIPacket packet, SNIAsyncCallback cb, ValueTask<int> valueTask)
253254
{
254-
Exception e = t.Exception?.InnerException;
255-
if (e != null)
255+
bool error = false;
256+
try
256257
{
257-
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, SNICommon.InternalExceptionError, e);
258-
error = true;
259-
}
260-
else
261-
{
262-
_length = t.Result;
263-
264-
if (_length == 0)
258+
packet._length = await valueTask.ConfigureAwait(false);
259+
if (packet._length == 0)
265260
{
266261
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, 0, SNICommon.ConnTerminatedError, string.Empty);
267262
error = true;
268263
}
269264
}
265+
catch (Exception ex)
266+
{
267+
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, SNICommon.InternalExceptionError, ex);
268+
error = true;
269+
}
270270

271271
if (error)
272272
{
273-
Release();
273+
packet.Release();
274+
}
275+
276+
cb(packet, error ? TdsEnums.SNI_ERROR : TdsEnums.SNI_SUCCESS);
277+
}
278+
279+
ValueTask<int> vt = stream.ReadAsync(new Memory<byte>(_data, 0, _capacity), CancellationToken.None);
280+
281+
if (vt.IsCompletedSuccessfully)
282+
{
283+
_length = vt.Result;
284+
// Zero length to go via async local function as is error condition
285+
if (_length > 0)
286+
{
287+
callback(this, TdsEnums.SNI_SUCCESS);
288+
289+
// Completed
290+
return;
274291
}
292+
}
275293

276-
callback(this, error ? TdsEnums.SNI_ERROR : TdsEnums.SNI_SUCCESS);
277-
},
278-
CancellationToken.None,
279-
TaskContinuationOptions.DenyChildAttach,
280-
TaskScheduler.Default);
294+
// Not complete or error call the async local function to complete
295+
_asyncOperation = ReadFromStreamAsync(this, callback, vt);
281296
}
282297

283298
/// <summary>
@@ -302,24 +317,47 @@ public void WriteToStream(Stream stream)
302317
/// Write data to a stream asynchronously
303318
/// </summary>
304319
/// <param name="stream">Stream to write to</param>
305-
public async void WriteToStreamAsync(Stream stream, SNIAsyncCallback callback, SNIProviders provider, bool disposeAfterWriteAsync = false)
320+
public void WriteToStreamAsync(Stream stream, SNIAsyncCallback callback, SNIProviders provider, bool disposeAfterWriteAsync = false)
306321
{
307-
uint status = TdsEnums.SNI_SUCCESS;
308-
try
322+
// Treat local function as a static and pass all params otherwise as async will allocate
323+
async ValueTask WriteToStreamAsync(SNIPacket packet, SNIAsyncCallback cb, SNIProviders providers, bool disposeAfter, ValueTask valueTask)
309324
{
310-
await stream.WriteAsync(_data, 0, _length, CancellationToken.None).ConfigureAwait(false);
311-
}
312-
catch (Exception e)
313-
{
314-
SNILoadHandle.SingletonInstance.LastError = new SNIError(provider, SNICommon.InternalExceptionError, e);
315-
status = TdsEnums.SNI_ERROR;
325+
uint status = TdsEnums.SNI_SUCCESS;
326+
try
327+
{
328+
await valueTask.ConfigureAwait(false);
329+
}
330+
catch (Exception e)
331+
{
332+
SNILoadHandle.SingletonInstance.LastError = new SNIError(providers, SNICommon.InternalExceptionError, e);
333+
status = TdsEnums.SNI_ERROR;
334+
}
335+
336+
cb(packet, status);
337+
338+
if (disposeAfter)
339+
{
340+
packet.Dispose();
341+
}
316342
}
317-
callback(this, status);
318343

319-
if (disposeAfterWriteAsync)
344+
ValueTask vt = stream.WriteAsync(new Memory<byte>(_data, 0, _length), CancellationToken.None);
345+
346+
if (vt.IsCompletedSuccessfully)
320347
{
321-
Dispose();
348+
callback(this, TdsEnums.SNI_SUCCESS);
349+
350+
if (disposeAfterWriteAsync)
351+
{
352+
Dispose();
353+
}
354+
355+
// Completed
356+
return;
322357
}
358+
359+
// Not complete or error call the async local function to complete
360+
_asyncOperation = WriteToStreamAsync(this, callback, provider, disposeAfterWriteAsync, vt);
323361
}
324362

325363
/// <summary>

0 commit comments

Comments
 (0)