Skip to content

Conversation

sanych-sun
Copy link
Member

No description provided.

@sanych-sun sanych-sun requested a review from a team as a code owner August 18, 2025 16:24
@sanych-sun sanych-sun requested review from ajcvickers and removed request for a team and ajcvickers August 18, 2025 16:24

var stream = new NetworkStream(socket, true);

if (_settings.ReadTimeout.HasValue)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read and Write timeout now is being applied by BinaryConnection.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to move this out, because socketTimeout is deprecated by CSOT timeout if it was provided. So we have to apply both in the same level, otherwise it could be a confusion which timeout should be enforced. Even if we applied socket_timeout here briefly and remove on BinaryConnection, we could run into socket timeout when SSL stream authentication.

Copy link
Contributor

@BorisDog BorisDog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial review

var waitQueueTimeout = _pool.Settings.WaitQueueTimeout;
if (operationContext.RemainingTimeout != Timeout.InfiniteTimeSpan)
{
waitQueueTimeout = operationContext.RemainingTimeout < _pool.Settings.WaitQueueTimeout ? operationContext.RemainingTimeout : _pool.Settings.WaitQueueTimeout;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need Max(TimeSpan) extension method yet :) ?
And then MaxIgnoreInfinite...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code was rewritten a little to be more readable.

