2929
3030namespace MongoDB . Driver . Core . ConnectionPools
3131{
32- internal sealed partial class ExclusiveConnectionPool : IConnectionPool
32+ internal sealed partial class ExclusiveConnectionPool
3333 {
34+ // private methods
35+ private Exception CreateTimeoutException ( Stopwatch stopwatch , string message )
36+ {
37+ var checkOutsForCursorCount = _checkOutReasonCounter . GetCheckOutsCount ( CheckOutReason . Cursor ) ;
38+ var checkOutsForTransactionCount = _checkOutReasonCounter . GetCheckOutsCount ( CheckOutReason . Transaction ) ;
39+
40+ // only use the expanded message format when connected to a load balancer
41+ if ( checkOutsForCursorCount != 0 || checkOutsForTransactionCount != 0 )
42+ {
43+ var maxPoolSize = _settings . MaxConnections ;
44+ var availableConnectionsCount = AvailableCount ;
45+ var checkOutsCount = maxPoolSize - availableConnectionsCount ;
46+ var checkOutsForOtherCount = checkOutsCount - checkOutsForCursorCount - checkOutsForTransactionCount ;
47+
48+ message =
49+ $ "Timed out after { stopwatch . ElapsedMilliseconds } ms waiting for a connection from the connection pool. " +
50+ $ "maxPoolSize: { maxPoolSize } , " +
51+ $ "connections in use by cursors: { checkOutsForCursorCount } , " +
52+ $ "connections in use by transactions: { checkOutsForTransactionCount } , " +
53+ $ "connections in use by other operations: { checkOutsForOtherCount } .";
54+ }
55+
56+ return new TimeoutException ( message ) ;
57+ }
58+
3459 // nested classes
3560 private static class State
3661 {
@@ -125,7 +150,7 @@ private AcquiredConnection FinalizePoolEnterance(PooledConnection pooledConnecti
125150 _stopwatch . Stop ( ) ;
126151
127152 var message = $ "Timed out waiting for a connection after { _stopwatch . ElapsedMilliseconds } ms.";
128- throw new TimeoutException ( message ) ;
153+ throw _pool . CreateTimeoutException ( _stopwatch , message ) ;
129154 }
130155 }
131156
@@ -173,8 +198,9 @@ public void HandleException(Exception ex)
173198 }
174199 }
175200
176- private sealed class PooledConnection : IConnection
201+ private sealed class PooledConnection : IConnection , ICheckOutReasonTracker
177202 {
203+ private CheckOutReason ? _checkOutReason ;
178204 private readonly IConnection _connection ;
179205 private readonly ExclusiveConnectionPool _connectionPool ;
180206 private int _generation ;
@@ -187,6 +213,14 @@ public PooledConnection(ExclusiveConnectionPool connectionPool, IConnection conn
187213 _generation = connectionPool . _generation ;
188214 }
189215
216+ public CheckOutReason ? CheckOutReason
217+ {
218+ get
219+ {
220+ return _checkOutReason ;
221+ }
222+ }
223+
190224 public ConnectionId ConnectionId
191225 {
192226 get { return _connection . ConnectionId ; }
@@ -313,6 +347,15 @@ public async Task SendMessagesAsync(IEnumerable<RequestMessage> messages, Messag
313347 }
314348 }
315349
350+ public void SetCheckOutReasonIfNotAlreadySet ( CheckOutReason reason )
351+ {
352+ if ( _checkOutReason == null )
353+ {
354+ _checkOutReason = reason ;
355+ _connectionPool . _checkOutReasonCounter . Increment ( reason ) ;
356+ }
357+ }
358+
316359 public void SetReadTimeout ( TimeSpan timeout )
317360 {
318361 _connection . SetReadTimeout ( timeout ) ;
@@ -335,7 +378,7 @@ private void SetEffectiveGenerationIfRequired(ConnectionDescription description)
335378 }
336379 }
337380
338- private sealed class AcquiredConnection : IConnectionHandle
381+ private sealed class AcquiredConnection : IConnectionHandle , ICheckOutReasonTracker
339382 {
340383 private ExclusiveConnectionPool _connectionPool ;
341384 private bool _disposed ;
@@ -347,6 +390,14 @@ public AcquiredConnection(ExclusiveConnectionPool connectionPool, ReferenceCount
347390 _reference = reference ;
348391 }
349392
393+ public CheckOutReason ? CheckOutReason
394+ {
395+ get
396+ {
397+ return _reference . Instance . CheckOutReason ;
398+ }
399+ }
400+
350401 public ConnectionId ConnectionId
351402 {
352403 get { return _reference . Instance . ConnectionId ; }
@@ -432,6 +483,12 @@ public Task SendMessagesAsync(IEnumerable<RequestMessage> messages, MessageEncod
432483 return _reference . Instance . SendMessagesAsync ( messages , messageEncoderSettings , cancellationToken ) ;
433484 }
434485
486+ public void SetCheckOutReasonIfNotAlreadySet ( CheckOutReason reason )
487+ {
488+ ThrowIfDisposed ( ) ;
489+ _reference . Instance . SetCheckOutReasonIfNotAlreadySet ( reason ) ;
490+ }
491+
435492 public void SetReadTimeout ( TimeSpan timeout )
436493 {
437494 ThrowIfDisposed ( ) ;
@@ -674,15 +731,15 @@ public PooledConnection CreateOpenedOrReuse(CancellationToken cancellationToken)
674731 {
675732 SemaphoreSlimSignalable . SemaphoreWaitResult . Signaled => _pool . _connectionHolder . Acquire ( ) ,
676733 SemaphoreSlimSignalable . SemaphoreWaitResult . Entered => CreateOpenedInternal ( cancellationToken ) ,
677- SemaphoreSlimSignalable . SemaphoreWaitResult . TimedOut => throw new TimeoutException ( $ "Timed out waiting in connecting queue after { stopwatch . ElapsedMilliseconds } ms." ) ,
734+ SemaphoreSlimSignalable . SemaphoreWaitResult . TimedOut => throw CreateTimeoutException ( stopwatch ) ,
678735 _ => throw new InvalidOperationException ( $ "Invalid wait result { _connectingWaitStatus } ")
679736 } ;
680737
681738 waitTimeout = _connectingTimeout - stopwatch . Elapsed ;
682739
683740 if ( connection == null && waitTimeout <= TimeSpan . Zero )
684741 {
685- throw TimoutException ( stopwatch ) ;
742+ throw CreateTimeoutException ( stopwatch ) ;
686743 }
687744 }
688745
@@ -708,15 +765,15 @@ public async Task<PooledConnection> CreateOpenedOrReuseAsync(CancellationToken c
708765 {
709766 SemaphoreSlimSignalable . SemaphoreWaitResult . Signaled => _pool . _connectionHolder . Acquire ( ) ,
710767 SemaphoreSlimSignalable . SemaphoreWaitResult . Entered => await CreateOpenedInternalAsync ( cancellationToken ) . ConfigureAwait ( false ) ,
711- SemaphoreSlimSignalable . SemaphoreWaitResult . TimedOut => throw TimoutException ( stopwatch ) ,
768+ SemaphoreSlimSignalable . SemaphoreWaitResult . TimedOut => throw CreateTimeoutException ( stopwatch ) ,
712769 _ => throw new InvalidOperationException ( $ "Invalid wait result { _connectingWaitStatus } ")
713770 } ;
714771
715772 waitTimeout = _connectingTimeout - stopwatch . Elapsed ;
716773
717774 if ( connection == null && waitTimeout <= TimeSpan . Zero )
718775 {
719- throw TimoutException ( stopwatch ) ;
776+ throw CreateTimeoutException ( stopwatch ) ;
720777 }
721778 }
722779
@@ -783,8 +840,11 @@ private void FinishCreating(ConnectionDescription description)
783840 _pool . _serviceStates . IncrementConnectionCount ( description ? . ServiceId ) ;
784841 }
785842
786- private Exception TimoutException ( Stopwatch stopwatch ) =>
787- new TimeoutException ( $ "Timed out waiting in connecting queue after { stopwatch . ElapsedMilliseconds } ms.") ;
843+ private Exception CreateTimeoutException ( Stopwatch stopwatch )
844+ {
845+ var message = $ "Timed out waiting in connecting queue after { stopwatch . ElapsedMilliseconds } ms.";
846+ return _pool . CreateTimeoutException ( stopwatch , message ) ;
847+ }
788848 }
789849 }
790850}
0 commit comments