@@ -46,9 +46,7 @@ internal abstract class Cluster : IClusterInternal
4646 private readonly TimeSpan _minHeartbeatInterval = __minHeartbeatIntervalDefault ;
4747 private readonly IClusterClock _clusterClock = new ClusterClock ( ) ;
4848 private readonly ClusterId _clusterId ;
49- private ClusterDescription _description ;
50- private TaskCompletionSource < bool > _descriptionChangedTaskCompletionSource ;
51- private readonly object _descriptionLock = new object ( ) ;
49+ private ClusterDescriptionChangeSource _descriptionWithChangedTaskCompletionSource ;
5250 private readonly LatencyLimitingServerSelector _latencyLimitingServerSelector ;
5351 protected readonly EventLogger < LogCategories . SDAM > _clusterEventLogger ;
5452 protected readonly EventLogger < LogCategories . ServerSelection > _serverSelectionEventLogger ;
@@ -70,10 +68,8 @@ protected Cluster(ClusterSettings settings, IClusterableServerFactory serverFact
7068 Ensure . IsNotNull ( eventSubscriber , nameof ( eventSubscriber ) ) ;
7169 _state = new InterlockedInt32 ( State . Initial ) ;
7270 _rapidHeartbeatTimerCallbackState = new InterlockedInt32 ( RapidHeartbeatTimerCallbackState . NotRunning ) ;
73-
7471 _clusterId = new ClusterId ( ) ;
75- _description = ClusterDescription . CreateInitial ( _clusterId , _settings . DirectConnection ) ;
76- _descriptionChangedTaskCompletionSource = new TaskCompletionSource < bool > ( ) ;
72+ _descriptionWithChangedTaskCompletionSource = new ( ClusterDescription . CreateInitial ( _clusterId , _settings . DirectConnection ) ) ;
7773 _latencyLimitingServerSelector = new LatencyLimitingServerSelector ( settings . LocalThreshold ) ;
7874
7975 _rapidHeartbeatTimer = new Timer ( RapidHeartbeatTimerCallback , null , Timeout . InfiniteTimeSpan , Timeout . InfiniteTimeSpan ) ;
@@ -97,10 +93,7 @@ public ClusterDescription Description
9793 {
9894 get
9995 {
100- lock ( _descriptionLock )
101- {
102- return _description ;
103- }
96+ return _descriptionWithChangedTaskCompletionSource . ClusterDescription ;
10497 }
10598 }
10699
@@ -134,7 +127,7 @@ protected virtual void Dispose(bool disposing)
134127
135128 var newClusterDescription = new ClusterDescription (
136129 _clusterId ,
137- _description . DirectConnection ,
130+ _descriptionWithChangedTaskCompletionSource . ClusterDescription . DirectConnection ,
138131 dnsMonitorException : null ,
139132 ClusterType . Unknown ,
140133 Enumerable . Empty < ServerDescription > ( ) ) ;
@@ -293,22 +286,11 @@ public ICoreSessionHandle StartSession(CoreSessionOptions options)
293286
294287 protected void UpdateClusterDescription ( ClusterDescription newClusterDescription , bool shouldClusterDescriptionChangedEventBePublished = true )
295288 {
296- ClusterDescription oldClusterDescription = null ;
297- TaskCompletionSource < bool > oldDescriptionChangedTaskCompletionSource = null ;
289+ var oldClusterDescription = Interlocked . Exchange ( ref _descriptionWithChangedTaskCompletionSource , new ( newClusterDescription ) ) ;
298290
299- lock ( _descriptionLock )
300- {
301- oldClusterDescription = _description ;
302- _description = newClusterDescription ;
291+ OnDescriptionChanged ( oldClusterDescription . ClusterDescription , newClusterDescription , shouldClusterDescriptionChangedEventBePublished ) ;
303292
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 ( ) ;
312294 }
313295
314296 private string BuildTimeoutExceptionMessage ( TimeSpan timeout , IServerSelector selector , ClusterDescription clusterDescription )
@@ -363,6 +345,25 @@ private void ThrowTimeoutException(IServerSelector selector, ClusterDescription
363345 }
364346
365347 // 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+
366367 private class SelectServerHelper : IDisposable
367368 {
368369 private readonly Cluster _cluster ;
@@ -380,7 +381,7 @@ public SelectServerHelper(Cluster cluster, IServerSelector selector)
380381 {
381382 _cluster = cluster ;
382383
383- _connectedServers = new List < IClusterableServer > ( _cluster . _description ? . Servers ? . Count ?? 1 ) ;
384+ _connectedServers = new List < IClusterableServer > ( _cluster . _descriptionWithChangedTaskCompletionSource . ClusterDescription ? . Servers ? . Count ?? 1 ) ;
384385 _connectedServerDescriptions = new List < ServerDescription > ( _connectedServers . Count ) ;
385386 _operationCountServerSelector = new OperationsCountServerSelector ( _connectedServers ) ;
386387
@@ -429,11 +430,9 @@ public void HandleException(Exception exception)
429430
430431 public IServer SelectServer ( )
431432 {
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 ;
437436
438437 if ( ! _serverSelectionWaitQueueEntered )
439438 {
0 commit comments