-
Notifications
You must be signed in to change notification settings - Fork 292
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial Commit of Transport Creation Handler #2569
Initial Commit of Transport Creation Handler #2569
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few performance comments, but I'm looking forward to seeing how this pans out!
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/IpAddressVersionComparer.cs
Outdated
Show resolved
Hide resolved
throw new NotImplementedException(); | ||
|
||
case TcpTransportCreationParams tcpParams: | ||
request.ConnectionStream = await HandleTcpRequest(tcpParams, ct).ConfigureAwait(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like it'd introduce sync-over-async via Dns.GetHostAddressesAsync
and OpenSocketAsync
. There are some situations (MultiSubnetFailover == Enabled) where that's unavoidable because we need to connect to all IP addresses in parallel, but in most cases it's possible to open a connection synchronously without waiting on the thread pool.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I spent sometime reading up on this and digging through the code for the calls, but I'm not sure I see the sync-over-asyn anti-pattern going on. It looks like Dns.GetHostAddressesAsync
isn't really async, but Socket.ConnectAsync
is definitely async. I could change the call to get the addresses to use the sync method, but I think we're justified in using async for connecting. It sounds like you might know more about this than I do, so please let me know if I'm missing something.
This might also be a time for using one of those ValueTask
s I've heard so much about 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking of a case where we call the method with isAsync
set to false. Because isAsync
is never passed down to HandleTcpRequest
, it's effectively always asynchronous. A caller who waits on Handle is wrapping a synchronous operation around async operations occurring on the thread pool (sync-over-async.) Your points around Dns.GetHostAddressesAsync
and Socket.ConnectAsync
are absolutely correct, but protect against thread-level blocking within a task (async-over-sync.)
There's a minor (but immediate) performance hit because we might now allocate Tasks. There's also a more subtle one which is a pain point for the current iteration of SqlClient, which is that if the thread pool is heavily loaded it could be some time until the thread pool has enough capacity to start the work. A caller wouldn't necessarily expect that if MultiSubnetFailover is disabled. In the worst case, both sync-over-async and async-over-sync can cause deadlocks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the Sync path would need a separate flow where the sync versions of DNS and sockets are used, rather than relying on the async overloads. Likely in this PR it would make sense to throw
or add a TODO to say Sync is to be supported.
For MSF in sync mode, sync over async will suffer from the problems @edwardneal mentioned. However a potential path forward for sync mode is to open all sockets in non-blocking mode, and later check using Socket.Select to see which one is writeable for the timeout duration, and return that particular socket.
This way the I/O is used for socket open parallelization, and we dont rely on sync over async.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either a throw
or a TODO is fine by me, so long as the problem's raised explicitly rather than implicitly - getting the correct behaviour from various scenarios of MSF/TNIR/connection timeouts would probably be better handled separately.
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...ata.SqlClient/netcore/src/Microsoft/Data/SqlClientX/Handlers/Connection/ConnectionRequest.cs
Outdated
Show resolved
Hide resolved
.../netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationParams.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/NamedPipeTransportCreationParams.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIProxy.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Outdated
Show resolved
Hide resolved
|
||
private async ValueTask<Socket> OpenSocket(IPEndPoint ipEndPoint, bool isAsync, CancellationToken ct) | ||
{ | ||
ct.ThrowIfCancellationRequested(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For sync cases, the callers will provide a default
Cancellation token. the ct.ThrowIfCancellationRequested() may not be needed in sync paths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to utilize the cancellation token as the way to signal that either the timeout has expired or the user has requested cancellation. This will be adopted in a later PR. As such, I think it would still be valuable to keep the cancellation token in the sync code path. @edwardneal had a good suggestion for how to cancel while the socket is opening by registering event on the cancellation token.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am still not sure how this would look end to end. If this theory holds, then great, else we will modify.
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Show resolved
Hide resolved
...netcore/src/Microsoft/Data/SqlClientX/Handlers/TransportCreation/TransportCreationHandler.cs
Show resolved
Hide resolved
CI build didn't kick off. It builds locally and unit tests work, so I think it's fine. Feel free to annoy me if I broke branch. |
Description: Handler that creates the transport for a connection request chain of responsibility. It only works for TCP connections right now. IP addresses are looked up, if there is a preference for IPv4 or IPv6, the list is sorted and each one is tried until one connects or all fail.
Exceptions still need to be properly handled.
Testing: Everything builds :)