@@ -223,7 +244,8 @@ public async Task<IConnectionHandle> AcquireConnectionAsync(OperationContext ope

using (var connectionCreator = new ConnectionCreator(_pool))
{
pooledConnection = await connectionCreator.CreateOpenedOrReuseAsync(operationContext).ConfigureAwait(false);
waitQueueTimeout = _pool.CalculateRemainingTimeout(waitQueueTimeout, stopwatch);
pooledConnection = await connectionCreator.CreateOpenedOrReuseAsync(operationContext, waitQueueTimeout - stopwatch.Elapsed).ConfigureAwait(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct?

waitQueueTimeout := waitQueueTimeout - elapsed // Remaining
And then another waitQueueTimeout - stopwatch.Elapsed (==waitQueueTimeout - elapsed * 2) in
CreateOpenedOrReuseAsync(operationContext, waitQueueTimeout - stopwatch.Elapsed) ?

If this is a bug, no tests to catch this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Thank you! I've spotted the problem in sync code path, but forget to do the same fix into async code-path.
Fixed.

@sanych-sun sanych-sun requested a review from BorisDog August 25, 2025 23:42
while (count > 0)
{
var timeout = hasOperationTimeout ? operationContext.RemainingTimeout : streamTimeout;
var timeout = operationContext.Timeout == null ? socketTimeout : operationContext.RemainingTimeout;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.RemainingTimeoutOrDefaut(defaultTimeout) ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -223,7 +244,8 @@ public async Task<IConnectionHandle> AcquireConnectionAsync(OperationContext ope

using (var connectionCreator = new ConnectionCreator(_pool))
{
pooledConnection = await connectionCreator.CreateOpenedOrReuseAsync(operationContext).ConfigureAwait(false);
waitQueueTimeout = _pool.CalculateRemainingTimeout(waitQueueTimeout, stopwatch);
pooledConnection = await connectionCreator.CreateOpenedOrReuseAsync(operationContext, waitQueueTimeout).ConfigureAwait(false);
Copy link
Contributor

@BorisDog BorisDog Aug 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So no failing tests for this previous issue?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non of existing tests were failing.

SkipNotSupportedTestCases("timeoutMS applies to whole operation, not individual attempts"); // blocked by DRIVERS-3247
SkipNotSupportedTestCases("WaitQueueTimeoutError does not clear the pool"); // TODO: CSOT: TimeoutMS is not implemented yet for runCommand
SkipNotSupportedTestCases("write concern error MaxTimeMSExpired is transformed"); // TODO: CSOT: investigate error transformation, implementing the requirement might be breaking change
SkipNotSupportedTestCases("operation succeeds after one socket timeout - listDatabases on client"); // TODO: listDatabases is not retryable in CSharp Driver, NEED TICKET!!!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ticket created :)

@@ -317,17 +317,17 @@ void ICoreSessionInternal.CommitTransaction(CommitTransactionOptions options, Ca

try
{
var firstAttempt = CreateCommitTransactionOperation(IsFirstCommitAttemptRetry());
var firstAttempt = CreateCommitTransactionOperation(operationContext,IsFirstCommitAttemptRetry());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing space after comma

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

{
// unpin server if needed, then ignore exception and retry
TransactionHelper.UnpinServerIfNeededOnRetryableCommitException(_currentTransaction, exception);
}

var secondAttempt = CreateCommitTransactionOperation(isCommitRetry: true);
var secondAttempt = CreateCommitTransactionOperation(operationContext,isCommitRetry: true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing space after comma

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@@ -33,7 +34,7 @@ public void Compress(Stream input, Stream output)
{
var uncompressedSize = (int)(input.Length - input.Position);
var uncompressedBytes = new byte[uncompressedSize]; // does not include uncompressed message headers
input.ReadBytes(OperationContext.NoTimeout, uncompressedBytes, offset: 0, count: uncompressedSize);
input.ReadBytes(OperationContext.NoTimeout, uncompressedBytes, offset: 0, count: uncompressedSize, Timeout.InfiniteTimeSpan);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use a named argument for the socketTimeout here? so its clear at a glance what that Timeout value at the end is for.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

break;
case "readConcern":
options = options ?? new TransactionOptions();
options = options.With(readConcern: ReadConcern.FromBsonDocument(argument.Value.AsBsonDocument));
readConcern =ReadConcern.FromBsonDocument(argument.Value.AsBsonDocument);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing space after =

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@sanych-sun sanych-sun requested a review from adelinowona August 26, 2025 19:10
Copy link
Contributor

@BorisDog BorisDog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few minor comments

@@ -223,7 +244,8 @@ public async Task<IConnectionHandle> AcquireConnectionAsync(OperationContext ope

using (var connectionCreator = new ConnectionCreator(_pool))
{
pooledConnection = await connectionCreator.CreateOpenedOrReuseAsync(operationContext).ConfigureAwait(false);
waitQueueTimeout = _pool.CalculateRemainingTimeout(waitQueueTimeout, stopwatch);
pooledConnection = await connectionCreator.CreateOpenedOrReuseAsync(operationContext, waitQueueTimeout).ConfigureAwait(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public static bool IsRootContextTimeoutConfigured(this OperationContext operationContext) =>
operationContext.RootContext.Timeout.HasValue;

public static TimeSpan RemainingTimeoutOrDefault(this OperationContext operationContext, TimeSpan defaultValue) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth adding a test.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OperationContextExtensionsTests test class was created.

@@ -322,6 +321,7 @@ private HelloResult GetHelloResult(

private void Heartbeat(CancellationToken cancellationToken)
{
using var operationContext = new OperationContext(null, cancellationToken);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather not have this unless there is a timeout that encompasses the entire heartbeat cycle (I doubt we have that). InitializeConnection and GetHelloResult could use their own independent OperationContext instances.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it was discussed offline: we will keep the code as is for now.

BorisDog
BorisDog previously approved these changes Aug 28, 2025
Copy link
Contributor

@BorisDog BorisDog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM + nit comment

using MongoDB.Driver.Core.Misc;
using Xunit;

namespace MongoDB.Driver.Tests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File scoped namespace?

adelinowona
adelinowona previously approved these changes Aug 28, 2025
Copy link
Contributor

@adelinowona adelinowona left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@sanych-sun sanych-sun dismissed stale reviews from adelinowona and BorisDog via 613f693 August 28, 2025 19:48
Copy link
Contributor

@BorisDog BorisDog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@sanych-sun sanych-sun merged commit c91f85a into mongodb:main Aug 28, 2025
27 of 29 checks passed
@sanych-sun sanych-sun deleted the csharp5695 branch August 28, 2025 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants