-
Notifications
You must be signed in to change notification settings - Fork 1.3k
CSHARP-5608: CSOT: Command Execution #1716
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
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.
Pull Request Overview
This PR introduces explicit handling of server round-trip time ("RTT") by expanding SelectServer
to return both a server and its RTT, and thread this RTT through various APIs and wire protocols to support operation timeouts and fail points.
- Update
SelectServer
andSelectServerAsync
to return(IServer server, TimeSpan roundTripTime)
. - Add
serverRoundTripTime
parameters toFailPoint.Configure
, binding constructors, andCommandWireProtocol
. - Inject RTT into command message sections for dynamic timeout calculation and update numerous tests to use the new overloads.
Reviewed Changes
Copilot reviewed 103 out of 103 changed files in this pull request and generated no comments.
Show a summary per file
File | Description |
---|---|
tests/MongoDB.Driver.Tests/UnifiedTestOperations/UnifiedTargetedFailPointOperation.cs | Destructure (server, roundTripTime) and pass RTT into FailPoint.Configure |
src/MongoDB.Driver/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs | Thread serverRoundTripTime into command creation and timeout logic |
src/MongoDB.Driver/OperationContextExtensions.cs | Add HasOperationTimeout and root context lookup |
src/MongoDB.Driver/Core/WireProtocol/CommandWireProtocol.cs | Update IWireProtocol methods to accept OperationContext and RTT |
tests/MongoDB.Driver.Tests/Core/Bindings/SingleServerReadWriteBindingTests.cs | Introduce RTT parameter in test constructors and add validation |
Comments suppressed due to low confidence (3)
src/MongoDB.Driver/Core/WireProtocol/CommandWireProtocol.cs:88
- [nitpick] The field
_serverRoundTripTime
is declared without XML doc. Add a brief comment explaining that this RTT is used for dynamic timeout calculations in command messages.
messageEncoderSettings,
src/MongoDB.Driver/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs:381
- OperationContext does not define a
RemainingTimeout
property. You should compute the remaining time from the original timeout and elapsed time, or add a helper onOperationContext
to expose the remaining timeout.
var serverTimeout = operationContext.RemainingTimeout - _serverRoundTripTime;
src/MongoDB.Driver/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs:630
RemainingTimeout
is not a member ofOperationContext
. Consider replacing this check with your new helper (e.g.,HasOperationTimeout
) or implement a properRemainingTimeout
getter.
if (operationContext.RemainingTimeout == Timeout.InfiniteTimeSpan)
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.
No major comments from me, just minor issues/questions
src/MongoDB.Driver/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs
Show resolved
Hide resolved
EndServerSelection(expirableClusterDescription.ClusterDescription, selector, result.ServerDescription, stopwatch); | ||
return result.Server; | ||
EndServerSelection(expirableClusterDescription.ClusterDescription, selector, description, stopwatch); | ||
return (server, description.AverageRoundTripTime); |
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.
Accordingly to CSOT spec we should use MinRoundTripTime here, but CSharp driver do not track it yet, we have only AverageRoundTripTime. We decided to go with the AverageRoundTripTime and replace it on the later stages of CSOT implementation. More over there is a chance that RTT will be removed from maxTimeMs calculation at all.
Find more details in the https://jira.mongodb.org/browse/CSHARP-5627
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.
LGTM
@@ -61,10 +64,45 @@ public TimeSpan RemainingTimeout | |||
} | |||
} | |||
|
|||
[Obsolete("Do not use this property, unless it's needed to avoid breaking changes in public API")] | |||
public CancellationToken CombinedCancellationToken |
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.
We have a number of use-cases when we cannot update the interfaces, because they are public (I've run into at least 2 cases like that: IStreamFactory
and ISaslStep
), so we have to squeeze both: cancellation token itself and timeout into linked cancellation token. Having such CombinedCancellationToken
on operation context allow us to reuse instantiated CancellationTokenSource
s. Also I've marked the property as obsolete, so we easily can find all usages and replace with some interface changes in next major release.
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.
Is [Obsolete]
really useful here?
When this property is removed the compiler will tell us where it is used.
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.
Yep, as I do not want to encourage more usages of the property.
@@ -94,7 +115,7 @@ public void WaitTask(Task task) | |||
} | |||
|
|||
var timeout = RemainingTimeout; | |||
if (timeout != System.Threading.Timeout.InfiniteTimeSpan && timeout < TimeSpan.Zero) |
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.
RemainingTimeout
returns TimeSpan.Zero
if timed out now, so the check could be simplified.
{ | ||
var remainingTimeout = RemainingTimeout; | ||
if (remainingTimeout == System.Threading.Timeout.InfiniteTimeSpan) |
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.
RemainingTimeout
returns TimeSpan.Zero
if timed out now, so the check could be simplified.
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.
LGTM!
@@ -61,10 +64,45 @@ public TimeSpan RemainingTimeout | |||
} | |||
} | |||
|
|||
[Obsolete("Do not use this property, unless it's needed to avoid breaking changes in public API")] | |||
public CancellationToken CombinedCancellationToken |
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.
Is [Obsolete]
really useful here?
When this property is removed the compiler will tell us where it is used.
{ | ||
get { return _reference.Instance.Session; } | ||
} | ||
public TimeSpan RoundTripTime => _reference.Instance.RoundTripTime; |
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.
Not needed if we use ISelectedServer
interface.
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.
In fact this file probably needs NO changes.
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.
Reverted most of the changes.
@@ -27,25 +27,21 @@ internal sealed class ChannelReadBinding : IReadBinding | |||
private bool _disposed; | |||
private readonly ReadPreference _readPreference; | |||
private readonly IServer _server; | |||
private readonly TimeSpan _roundTripTime; |
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 file needs NO changes if we use the new ISelectedServer
interface.
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.
Reverted.
@@ -26,24 +26,20 @@ internal sealed class ChannelReadWriteBinding : IReadWriteBinding | |||
private readonly IChannelHandle _channel; | |||
private bool _disposed; | |||
private readonly IServer _server; | |||
private readonly TimeSpan _serverRoundTripTime; |
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 file needs NO changes if we use the new ISelectedServer
interface.
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.
Reverted.
@@ -72,7 +65,6 @@ public void Dispose() | |||
{ | |||
_reference.DecrementReferenceCount(); | |||
_disposed = true; | |||
GC.SuppressFinalize(this); |
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.
Why did you remove this line?
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.
As far as I know there is no reason to call GC.SuppressFinalize
on class without finalizer.
@@ -49,6 +49,7 @@ internal sealed class CommandUsingCommandMessageWireProtocol<TCommandResult> : I | |||
private readonly CommandResponseHandling _responseHandling; | |||
private readonly IBsonSerializer<TCommandResult> _resultSerializer; | |||
private readonly ServerApi _serverApi; | |||
private readonly TimeSpan _serverRoundTripTime; |
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.
Should name be _minRoundTripTime
?
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 prefer _roundTripTime
, I suppose the fact that this is suppose to be Min is kind of secondary here. The main thing here - this is round trip time that need to be used in the calculation. Especially now, when we do not support MinRoundTripTime yet.
@@ -369,6 +376,12 @@ private Type0CommandMessageSection<BsonDocument> CreateType0Section(ConnectionDe | |||
} | |||
} | |||
|
|||
if (operationContext.IsOperationTimeoutConfigured()) | |||
{ | |||
var serverTimeout = operationContext.RemainingTimeout - _serverRoundTripTime; |
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.
We need to handle the possibility that serverTimeout
will be negative here.
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.
Yep. Good catch!
@@ -45,6 +44,7 @@ internal sealed class CommandWireProtocol<TCommandResult> : IWireProtocol<TComma | |||
private readonly CommandResponseHandling _responseHandling; | |||
private readonly IBsonSerializer<TCommandResult> _resultSerializer; | |||
private readonly ServerApi _serverApi; | |||
private readonly TimeSpan _serverRoundTripTime; |
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.
Should name be _minRoundTripTime
?
@@ -32,6 +32,7 @@ public static IReadBindingHandle CreateReadBinding(IClusterInternal cluster, ICo | |||
{ | |||
readBinding = new ChannelReadWriteBinding( | |||
session.CurrentTransaction.PinnedServer, | |||
session.CurrentTransaction.PinnedServerRoundTripTime, |
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 file needs NO changes if we use the new ISelectedServer
interface.
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.
Reverted
@@ -1003,33 +1003,33 @@ private IReadBindingHandle GetSingleServerReadBinding(OperationContext operation | |||
{ | |||
var readPreference = _options.ReadPreference ?? _database.Settings.ReadPreference; | |||
var selector = new ReadPreferenceServerSelector(readPreference); | |||
var server = _cluster.SelectServer(operationContext, selector); | |||
var binding = new SingleServerReadBinding(server, readPreference, NoCoreSession.NewHandle()); | |||
var (server, serverRoundTripTime) = _cluster.SelectServer(operationContext, selector); |
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 file needs NO changes if we use the new ISelectedServer
interface.
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.
Reverted
{ | ||
get { return _server; } | ||
} | ||
public IServer Server => _server; |
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 file now only has cosmetic changes.
Up to you whether they belong in this PR or not.
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.
Will keep
@@ -172,8 +192,12 @@ public void Invalidate(string reasonInvalidated, TopologyVersion responseTopolog | |||
|
|||
public abstract void RequestHeartbeat(); | |||
|
|||
// protected methods | |||
public void ReturnConnection(IConnectionHandle connection) |
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.
We're not actually returning the connection at all here. The connection parameter is ignored.
I suggest naming this method DecrementOutstandingOperationsCount
.
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.
Done
private readonly IConnectionHandle _connection; | ||
private readonly IServer _server; | ||
private readonly InterlockedInt32 _state; | ||
private readonly bool _ownConnection; |
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.
Keep the original name for this field: _decrementOperationsCount
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.
Done
|
||
IChannelHandle GetChannel(OperationContext operationContext); | ||
Task<IChannelHandle> GetChannelAsync(OperationContext operationContext); | ||
void HandleChannelException(IConnectionHandle connection, Exception exception); | ||
void ReturnConnection(IConnectionHandle connection); |
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.
Name this method DecrementOutstandingOperationsCount
.
A future refactoring might improve how we keep track of the operations count and might result in this method not being necessary in the future.
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.
Done
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.
LGTM
{ | ||
if (_decrementOperationsCount) | ||
{ | ||
_server.DecrementOutstandingOperationsCount(); |
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.
Github PR doesn't show what this line used to be because it was in a different file, but with the latest changes this line changed from:
Interlocked.Decrement(ref _server._outstandingOperationsCount);
to this.
Now it is much clearer that we are preserving existing behavior!
No description provided.