-
Notifications
You must be signed in to change notification settings - Fork 1.3k
CSHARP-3671: Better wait queue timeout errors for load balanced clusters. #579
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
f7f627e
to
0f5b393
Compare
var numberOfCheckOutsForCursor = pool._checkedOutTracker.GetCheckedOutNumber(CheckedOutReason.Cursor); | ||
var numberOfCheckOutsForTransaction = pool._checkedOutTracker.GetCheckedOutNumber(CheckedOutReason.Transaction); | ||
|
||
var message = numberOfCheckOutsForCursor == 0 && numberOfCheckOutsForTransaction == 0 |
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 logic is copied from java, if we have no checkouts for transaction or cursor, we use old variant of exception message
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.
also, this logic can be simplified if in the current master version we will leave only one timeout exception message (we have two that are a bit different), it looks like a single timeout error message is how java behaves.
But I will be ok with the current way also. cc: @rstam
@@ -104,14 +104,14 @@ public override IAsyncCursor<TResult> Aggregate<TResult>(IClientSessionHandle se | |||
var forkedSession = session.Fork(); | |||
var deferredCursor = new DeferredAsyncCursor<TResult>( | |||
() => forkedSession.Dispose(), | |||
ct => ExecuteReadOperation(forkedSession, findOperation, ReadPreference.Primary, ct), | |||
ct => ExecuteReadOperationAsync(forkedSession, findOperation, ReadPreference.Primary, ct)); | |||
ct => ExecuteReadOperation(forkedSession, findOperation, ReadPreference.Primary, doesInitiateCursor: true, ct), |
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 theory we can avoid such changes via analyzing an operation type (which is like IReadOperation<IAsyncCursor<TResult>>
), but I didn't find a way to do it without reflection which can reduce performance
@@ -63,7 +63,7 @@ public async Task<OperationResult> ExecuteAsync(CancellationToken cancellationTo | |||
? await _database.ListCollectionsAsync(_options, cancellationToken) | |||
: await _database.ListCollectionsAsync(_session, _options, cancellationToken); | |||
|
|||
_ = cursor.ToListAsync(cancellationToken); | |||
_ = await cursor.ToListAsync(cancellationToken); |
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 and below are changes from a different PR
0f5b393
to
a610696
Compare
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.
Please re-request my review when you've added the new commit you said you were working on.
The latest 2 commits contains simplifying of the logic in this PR:
|
ee358f6
to
0805ff0
Compare
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 like this approach a lot. It makes sense.
Don't be dismayed by the number of requested changes. They are almost all requests to rename something.
Requested changes prototyped here:
https://github.com/rstam/mongo-csharp-driver/tree/csharp3671-0722
@@ -29,6 +29,7 @@ namespace MongoDB.Driver.Core.ConnectionPools | |||
internal sealed partial class ExclusiveConnectionPool : IConnectionPool | |||
{ | |||
// fields | |||
private readonly CheckedOutTracker _checkedOutTracker; |
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.
private readonly CheckoutReasonCounter _checkoutReasonCounter;
@@ -71,6 +72,7 @@ internal sealed partial class ExclusiveConnectionPool : IConnectionPool | |||
_connectionFactory = Ensure.IsNotNull(connectionFactory, nameof(connectionFactory)); | |||
Ensure.IsNotNull(eventSubscriber, nameof(eventSubscriber)); | |||
|
|||
_checkedOutTracker = new CheckedOutTracker(); |
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.
_checkoutReasonCounter = new CheckoutReasonCounter();
@@ -385,6 +387,8 @@ private void ReleaseConnection(PooledConnection connection) | |||
_checkedInConnectionEventHandler(new ConnectionPoolCheckedInConnectionEvent(connection.ConnectionId, TimeSpan.Zero, EventContext.OperationId)); | |||
} | |||
|
|||
_checkedOutTracker.CheckInIfNotNull(connection.CheckedOutReason); |
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.
_checkoutReasonCounter.Decrement(connection.CheckoutReason);
src/MongoDB.Driver.Core/Core/ConnectionPools/ExclusiveConnectionPool.Helpers.cs
Show resolved
Hide resolved
@@ -39,6 +39,23 @@ private static class State | |||
public const int Disposed = 2; | |||
} | |||
|
|||
private static Exception CreateEffectiveTimeoutException(string defaultExceptionMessage, ExclusiveConnectionPool pool, Stopwatch stopwatch) |
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 should be an instance method of the ExclusiveConnectionPool:
// private methods
private Exception CreateTimeoutException(Stopwatch stopwatch, string message)
{
var checkoutsForCursorCount = _checkoutReasonCounter.GetCheckoutsCount(CheckoutReason.Cursor);
var checkoutsForTransactionCount = _checkoutReasonCounter.GetCheckoutsCount(CheckoutReason.Transaction);
// only use the expanded message format when connected to a load balancer
if (checkoutsForCursorCount != 0 || checkoutsForTransactionCount != 0)
{
var maxPoolSize = _settings.MaxConnections;
var availableConnectionsCount = AvailableCount;
var checkoutsCount = maxPoolSize - availableConnectionsCount;
var checkoutsForOtherCount = checkoutsCount - checkoutsForCursorCount - checkoutsForTransactionCount;
message =
$"Timed out after {stopwatch.ElapsedMilliseconds}ms waiting for a connection from the connection pool. " +
$"maxPoolSize: {maxPoolSize}, " +
$"connections in use by cursors: {checkoutsForCursorCount}, " +
$"connections in use by transactions: {checkoutsForTransactionCount}, " +
$"connections in use by other operations: {checkoutsForOtherCount}.";
}
return new TimeoutException(message);
}
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.
Also... move to after line 33 (this is not a nested class).
Note: yet another reason why this should not be a partial class. This is an instance method of the ExclusiveConnectionPool
class. According to the split of this class into two files (which I disagree with) this instance method should be in the ExclusiveConnectionPool.cs
file, BUT... it is only used in this file.
So where should it go?
Yet another example of why this is not how partial classes should be used.
} | ||
} | ||
|
||
public void CheckInIfNotNull(CheckedOutReason? reason) |
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.
public void Decrement(CheckoutReason? reason)
// should not be reached | ||
throw new InvalidOperationException($"Unsupported checked out reason {reason}."); | ||
} | ||
} |
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.
Replace 71-88 with:
switch (reason)
{
case null:
break;
case CheckoutReason.Cursor:
Interlocked.Decrement(ref _cursorCheckoutsCount);
break;
case CheckoutReason.Transaction:
Interlocked.Decrement(ref _transactionCheckoutsCount);
break;
default:
throw new InvalidOperationException($"Invalid checkout reason {reason}.");
}
|
||
// pinning channel |
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.
Do you mean?
// pin to channel
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 meant that this is pinning implementation(to cursor) requested in the ticket: Update connection pinning logic for LB mode
, I will just remove this comment
{ | ||
session.CurrentTransaction.PinChannel(channel.Fork()); | ||
session.CurrentTransaction.PinnedServer = server; | ||
trackedConnection.SetPinningCheckoutReasonIfNotAlreadySet(CheckedOutReason.Transaction); |
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.
if (channel.Connection is ICheckoutReasonTracker checkoutReasonTracker)
{
checkoutReasonTracker.SetCheckoutReasonIfNotAlreadySet(CheckoutReason.Transaction);
}
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.
ready for review
|
||
namespace MongoDB.Driver.Core.ConnectionPools | ||
{ | ||
internal enum CheckedOutReason |
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.
previously it shown a difference between Event*ing*
and Event*ed*
, but now it's useless anymore, done
|
||
// pinning channel |
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 meant that this is pinning implementation(to cursor) requested in the ticket: Update connection pinning logic for LB mode
, I will just remove this comment
{ | ||
session.CurrentTransaction.PinChannel(channel.Fork()); | ||
session.CurrentTransaction.PinnedServer = server; | ||
trackedConnection.SetPinningCheckoutReasonIfNotAlreadySet(CheckedOutReason.Transaction); |
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
break; | ||
default: | ||
// should not be reached | ||
throw new InvalidOperationException($"Unsupported checked out reason {reason}."); |
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
@@ -0,0 +1,91 @@ | |||
/*Copyright 2021 - present MongoDB Inc. |
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
{ | ||
internal enum CheckedOutReason | ||
{ | ||
NotSet, |
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, this was a bug, originally I set reason for any checkout operations, now it's not and I missed this case
Transaction | ||
} | ||
|
||
internal interface ITrackedPinningReason |
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 (looks great to me)
…ers. (mongodb#579) CSHARP-3671: Better wait queue timeout errors for load balanced clusters.
No description provided.