Skip to content

Commit 2c56830

Browse files
authored
Simplify managed SNI receive callback use (#1186)
1 parent caaecea commit 2c56830

File tree

8 files changed

+43
-89
lines changed

8 files changed

+43
-89
lines changed

src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj

-1
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,6 @@
614614
<Compile Include="Microsoft\Data\SqlClient\SNI\SNILoadHandle.cs" />
615615
<Compile Include="Microsoft\Data\SqlClient\SNI\SNIMarsConnection.cs" />
616616
<Compile Include="Microsoft\Data\SqlClient\SNI\SNIMarsHandle.cs" />
617-
<Compile Include="Microsoft\Data\SqlClient\SNI\SNIMarsQueuedPacket.cs" />
618617
<Compile Include="Microsoft\Data\SqlClient\SNI\SNINpHandle.cs" />
619618
<Compile Include="Microsoft\Data\SqlClient\SNI\SNIPacket.cs" />
620619
<Compile Include="Microsoft\Data\SqlClient\SNI\SNIPhysicalHandle.cs" />

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,8 @@ internal abstract class SNIHandle
5151
/// Send a packet asynchronously
5252
/// </summary>
5353
/// <param name="packet">SNI packet</param>
54-
/// <param name="callback">Completion callback</param>
5554
/// <returns>SNI error code</returns>
56-
public abstract uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = null);
55+
public abstract uint SendAsync(SNIPacket packet);
5756

5857
/// <summary>
5958
/// Receive a packet synchronously

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs

+4-5
Original file line numberDiff line numberDiff line change
@@ -112,16 +112,15 @@ public uint Send(SNIPacket packet)
112112
/// Send a packet asynchronously
113113
/// </summary>
114114
/// <param name="packet">SNI packet</param>
115-
/// <param name="callback">Completion callback</param>
116115
/// <returns>SNI error code</returns>
117-
public uint SendAsync(SNIPacket packet, SNIAsyncCallback callback)
116+
public uint SendAsync(SNIPacket packet)
118117
{
119118
long scopeID = SqlClientEventSource.Log.TrySNIScopeEnterEvent(s_className);
120119
try
121120
{
122121
lock (this)
123122
{
124-
return _lowerHandle.SendAsync(packet, callback);
123+
return _lowerHandle.SendAsync(packet);
125124
}
126125
}
127126
finally
@@ -192,7 +191,7 @@ public void HandleReceiveError(SNIPacket packet)
192191
Debug.Assert(Monitor.IsEntered(this), "HandleReceiveError was called without being locked.");
193192
foreach (SNIMarsHandle handle in _sessions.Values)
194193
{
195-
if (packet.HasCompletionCallback)
194+
if (packet.HasAsyncIOCompletionCallback)
196195
{
197196
handle.HandleReceiveError(packet);
198197
#if DEBUG
@@ -215,7 +214,7 @@ public void HandleReceiveError(SNIPacket packet)
215214
/// <param name="sniErrorCode">SNI error code</param>
216215
public void HandleSendComplete(SNIPacket packet, uint sniErrorCode)
217216
{
218-
packet.InvokeCompletionCallback(sniErrorCode);
217+
packet.InvokeAsyncIOCompletionCallback(sniErrorCode);
219218
}
220219

221220
/// <summary>

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs

+9-10
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ internal sealed class SNIMarsHandle : SNIHandle
1919
private readonly SNIMarsConnection _connection;
2020
private readonly uint _status = TdsEnums.SNI_UNINITIALIZED;
2121
private readonly Queue<SNIPacket> _receivedPacketQueue = new Queue<SNIPacket>();
22-
private readonly Queue<SNIMarsQueuedPacket> _sendPacketQueue = new Queue<SNIMarsQueuedPacket>();
22+
private readonly Queue<SNIPacket> _sendPacketQueue = new Queue<SNIPacket>();
2323
private readonly object _callbackObject;
2424
private readonly Guid _connectionId;
2525
private readonly ushort _sessionId;
@@ -191,9 +191,8 @@ public override uint Send(SNIPacket packet)
191191
/// Send packet asynchronously
192192
/// </summary>
193193
/// <param name="packet">SNI packet</param>
194-
/// <param name="callback">Completion callback</param>
195194
/// <returns>SNI error code</returns>
196-
private uint InternalSendAsync(SNIPacket packet, SNIAsyncCallback callback)
195+
private uint InternalSendAsync(SNIPacket packet)
197196
{
198197
Debug.Assert(packet.ReservedHeaderSize == SNISMUXHeader.HEADER_LENGTH, "mars handle attempting to send muxed packet without smux reservation in InternalSendAsync");
199198
using (TrySNIEventScope.Create("SNIMarsHandle.InternalSendAsync | SNI | INFO | SCOPE | Entering Scope {0}"))
@@ -207,9 +206,9 @@ private uint InternalSendAsync(SNIPacket packet, SNIAsyncCallback callback)
207206
}
208207

209208
SNIPacket muxedPacket = SetPacketSMUXHeader(packet);
210-
muxedPacket.SetCompletionCallback(callback ?? HandleSendComplete);
209+
muxedPacket.SetAsyncIOCompletionCallback(_handleSendCompleteCallback);
211210
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, _sequenceNumber {1}, _sendHighwater {2}, Sending packet", args0: ConnectionId, args1: _sequenceNumber, args2: _sendHighwater);
212-
return _connection.SendAsync(muxedPacket, callback);
211+
return _connection.SendAsync(muxedPacket);
213212
}
214213
}
215214
}
@@ -222,7 +221,7 @@ private uint SendPendingPackets()
222221
{
223222
using (TrySNIEventScope.Create(nameof(SNIMarsHandle)))
224223
{
225-
SNIMarsQueuedPacket packet = null;
224+
SNIPacket packet = null;
226225

227226
while (true)
228227
{
@@ -233,7 +232,7 @@ private uint SendPendingPackets()
233232
if (_sendPacketQueue.Count != 0)
234233
{
235234
packet = _sendPacketQueue.Peek();
236-
uint result = InternalSendAsync(packet.Packet, packet.Callback);
235+
uint result = InternalSendAsync(packet);
237236

238237
if (result != TdsEnums.SNI_SUCCESS && result != TdsEnums.SNI_SUCCESS_IO_PENDING)
239238
{
@@ -264,15 +263,15 @@ private uint SendPendingPackets()
264263
/// Send a packet asynchronously
265264
/// </summary>
266265
/// <param name="packet">SNI packet</param>
267-
/// <param name="callback">Completion callback</param>
268266
/// <returns>SNI error code</returns>
269-
public override uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = null)
267+
public override uint SendAsync(SNIPacket packet)
270268
{
271269
using (TrySNIEventScope.Create(nameof(SNIMarsHandle)))
272270
{
271+
packet.SetAsyncIOCompletionCallback(_handleSendCompleteCallback);
273272
lock (this)
274273
{
275-
_sendPacketQueue.Enqueue(new SNIMarsQueuedPacket(packet, callback ?? _handleSendCompleteCallback));
274+
_sendPacketQueue.Enqueue(packet);
276275
}
277276

278277
SendPendingPackets();

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsQueuedPacket.cs

-30
This file was deleted.

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs

+4-5
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,10 @@ public override uint ReceiveAsync(ref SNIPacket packet)
210210
{
211211
SNIPacket errorPacket;
212212
packet = RentPacket(headerSize: 0, dataSize: _bufferSize);
213-
213+
packet.SetAsyncIOCompletionCallback(_receiveCallback);
214214
try
215215
{
216-
packet.ReadFromStreamAsync(_stream, _receiveCallback);
216+
packet.ReadFromStreamAsync(_stream);
217217
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Rented and read packet asynchronously, dataLeft {1}", args0: _connectionId, args1: packet?.DataLeft);
218218
return TdsEnums.SNI_SUCCESS_IO_PENDING;
219219
}
@@ -288,13 +288,12 @@ public override uint Send(SNIPacket packet)
288288
}
289289
}
290290

291-
public override uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = null)
291+
public override uint SendAsync(SNIPacket packet)
292292
{
293293
using (TrySNIEventScope.Create(nameof(SNINpHandle)))
294294
{
295-
SNIAsyncCallback cb = callback ?? _sendCallback;
296295
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Packet writing to stream, dataLeft {1}", args0: _connectionId, args1: packet?.DataLeft);
297-
packet.WriteToStreamAsync(_stream, cb, SNIProviders.NP_PROV);
296+
packet.WriteToStreamAsync(_stream, _sendCallback, SNIProviders.NP_PROV);
298297
return TdsEnums.SNI_SUCCESS_IO_PENDING;
299298
}
300299
}

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.cs

+21-30
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
using System;
88
using System.Buffers;
9-
using System.Collections.Generic;
109
using System.Diagnostics;
1110
using System.IO;
1211
using System.Threading;
@@ -19,14 +18,14 @@ namespace Microsoft.Data.SqlClient.SNI
1918
/// </summary>
2019
internal sealed class SNIPacket
2120
{
21+
private static readonly Action<Task<int>, object> s_readCallback = ReadFromStreamAsyncContinuation;
2222
private int _dataLength; // the length of the data in the data segment, advanced by Append-ing data, does not include smux header length
2323
private int _dataCapacity; // the total capacity requested, if the array is rented this may be less than the _data.Length, does not include smux header length
2424
private int _dataOffset; // the start point of the data in the data segment, advanced by Take-ing data
2525
private int _headerLength; // the amount of space at the start of the array reserved for the smux header, this is zeroed in SetHeader
2626
// _headerOffset is not needed because it is always 0
2727
private byte[] _data;
28-
private SNIAsyncCallback _completionCallback;
29-
private readonly Action<Task<int>, object> _readCallback;
28+
private SNIAsyncCallback _asyncIOCompletionCallback;
3029
#if DEBUG
3130
internal readonly int _id; // in debug mode every packet is assigned a unique id so that the entire lifetime can be tracked when debugging
3231
/// refcount = 0 means that a packet should only exist in the pool
@@ -85,7 +84,6 @@ public SNIPacket(SNIHandle owner, int id)
8584
#endif
8685
public SNIPacket()
8786
{
88-
_readCallback = ReadFromStreamAsyncContinuation;
8987
}
9088

9189
/// <summary>
@@ -110,25 +108,19 @@ public SNIPacket()
110108

111109
public int ReservedHeaderSize => _headerLength;
112110

113-
public bool HasCompletionCallback => !(_completionCallback is null);
111+
public bool HasAsyncIOCompletionCallback => _asyncIOCompletionCallback is not null;
114112

115113
/// <summary>
116-
/// Set async completion callback
114+
/// Set async receive callback
117115
/// </summary>
118-
/// <param name="completionCallback">Completion callback</param>
119-
public void SetCompletionCallback(SNIAsyncCallback completionCallback)
120-
{
121-
_completionCallback = completionCallback;
122-
}
116+
/// <param name="asyncIOCompletionCallback">Completion callback</param>
117+
public void SetAsyncIOCompletionCallback(SNIAsyncCallback asyncIOCompletionCallback) => _asyncIOCompletionCallback = asyncIOCompletionCallback;
123118

124119
/// <summary>
125-
/// Invoke the completion callback
120+
/// Invoke the receive callback
126121
/// </summary>
127122
/// <param name="sniErrorCode">SNI error</param>
128-
public void InvokeCompletionCallback(uint sniErrorCode)
129-
{
130-
_completionCallback(this, sniErrorCode);
131-
}
123+
public void InvokeAsyncIOCompletionCallback(uint sniErrorCode) => _asyncIOCompletionCallback(this, sniErrorCode);
132124

133125
/// <summary>
134126
/// Allocate space for data
@@ -253,7 +245,7 @@ public void Release()
253245
_dataLength = 0;
254246
_dataOffset = 0;
255247
_headerLength = 0;
256-
_completionCallback = null;
248+
_asyncIOCompletionCallback = null;
257249
IsOutOfBand = false;
258250
}
259251

@@ -273,49 +265,48 @@ public void ReadFromStream(Stream stream)
273265
/// Read data from a stream asynchronously
274266
/// </summary>
275267
/// <param name="stream">Stream to read from</param>
276-
/// <param name="callback">Completion callback</param>
277-
public void ReadFromStreamAsync(Stream stream, SNIAsyncCallback callback)
268+
public void ReadFromStreamAsync(Stream stream)
278269
{
279270
stream.ReadAsync(_data, 0, _dataCapacity, CancellationToken.None)
280271
.ContinueWith(
281-
continuationAction: _readCallback,
282-
state: callback,
272+
continuationAction: s_readCallback,
273+
state: this,
283274
CancellationToken.None,
284275
TaskContinuationOptions.DenyChildAttach,
285276
TaskScheduler.Default
286277
);
287278
}
288279

289-
private void ReadFromStreamAsyncContinuation(Task<int> t, object state)
280+
private static void ReadFromStreamAsyncContinuation(Task<int> task, object state)
290281
{
291-
SNIAsyncCallback callback = (SNIAsyncCallback)state;
282+
SNIPacket packet = (SNIPacket)state;
292283
bool error = false;
293-
Exception e = t.Exception?.InnerException;
284+
Exception e = task.Exception?.InnerException;
294285
if (e != null)
295286
{
296287
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, SNICommon.InternalExceptionError, e);
297288
#if DEBUG
298-
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIPacket), EventType.ERR, "Connection Id {0}, Internal Exception occurred while reading data: {1}", args0: _owner?.ConnectionId, args1: e?.Message);
289+
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIPacket), EventType.ERR, "Connection Id {0}, Internal Exception occurred while reading data: {1}", args0: packet._owner?.ConnectionId, args1: e?.Message);
299290
#endif
300291
error = true;
301292
}
302293
else
303294
{
304-
_dataLength = t.Result;
295+
packet._dataLength = task.Result;
305296
#if DEBUG
306-
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIPacket), EventType.INFO, "Connection Id {0}, Packet Id {1} _dataLength {2} read from stream.", args0: _owner?.ConnectionId, args1: _id, args2: _dataLength);
297+
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIPacket), EventType.INFO, "Connection Id {0}, Packet Id {1} _dataLength {2} read from stream.", args0: packet._owner?.ConnectionId, args1: packet._id, args2: packet._dataLength);
307298
#endif
308-
if (_dataLength == 0)
299+
if (packet._dataLength == 0)
309300
{
310301
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, 0, SNICommon.ConnTerminatedError, Strings.SNI_ERROR_2);
311302
#if DEBUG
312-
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIPacket), EventType.ERR, "Connection Id {0}, No data read from stream, connection was terminated.", args0: _owner?.ConnectionId);
303+
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIPacket), EventType.ERR, "Connection Id {0}, No data read from stream, connection was terminated.", args0: packet._owner?.ConnectionId);
313304
#endif
314305
error = true;
315306
}
316307
}
317308

