@@ -46,9 +46,7 @@ internal abstract class Cluster : IClusterInternal
46
46
private readonly TimeSpan _minHeartbeatInterval = __minHeartbeatIntervalDefault ;
47
47
private readonly IClusterClock _clusterClock = new ClusterClock ( ) ;
48
48
private readonly ClusterId _clusterId ;
49
- private ClusterDescription _description ;
50
- private TaskCompletionSource < bool > _descriptionChangedTaskCompletionSource ;
51
- private readonly object _descriptionLock = new object ( ) ;
49
+ private ClusterDescriptionChangeSource _descriptionWithChangedTaskCompletionSource ;
52
50
private readonly LatencyLimitingServerSelector _latencyLimitingServerSelector ;
53
51
protected readonly EventLogger < LogCategories . SDAM > _clusterEventLogger ;
54
52
protected readonly EventLogger < LogCategories . ServerSelection > _serverSelectionEventLogger ;
@@ -70,10 +68,8 @@ protected Cluster(ClusterSettings settings, IClusterableServerFactory serverFact
70
68
Ensure . IsNotNull ( eventSubscriber , nameof ( eventSubscriber ) ) ;
71
69
_state = new InterlockedInt32 ( State . Initial ) ;
72
70
_rapidHeartbeatTimerCallbackState = new InterlockedInt32 ( RapidHeartbeatTimerCallbackState . NotRunning ) ;
73
-
74
71
_clusterId = new ClusterId ( ) ;
75
- _description = ClusterDescription . CreateInitial ( _clusterId , _settings . DirectConnection ) ;
76
- _descriptionChangedTaskCompletionSource = new TaskCompletionSource < bool > ( ) ;
72
+ _descriptionWithChangedTaskCompletionSource = new ( ClusterDescription . CreateInitial ( _clusterId , _settings . DirectConnection ) ) ;
77
73
_latencyLimitingServerSelector = new LatencyLimitingServerSelector ( settings . LocalThreshold ) ;
78
74
79
75
_rapidHeartbeatTimer = new Timer ( RapidHeartbeatTimerCallback , null , Timeout . InfiniteTimeSpan , Timeout . InfiniteTimeSpan ) ;
@@ -97,10 +93,7 @@ public ClusterDescription Description
97
93
{
98
94
get
99
95
{
100
- lock ( _descriptionLock )
101
- {
102
- return _description ;
103
- }
96
+ return _descriptionWithChangedTaskCompletionSource . ClusterDescription ;
104
97
}
105
98
}
106
99
@@ -134,7 +127,7 @@ protected virtual void Dispose(bool disposing)
134
127
135
128
var newClusterDescription = new ClusterDescription (
136
129
_clusterId ,
137
- _description . DirectConnection ,
130
+ _descriptionWithChangedTaskCompletionSource . ClusterDescription . DirectConnection ,
138
131
dnsMonitorException : null ,
139
132
ClusterType . Unknown ,
140
133
Enumerable . Empty < ServerDescription > ( ) ) ;
@@ -293,22 +286,11 @@ public ICoreSessionHandle StartSession(CoreSessionOptions options)
293
286
294
287
protected void UpdateClusterDescription ( ClusterDescription newClusterDescription , bool shouldClusterDescriptionChangedEventBePublished = true )
295
288
{
296
- ClusterDescription oldClusterDescription = null ;
297
- TaskCompletionSource < bool > oldDescriptionChangedTaskCompletionSource = null ;
289
+ var oldClusterDescription = Interlocked . Exchange ( ref _descriptionWithChangedTaskCompletionSource , new ( newClusterDescription ) ) ;
298
290
299
- lock ( _descriptionLock )
300
- {
301
- oldClusterDescription = _description ;
302
- _description = newClusterDescription ;
291
+ OnDescriptionChanged ( oldClusterDescription . ClusterDescription , newClusterDescription , shouldClusterDescriptionChangedEventBePublished ) ;
303
292
304
- oldDescriptionChangedTaskCompletionSource = _descriptionChangedTaskCompletionSource ;
305
- _descriptionChangedTaskCompletionSource = new TaskCompletionSource < bool > ( ) ;
306
- }
307
-
308
- OnDescriptionChanged ( oldClusterDescription , newClusterDescription , shouldClusterDescriptionChangedEventBePublished ) ;
309
-
310
- // TODO: use RunContinuationsAsynchronously instead once we require a new enough .NET Framework
311
- Task . Run ( ( ) => oldDescriptionChangedTaskCompletionSource . TrySetResult ( true ) ) ;
293
+ oldClusterDescription . TrySetChanged ( ) ;
312
294
}
313
295
314
296
private string BuildTimeoutExceptionMessage ( TimeSpan timeout , IServerSelector selector , ClusterDescription clusterDescription )
@@ -363,6 +345,25 @@ private void ThrowTimeoutException(IServerSelector selector, ClusterDescription
363
345
}
364
346
365
347
// nested classes
348
+ internal sealed class ClusterDescriptionChangeSource
349
+ {
350
+ private readonly TaskCompletionSource < bool > _changedTaskCompletionSource ;
351
+ private readonly ClusterDescription _clusterDescription ;
352
+
353
+ public ClusterDescriptionChangeSource ( ClusterDescription clusterDescription )
354
+ {
355
+ _changedTaskCompletionSource = new TaskCompletionSource < bool > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
356
+ _clusterDescription = clusterDescription ;
357
+ }
358
+
359
+ public ClusterDescription ClusterDescription => _clusterDescription ;
360
+
361
+ public Task Changed => _changedTaskCompletionSource . Task ;
362
+
363
+ public bool TrySetChanged ( )
364
+ => _changedTaskCompletionSource . TrySetResult ( true ) ;
365
+ }
366
+
366
367
private class SelectServerHelper : IDisposable
367
368
{
368
369
private readonly Cluster _cluster ;
@@ -380,7 +381,7 @@ public SelectServerHelper(Cluster cluster, IServerSelector selector)
380
381
{
381
382
_cluster = cluster ;
382
383
383
- _connectedServers = new List < IClusterableServer > ( _cluster . _description ? . Servers ? . Count ?? 1 ) ;
384
+ _connectedServers = new List < IClusterableServer > ( _cluster . _descriptionWithChangedTaskCompletionSource . ClusterDescription ? . Servers ? . Count ?? 1 ) ;
384
385
_connectedServerDescriptions = new List < ServerDescription > ( _connectedServers . Count ) ;
385
386
_operationCountServerSelector = new OperationsCountServerSelector ( _connectedServers ) ;
386
387
@@ -429,11 +430,9 @@ public void HandleException(Exception exception)
429
430
430
431
public IServer SelectServer ( )
431
432
{
432
- lock ( _cluster . _descriptionLock )
433
- {
434
- _descriptionChangedTask = _cluster . _descriptionChangedTaskCompletionSource . Task ;
435
- _description = _cluster . _description ;
436
- }
433
+ var clusterDescription = _cluster . _descriptionWithChangedTaskCompletionSource ;
434
+ _descriptionChangedTask = clusterDescription . Changed ;
435
+ _description = clusterDescription . ClusterDescription ;
437
436
438
437
if ( ! _serverSelectionWaitQueueEntered )
439
438
{
0 commit comments