29
29
30
30
namespace MongoDB . Driver . Core . ConnectionPools
31
31
{
32
- internal sealed partial class ExclusiveConnectionPool : IConnectionPool
32
+ internal sealed partial class ExclusiveConnectionPool
33
33
{
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
+
34
59
// nested classes
35
60
private static class State
36
61
{
@@ -125,7 +150,7 @@ private AcquiredConnection FinalizePoolEnterance(PooledConnection pooledConnecti
125
150
_stopwatch . Stop ( ) ;
126
151
127
152
var message = $ "Timed out waiting for a connection after { _stopwatch . ElapsedMilliseconds } ms.";
128
- throw new TimeoutException ( message ) ;
153
+ throw _pool . CreateTimeoutException ( _stopwatch , message ) ;
129
154
}
130
155
}
131
156
@@ -173,8 +198,9 @@ public void HandleException(Exception ex)
173
198
}
174
199
}
175
200
176
- private sealed class PooledConnection : IConnection
201
+ private sealed class PooledConnection : IConnection , ICheckOutReasonTracker
177
202
{
203
+ private CheckOutReason ? _checkOutReason ;
178
204
private readonly IConnection _connection ;
179
205
private readonly ExclusiveConnectionPool _connectionPool ;
180
206
private int _generation ;
@@ -187,6 +213,14 @@ public PooledConnection(ExclusiveConnectionPool connectionPool, IConnection conn
187
213
_generation = connectionPool . _generation ;
188
214
}
189
215
216
+ public CheckOutReason ? CheckOutReason
217
+ {
218
+ get
219
+ {
220
+ return _checkOutReason ;
221
+ }
222
+ }
223
+
190
224
public ConnectionId ConnectionId
191
225
{
192
226
get { return _connection . ConnectionId ; }
@@ -313,6 +347,15 @@ public async Task SendMessagesAsync(IEnumerable<RequestMessage> messages, Messag
313
347
}
314
348
}
315
349
350
+ public void SetCheckOutReasonIfNotAlreadySet ( CheckOutReason reason )
351
+ {
352
+ if ( _checkOutReason == null )
353
+ {
354
+ _checkOutReason = reason ;
355
+ _connectionPool . _checkOutReasonCounter . Increment ( reason ) ;
356
+ }
357
+ }
358
+
316
359
public void SetReadTimeout ( TimeSpan timeout )
317
360
{
318
361
_connection . SetReadTimeout ( timeout ) ;
@@ -335,7 +378,7 @@ private void SetEffectiveGenerationIfRequired(ConnectionDescription description)
335
378
}
336
379
}
337
380
338
- private sealed class AcquiredConnection : IConnectionHandle
381
+ private sealed class AcquiredConnection : IConnectionHandle , ICheckOutReasonTracker
339
382
{
340
383
private ExclusiveConnectionPool _connectionPool ;
341
384
private bool _disposed ;
@@ -347,6 +390,14 @@ public AcquiredConnection(ExclusiveConnectionPool connectionPool, ReferenceCount
347
390
_reference = reference ;
348
391
}
349
392
393
+ public CheckOutReason ? CheckOutReason
394
+ {
395
+ get
396
+ {
397
+ return _reference . Instance . CheckOutReason ;
398
+ }
399
+ }
400
+
350
401
public ConnectionId ConnectionId
351
402
{
352
403
get { return _reference . Instance . ConnectionId ; }
@@ -432,6 +483,12 @@ public Task SendMessagesAsync(IEnumerable<RequestMessage> messages, MessageEncod
432
483
return _reference . Instance . SendMessagesAsync ( messages , messageEncoderSettings , cancellationToken ) ;
433
484
}
434
485
486
+ public void SetCheckOutReasonIfNotAlreadySet ( CheckOutReason reason )
487
+ {
488
+ ThrowIfDisposed ( ) ;
489
+ _reference . Instance . SetCheckOutReasonIfNotAlreadySet ( reason ) ;
490
+ }
491
+
435
492
public void SetReadTimeout ( TimeSpan timeout )
436
493
{
437
494
ThrowIfDisposed ( ) ;
@@ -674,15 +731,15 @@ public PooledConnection CreateOpenedOrReuse(CancellationToken cancellationToken)
674
731
{
675
732
SemaphoreSlimSignalable . SemaphoreWaitResult . Signaled => _pool . _connectionHolder . Acquire ( ) ,
676
733
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 ) ,
678
735
_ => throw new InvalidOperationException ( $ "Invalid wait result { _connectingWaitStatus } ")
679
736
} ;
680
737
681
738
waitTimeout = _connectingTimeout - stopwatch . Elapsed ;
682
739
683
740
if ( connection == null && waitTimeout <= TimeSpan . Zero )
684
741
{
685
- throw TimoutException ( stopwatch ) ;
742
+ throw CreateTimeoutException ( stopwatch ) ;
686
743
}
687
744
}
688
745
@@ -708,15 +765,15 @@ public async Task<PooledConnection> CreateOpenedOrReuseAsync(CancellationToken c
708
765
{
709
766
SemaphoreSlimSignalable . SemaphoreWaitResult . Signaled => _pool . _connectionHolder . Acquire ( ) ,
710
767
SemaphoreSlimSignalable . SemaphoreWaitResult . Entered => await CreateOpenedInternalAsync ( cancellationToken ) . ConfigureAwait ( false ) ,
711
- SemaphoreSlimSignalable . SemaphoreWaitResult . TimedOut => throw TimoutException ( stopwatch ) ,
768
+ SemaphoreSlimSignalable . SemaphoreWaitResult . TimedOut => throw CreateTimeoutException ( stopwatch ) ,
712
769
_ => throw new InvalidOperationException ( $ "Invalid wait result { _connectingWaitStatus } ")
713
770
} ;
714
771
715
772
waitTimeout = _connectingTimeout - stopwatch . Elapsed ;
716
773
717
774
if ( connection == null && waitTimeout <= TimeSpan . Zero )
718
775
{
719
- throw TimoutException ( stopwatch ) ;
776
+ throw CreateTimeoutException ( stopwatch ) ;
720
777
}
721
778
}
722
779
@@ -783,8 +840,11 @@ private void FinishCreating(ConnectionDescription description)
783
840
_pool . _serviceStates . IncrementConnectionCount ( description ? . ServiceId ) ;
784
841
}
785
842
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
+ }
788
848
}
789
849
}
790
850
}
0 commit comments