318-
callback(this, error ? TdsEnums.SNI_ERROR : TdsEnums.SNI_SUCCESS);
309+
packet.InvokeAsyncIOCompletionCallback(error ? TdsEnums.SNI_ERROR : TdsEnums.SNI_SUCCESS);
319310
}
320311

321312
/// <summary>

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs

+4-6
Original file line numberDiff line numberDiff line change
@@ -813,14 +813,12 @@ public override void SetAsyncCallbacks(SNIAsyncCallback receiveCallback, SNIAsyn
813813
/// Send a packet asynchronously
814814
/// </summary>
815815
/// <param name="packet">SNI packet</param>
816-
/// <param name="callback">Completion callback</param>
817816
/// <returns>SNI error code</returns>
818-
public override uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = null)
817+
public override uint SendAsync(SNIPacket packet)
819818
{
820819
using (TrySNIEventScope.Create(nameof(SNITCPHandle)))
821820
{
822-
SNIAsyncCallback cb = callback ?? _sendCallback;
823-
packet.WriteToStreamAsync(_stream, cb, SNIProviders.TCP_PROV);
821+
packet.WriteToStreamAsync(_stream, _sendCallback, SNIProviders.TCP_PROV);
824822
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNITCPHandle), EventType.INFO, "Connection Id {0}, Data sent to stream asynchronously", args0: _connectionId);
825823
return TdsEnums.SNI_SUCCESS_IO_PENDING;
826824
}
@@ -835,10 +833,10 @@ public override uint ReceiveAsync(ref SNIPacket packet)
835833
{
836834
SNIPacket errorPacket;
837835
packet = RentPacket(headerSize: 0, dataSize: _bufferSize);
838-
836+
packet.SetAsyncIOCompletionCallback(_receiveCallback);
839837
try
840838
{
841-
packet.ReadFromStreamAsync(_stream, _receiveCallback);
839+
packet.ReadFromStreamAsync(_stream);
842840
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNITCPHandle), EventType.INFO, "Connection Id {0}, Data received from stream asynchronously", args0: _connectionId);
843841
return TdsEnums.SNI_SUCCESS_IO_PENDING;
844842
}

0 commit comments

Comments
 (0)