diff --git a/src/MongoDB.Driver/Core/Clusters/Cluster.cs b/src/MongoDB.Driver/Core/Clusters/Cluster.cs index fbf9cfe7ac5..287a40657aa 100644 --- a/src/MongoDB.Driver/Core/Clusters/Cluster.cs +++ b/src/MongoDB.Driver/Core/Clusters/Cluster.cs @@ -36,7 +36,6 @@ internal abstract class Cluster : IClusterInternal #region static private static readonly TimeSpan __minHeartbeatIntervalDefault = TimeSpan.FromMilliseconds(500); - private static readonly IServerSelector __randomServerSelector = new RandomServerSelector(); public static SemanticVersion MinSupportedServerVersion { get; } = WireVersion.ToServerVersion(WireVersion.SupportedWireVersionRange.Min); public static Range SupportedWireVersionRange { get; } = WireVersion.SupportedWireVersionRange; @@ -46,18 +45,15 @@ internal abstract class Cluster : IClusterInternal private readonly TimeSpan _minHeartbeatInterval = __minHeartbeatIntervalDefault; private readonly IClusterClock _clusterClock = new ClusterClock(); private readonly ClusterId _clusterId; - private ClusterDescriptionChangeSource _descriptionWithChangedTaskCompletionSource; + private ExpirableClusterDescription _expirableClusterDescription; private readonly LatencyLimitingServerSelector _latencyLimitingServerSelector; protected readonly EventLogger _clusterEventLogger; protected readonly EventLogger _serverSelectionEventLogger; - private Timer _rapidHeartbeatTimer; - private readonly object _serverSelectionWaitQueueLock = new object(); - private int _serverSelectionWaitQueueSize; private readonly IClusterableServerFactory _serverFactory; + private readonly ServerSelectionWaitQueue _serverSelectionWaitQueue; private readonly ICoreServerSessionPool _serverSessionPool; private readonly ClusterSettings _settings; private readonly InterlockedInt32 _state; - private readonly InterlockedInt32 _rapidHeartbeatTimerCallbackState; // constructors protected Cluster(ClusterSettings settings, IClusterableServerFactory serverFactory, IEventSubscriber eventSubscriber, ILoggerFactory loggerFactory) @@ -67,15 +63,11 @@ protected Cluster(ClusterSettings settings, IClusterableServerFactory serverFact _serverFactory = Ensure.IsNotNull(serverFactory, nameof(serverFactory)); Ensure.IsNotNull(eventSubscriber, nameof(eventSubscriber)); _state = new InterlockedInt32(State.Initial); - _rapidHeartbeatTimerCallbackState = new InterlockedInt32(RapidHeartbeatTimerCallbackState.NotRunning); _clusterId = new ClusterId(); - _descriptionWithChangedTaskCompletionSource = new (ClusterDescription.CreateInitial(_clusterId, _settings.DirectConnection)); + _expirableClusterDescription = new (this, ClusterDescription.CreateInitial(_clusterId, _settings.DirectConnection)); _latencyLimitingServerSelector = new LatencyLimitingServerSelector(settings.LocalThreshold); - - _rapidHeartbeatTimer = new Timer(RapidHeartbeatTimerCallback, null, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); - + _serverSelectionWaitQueue = new ServerSelectionWaitQueue(this); _serverSessionPool = new CoreServerSessionPool(this); - _clusterEventLogger = loggerFactory.CreateEventLogger(eventSubscriber); _serverSelectionEventLogger = loggerFactory.CreateEventLogger(eventSubscriber); } @@ -93,7 +85,7 @@ public ClusterDescription Description { get { - return _descriptionWithChangedTaskCompletionSource.ClusterDescription; + return _expirableClusterDescription.ClusterDescription; } } @@ -127,53 +119,19 @@ protected virtual void Dispose(bool disposing) var newClusterDescription = new ClusterDescription( _clusterId, - _descriptionWithChangedTaskCompletionSource.ClusterDescription.DirectConnection, + _expirableClusterDescription.ClusterDescription.DirectConnection, dnsMonitorException: null, ClusterType.Unknown, Enumerable.Empty()); UpdateClusterDescription(newClusterDescription); - _rapidHeartbeatTimer.Dispose(); + _serverSelectionWaitQueue.Dispose(); _clusterEventLogger.Logger?.LogTrace(_clusterId, "Cluster disposed"); } } - private void EnterServerSelectionWaitQueue(IServerSelector selector, ClusterDescription clusterDescription, long? operationId, TimeSpan remainingTime) - { - lock (_serverSelectionWaitQueueLock) - { - if (_serverSelectionWaitQueueSize >= _settings.MaxServerSelectionWaitQueueSize) - { - throw MongoWaitQueueFullException.ForServerSelection(); - } - - if (++_serverSelectionWaitQueueSize == 1) - { - _rapidHeartbeatTimer.Change(TimeSpan.Zero, _minHeartbeatInterval); - } - - _serverSelectionEventLogger.LogAndPublish(new ClusterEnteredSelectionQueueEvent( - clusterDescription, - selector, - operationId, - EventContext.OperationName, - remainingTime)); - } - } - - private void ExitServerSelectionWaitQueue() - { - lock (_serverSelectionWaitQueueLock) - { - if (--_serverSelectionWaitQueueSize == 0) - { - _rapidHeartbeatTimer.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); - } - } - } - public virtual void Initialize() { ThrowIfDisposed(); @@ -183,28 +141,6 @@ public virtual void Initialize() } } - private void RapidHeartbeatTimerCallback(object args) - { - // avoid requesting heartbeat reentrantly - if (_rapidHeartbeatTimerCallbackState.TryChange(RapidHeartbeatTimerCallbackState.NotRunning, RapidHeartbeatTimerCallbackState.Running)) - { - try - { - RequestHeartbeat(); - } - catch - { - // TODO: Trace this - // If we don't protect this call, we could - // take down the app domain. - } - finally - { - _rapidHeartbeatTimerCallbackState.TryChange(RapidHeartbeatTimerCallbackState.NotRunning); - } - } - } - protected abstract void RequestHeartbeat(); protected void OnDescriptionChanged(ClusterDescription oldDescription, ClusterDescription newDescription, bool shouldClusterDescriptionChangedEventBePublished) @@ -219,80 +155,78 @@ protected void OnDescriptionChanged(ClusterDescription oldDescription, ClusterDe public IServer SelectServer(OperationContext operationContext, IServerSelector selector) { - ThrowIfDisposedOrNotOpen(); Ensure.IsNotNull(selector, nameof(selector)); Ensure.IsNotNull(operationContext, nameof(operationContext)); + ThrowIfDisposedOrNotOpen(); - var serverSelectionOperationContext = operationContext.WithTimeout(Settings.ServerSelectionTimeout); + operationContext = operationContext.WithTimeout(Settings.ServerSelectionTimeout); + var expirableClusterDescription = _expirableClusterDescription; + IDisposable serverSelectionWaitQueueDisposer = null; + (selector, var operationCountSelector, var stopwatch) = BeginServerSelection(expirableClusterDescription.ClusterDescription, selector); - using (var helper = new SelectServerHelper(this, selector)) + try { - try + while (true) { - while (true) + var result = SelectServer(expirableClusterDescription, selector, operationCountSelector); + if (result != default) { - var server = helper.SelectServer(serverSelectionOperationContext); - if (server != null) - { - return server; - } - - helper.WaitForDescriptionChanged(serverSelectionOperationContext); + EndServerSelection(expirableClusterDescription.ClusterDescription, selector, result.ServerDescription, stopwatch); + return result.Server; } - } - catch (TimeoutException) - { - var message = BuildTimeoutExceptionMessage(_settings.ServerSelectionTimeout, selector, helper.Description); - var timeoutException = new TimeoutException(message); - helper.HandleException(timeoutException); - throw timeoutException; - } - catch (Exception ex) - { - helper.HandleException(ex); - throw; + serverSelectionWaitQueueDisposer ??= _serverSelectionWaitQueue.Enter(operationContext, selector, expirableClusterDescription.ClusterDescription, EventContext.OperationId); + + operationContext.WaitTask(expirableClusterDescription.Expired); + expirableClusterDescription = _expirableClusterDescription; } } + catch (Exception ex) + { + throw HandleServerSelectionException(expirableClusterDescription.ClusterDescription, selector, ex, stopwatch); + } + finally + { + serverSelectionWaitQueueDisposer?.Dispose(); + } } public async Task SelectServerAsync(OperationContext operationContext, IServerSelector selector) { - ThrowIfDisposedOrNotOpen(); Ensure.IsNotNull(selector, nameof(selector)); Ensure.IsNotNull(operationContext, nameof(operationContext)); + ThrowIfDisposedOrNotOpen(); - var serverSelectionOperationContext = operationContext.WithTimeout(Settings.ServerSelectionTimeout); + operationContext = operationContext.WithTimeout(Settings.ServerSelectionTimeout); + var expirableClusterDescription = _expirableClusterDescription; + IDisposable serverSelectionWaitQueueDisposer = null; + (selector, var operationCountSelector, var stopwatch) = BeginServerSelection(expirableClusterDescription.ClusterDescription, selector); - using (var helper = new SelectServerHelper(this, selector)) + try { - try + while (true) { - while (true) + var result = SelectServer(expirableClusterDescription, selector, operationCountSelector); + if (result != default) { - var server = helper.SelectServer(serverSelectionOperationContext); - if (server != null) - { - return server; - } - - await helper.WaitForDescriptionChangedAsync(serverSelectionOperationContext).ConfigureAwait(false); + EndServerSelection(expirableClusterDescription.ClusterDescription, selector, result.ServerDescription, stopwatch); + return result.Server; } - } - catch (TimeoutException) - { - var message = BuildTimeoutExceptionMessage(_settings.ServerSelectionTimeout, selector, helper.Description); - var timeoutException = new TimeoutException(message); - helper.HandleException(timeoutException); - throw timeoutException; - } - catch (Exception ex) - { - helper.HandleException(ex); - throw; + serverSelectionWaitQueueDisposer ??= _serverSelectionWaitQueue.Enter(operationContext, selector, expirableClusterDescription.ClusterDescription, EventContext.OperationId); + + await operationContext.WaitTaskAsync(expirableClusterDescription.Expired).ConfigureAwait(false); + expirableClusterDescription = _expirableClusterDescription; } } + catch (Exception ex) + { + throw HandleServerSelectionException(expirableClusterDescription.ClusterDescription, selector, ex, stopwatch); + } + finally + { + serverSelectionWaitQueueDisposer?.Dispose(); + } } public ICoreSessionHandle StartSession(CoreSessionOptions options) @@ -306,21 +240,91 @@ public ICoreSessionHandle StartSession(CoreSessionOptions options) protected void UpdateClusterDescription(ClusterDescription newClusterDescription, bool shouldClusterDescriptionChangedEventBePublished = true) { - var oldClusterDescription = Interlocked.Exchange(ref _descriptionWithChangedTaskCompletionSource, new(newClusterDescription)); + var expiredClusterDescription = Interlocked.Exchange(ref _expirableClusterDescription, new(this, newClusterDescription)); - OnDescriptionChanged(oldClusterDescription.ClusterDescription, newClusterDescription, shouldClusterDescriptionChangedEventBePublished); + OnDescriptionChanged(expiredClusterDescription.ClusterDescription, newClusterDescription, shouldClusterDescriptionChangedEventBePublished); - oldClusterDescription.TrySetChanged(); + expiredClusterDescription.TrySetExpired(); } - private string BuildTimeoutExceptionMessage(TimeSpan timeout, IServerSelector selector, ClusterDescription clusterDescription) + private (IServerSelector Selector, OperationsCountServerSelector OperationCountSelector, Stopwatch Stopwatch) BeginServerSelection(ClusterDescription clusterDescription, IServerSelector selector) { - var ms = (int)Math.Round(timeout.TotalMilliseconds); - return string.Format( - "A timeout occurred after {0}ms selecting a server using {1}. Client view of cluster state is {2}.", - ms.ToString(), - selector.ToString(), - clusterDescription.ToString()); + _serverSelectionEventLogger.LogAndPublish(new ClusterSelectingServerEvent( + clusterDescription, + selector, + EventContext.OperationId, + EventContext.OperationName)); + + var allSelectors = new List(5); + if (Settings.PreServerSelector != null) + { + allSelectors.Add(Settings.PreServerSelector); + } + + allSelectors.Add(selector); + if (Settings.PostServerSelector != null) + { + allSelectors.Add(Settings.PostServerSelector); + } + + allSelectors.Add(_latencyLimitingServerSelector); + var operationCountSelector = new OperationsCountServerSelector(Array.Empty()); + allSelectors.Add(operationCountSelector); + + return (new CompositeServerSelector(allSelectors), operationCountSelector, Stopwatch.StartNew()); + } + + private void EndServerSelection(ClusterDescription clusterDescription, IServerSelector selector, ServerDescription selectedServerDescription, Stopwatch stopwatch) + { + stopwatch.Stop(); + _serverSelectionEventLogger.LogAndPublish(new ClusterSelectedServerEvent( + clusterDescription, + selector, + selectedServerDescription, + stopwatch.Elapsed, + EventContext.OperationId, + EventContext.OperationName)); + } + + private Exception HandleServerSelectionException(ClusterDescription clusterDescription, IServerSelector selector, Exception exception, Stopwatch stopwatch) + { + stopwatch.Stop(); + + if (exception is TimeoutException) + { + var message = $"A timeout occurred after {stopwatch.ElapsedMilliseconds}ms selecting a server using {selector}. Client view of cluster state is {clusterDescription}."; + exception = new TimeoutException(message); + } + + _serverSelectionEventLogger.LogAndPublish(new ClusterSelectingServerFailedEvent( + clusterDescription, + selector, + exception, + EventContext.OperationId, + EventContext.OperationName)); + + return exception; + } + + private (IClusterableServer Server, ServerDescription ServerDescription) SelectServer(ExpirableClusterDescription clusterDescriptionChangeSource, IServerSelector selector, OperationsCountServerSelector operationCountSelector) + { + MongoIncompatibleDriverException.ThrowIfNotSupported(clusterDescriptionChangeSource.ClusterDescription); + + operationCountSelector.PopulateServers(clusterDescriptionChangeSource.ConnectedServers); + var selectedServerDescription = selector + .SelectServers(clusterDescriptionChangeSource.ClusterDescription, clusterDescriptionChangeSource.ConnectedServerDescriptions) + .SingleOrDefault(); + + if (selectedServerDescription != null) + { + var selectedServer = clusterDescriptionChangeSource.ConnectedServers.FirstOrDefault(s => EndPointHelper.Equals(s.EndPoint, selectedServerDescription.EndPoint)); + if (selectedServer != null) + { + return (selectedServer, selectedServerDescription); + } + } + + return default; } private void ThrowIfDisposed() @@ -341,201 +345,187 @@ private void ThrowIfDisposedOrNotOpen() } // nested classes - internal sealed class ClusterDescriptionChangeSource + internal sealed class ExpirableClusterDescription { - private readonly TaskCompletionSource _changedTaskCompletionSource; + private readonly Cluster _cluster; + private readonly TaskCompletionSource _expireCompletionSource; private readonly ClusterDescription _clusterDescription; + private readonly object _connectedServersLock = new(); + private IReadOnlyList _connectedServers; + private IReadOnlyList _connectedServerDescriptions; - public ClusterDescriptionChangeSource(ClusterDescription clusterDescription) + public ExpirableClusterDescription(Cluster cluster, ClusterDescription clusterDescription) { - _changedTaskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + _cluster = cluster; _clusterDescription = clusterDescription; + _expireCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); } public ClusterDescription ClusterDescription => _clusterDescription; - public Task Changed => _changedTaskCompletionSource.Task; - - public bool TrySetChanged() - => _changedTaskCompletionSource.TrySetResult(true); - } - - private class SelectServerHelper : IDisposable - { - private readonly Cluster _cluster; - private readonly List _connectedServers; - private readonly List _connectedServerDescriptions; - private ClusterDescription _description; - private Task _descriptionChangedTask; - private bool _serverSelectionWaitQueueEntered; - private readonly IServerSelector _selector; - private readonly OperationsCountServerSelector _operationCountServerSelector; - private readonly Stopwatch _stopwatch; - - public SelectServerHelper(Cluster cluster, IServerSelector selector) - { - _cluster = cluster; - _connectedServers = new List(_cluster._descriptionWithChangedTaskCompletionSource.ClusterDescription?.Servers?.Count ?? 1); - _connectedServerDescriptions = new List(_connectedServers.Count); - _operationCountServerSelector = new OperationsCountServerSelector(_connectedServers); - - _stopwatch = Stopwatch.StartNew(); - _selector = DecorateSelector(selector); - } + public Task Expired => _expireCompletionSource.Task; - public ClusterDescription Description + public IReadOnlyList ConnectedServers { - get { return _description; } - } - - public Task DescriptionChangedTask - { - get { return _descriptionChangedTask; } + get + { + EnsureConnectedServersInitialized(); + return _connectedServers; + } } - public IServerSelector Selector + public IReadOnlyList ConnectedServerDescriptions { - get { return _selector; } - } - - public void Dispose() - { - if (_serverSelectionWaitQueueEntered) + get { - _cluster.ExitServerSelectionWaitQueue(); + EnsureConnectedServersInitialized(); + return _connectedServerDescriptions; } } - public void HandleException(Exception exception) - { - _cluster._serverSelectionEventLogger.LogAndPublish(new ClusterSelectingServerFailedEvent( - _description, - _selector, - exception, - EventContext.OperationId, - EventContext.OperationName)); - } + public bool TrySetExpired() + => _expireCompletionSource.TrySetResult(true); - public IServer SelectServer(OperationContext operationContext) + private void EnsureConnectedServersInitialized() { - var clusterDescription = _cluster._descriptionWithChangedTaskCompletionSource; - _descriptionChangedTask = clusterDescription.Changed; - _description = clusterDescription.ClusterDescription; - - if (!_serverSelectionWaitQueueEntered) + if (_connectedServers != null) { - // this is our first time through... - _cluster._serverSelectionEventLogger.LogAndPublish(new ClusterSelectingServerEvent( - _description, - _selector, - EventContext.OperationId, - EventContext.OperationName)); + return; } - MongoIncompatibleDriverException.ThrowIfNotSupported(_description); - - _connectedServers.Clear(); - _connectedServerDescriptions.Clear(); - - foreach (var description in _description.Servers) + lock (_connectedServersLock) { - if (description.State == ServerState.Connected && - _cluster.TryGetServer(description.EndPoint, out var server)) + if (_connectedServers != null) { - _connectedServers.Add(server); - _connectedServerDescriptions.Add(description); + return; } - } - var selectedServersDescriptions = _selector - .SelectServers(_description, _connectedServerDescriptions) - .ToList(); + var connectedServerDescriptions = new List(ClusterDescription.Servers?.Count ?? 1); + var connectedServers = new List(connectedServerDescriptions.Capacity); - IServer selectedServer = null; - - if (selectedServersDescriptions.Count > 0) - { - var selectedServerDescription = selectedServersDescriptions.Count == 1 - ? selectedServersDescriptions[0] - : __randomServerSelector.SelectServers(_description, selectedServersDescriptions).Single(); + if (ClusterDescription.Servers != null) + { + foreach (var description in ClusterDescription.Servers) + { + if (description.State == ServerState.Connected && + _cluster.TryGetServer(description.EndPoint, out var server)) + { + connectedServers.Add(server); + connectedServerDescriptions.Add(description); + } + } + } - selectedServer = _connectedServers.FirstOrDefault(s => EndPointHelper.Equals(s.EndPoint, selectedServerDescription.EndPoint)); + _connectedServerDescriptions = connectedServerDescriptions; + _connectedServers = connectedServers; } + } + } - if (selectedServer != null) - { - _stopwatch.Stop(); - - _cluster._serverSelectionEventLogger.LogAndPublish(new ClusterSelectedServerEvent( - _description, - _selector, - selectedServer.Description, - _stopwatch.Elapsed, - EventContext.OperationId, - EventContext.OperationName)); - } + private static class State + { + public const int Initial = 0; + public const int Open = 1; + public const int Disposed = 2; + } - return selectedServer; - } + private static class RapidHeartbeatTimerCallbackState + { + public const int NotRunning = 0; + public const int Running = 1; + } + + private sealed class ServerSelectionWaitQueue : IDisposable + { + private readonly Cluster _cluster; + private readonly object _serverSelectionWaitQueueLock = new(); + private readonly Timer _rapidHeartbeatTimer; + private readonly InterlockedInt32 _rapidHeartbeatTimerCallbackState; - public void WaitForDescriptionChanged(OperationContext operationContext) + private int _serverSelectionWaitQueueSize; + + public ServerSelectionWaitQueue(Cluster cluster) { - EnsureEnteredServerSelectionQueue(operationContext); - operationContext.WaitTask(DescriptionChangedTask); + _cluster = cluster; + _rapidHeartbeatTimerCallbackState = new InterlockedInt32(RapidHeartbeatTimerCallbackState.NotRunning); + _rapidHeartbeatTimer = new Timer(RapidHeartbeatTimerCallback, null, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); } - public Task WaitForDescriptionChangedAsync(OperationContext operationContext) + public void Dispose() { - EnsureEnteredServerSelectionQueue(operationContext); - return operationContext.WaitTaskAsync(DescriptionChangedTask); + _rapidHeartbeatTimer.Dispose(); } - private void EnsureEnteredServerSelectionQueue(OperationContext operationContext) + public IDisposable Enter(OperationContext operationContext, IServerSelector selector, ClusterDescription clusterDescription, long? operationId) { - if (_serverSelectionWaitQueueEntered) + lock (_serverSelectionWaitQueueLock) { - return; + if (_serverSelectionWaitQueueSize >= _cluster._settings.MaxServerSelectionWaitQueueSize) + { + throw MongoWaitQueueFullException.ForServerSelection(); + } + + if (++_serverSelectionWaitQueueSize == 1) + { + _rapidHeartbeatTimer.Change(TimeSpan.Zero, _cluster._minHeartbeatInterval); + } + + _cluster._serverSelectionEventLogger.LogAndPublish(new ClusterEnteredSelectionQueueEvent( + clusterDescription, + selector, + operationId, + EventContext.OperationName, + operationContext.RemainingTimeout)); } - _cluster.EnterServerSelectionWaitQueue(_selector, _description, EventContext.OperationId, operationContext.RemainingTimeout); - _serverSelectionWaitQueueEntered = true; + return new ServerSelectionQueueDisposer(this); } - private IServerSelector DecorateSelector(IServerSelector selector) + private void ExitServerSelectionWaitQueue() { - var settings = _cluster.Settings; - var allSelectors = new List(); + lock (_serverSelectionWaitQueueLock) + { + if (--_serverSelectionWaitQueueSize == 0) + { + _rapidHeartbeatTimer.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); + } + } + } - if (settings.PreServerSelector != null) + private void RapidHeartbeatTimerCallback(object args) + { + // avoid requesting heartbeat reentrantly + if (_rapidHeartbeatTimerCallbackState.TryChange(RapidHeartbeatTimerCallbackState.NotRunning, RapidHeartbeatTimerCallbackState.Running)) { - allSelectors.Add(settings.PreServerSelector); + try + { + _cluster.RequestHeartbeat(); + } + catch + { + // TODO: Trace this + // If we don't protect this call, we could + // take down the app domain. + } + finally + { + _rapidHeartbeatTimerCallbackState.TryChange(RapidHeartbeatTimerCallbackState.NotRunning); + } } + } - allSelectors.Add(selector); + private sealed class ServerSelectionQueueDisposer : IDisposable + { + private readonly ServerSelectionWaitQueue _waitQueue; - if (settings.PostServerSelector != null) + public ServerSelectionQueueDisposer(ServerSelectionWaitQueue waitQueue) { - allSelectors.Add(settings.PostServerSelector); + _waitQueue = waitQueue; } - allSelectors.Add(_cluster._latencyLimitingServerSelector); - allSelectors.Add(_operationCountServerSelector); - - return new CompositeServerSelector(allSelectors); + public void Dispose() + => _waitQueue.ExitServerSelectionWaitQueue(); } } - - private static class State - { - public const int Initial = 0; - public const int Open = 1; - public const int Disposed = 2; - } - - private static class RapidHeartbeatTimerCallbackState - { - public const int NotRunning = 0; - public const int Running = 1; - } } } diff --git a/src/MongoDB.Driver/Core/Clusters/ServerSelectors/OperationsCountServerSelector.cs b/src/MongoDB.Driver/Core/Clusters/ServerSelectors/OperationsCountServerSelector.cs index 3442d6bd436..c6cf48bffcb 100644 --- a/src/MongoDB.Driver/Core/Clusters/ServerSelectors/OperationsCountServerSelector.cs +++ b/src/MongoDB.Driver/Core/Clusters/ServerSelectors/OperationsCountServerSelector.cs @@ -22,9 +22,9 @@ namespace MongoDB.Driver.Core.Clusters.ServerSelectors { internal sealed class OperationsCountServerSelector : IServerSelector { - private readonly IEnumerable _clusterableServers; + private IReadOnlyList _clusterableServers; - public OperationsCountServerSelector(IEnumerable clusterableServers) + public OperationsCountServerSelector(IReadOnlyList clusterableServers) { _clusterableServers = clusterableServers; } @@ -58,6 +58,11 @@ public IEnumerable SelectServers(ClusterDescription cluster, } } + public void PopulateServers(IReadOnlyList clusterableServers) + { + _clusterableServers = clusterableServers; + } + /// public override string ToString() => nameof(OperationsCountServerSelector); diff --git a/tests/MongoDB.Driver.Tests/Core/Jira/CSharp3173Tests.cs b/tests/MongoDB.Driver.Tests/Core/Jira/CSharp3173Tests.cs index 70ff0840d24..8be118b9db5 100644 --- a/tests/MongoDB.Driver.Tests/Core/Jira/CSharp3173Tests.cs +++ b/tests/MongoDB.Driver.Tests/Core/Jira/CSharp3173Tests.cs @@ -289,7 +289,7 @@ private IServerSelector CreateWritableServerAndEndPointSelector(EndPoint endPoin private void ForceClusterId(MultiServerCluster cluster, ClusterId clusterId) { Reflector.SetFieldValue(cluster, "_clusterId", clusterId); - Reflector.SetFieldValue(cluster, "_descriptionWithChangedTaskCompletionSource", new Cluster.ClusterDescriptionChangeSource(ClusterDescription.CreateInitial(clusterId, __directConnection))); + Reflector.SetFieldValue(cluster, "_expirableClusterDescription", new Cluster.ExpirableClusterDescription(cluster, ClusterDescription.CreateInitial(clusterId, __directConnection))); } private void SetupServerMonitorConnection( diff --git a/tests/MongoDB.Driver.Tests/Core/Jira/CSharp3302Tests.cs b/tests/MongoDB.Driver.Tests/Core/Jira/CSharp3302Tests.cs index a3c5488e56f..aa944ed0ca6 100644 --- a/tests/MongoDB.Driver.Tests/Core/Jira/CSharp3302Tests.cs +++ b/tests/MongoDB.Driver.Tests/Core/Jira/CSharp3302Tests.cs @@ -270,7 +270,7 @@ private IServerSelector CreateWritableServerAndEndPointSelector(EndPoint endPoin private void ForceClusterId(MultiServerCluster cluster, ClusterId clusterId) { Reflector.SetFieldValue(cluster, "_clusterId", clusterId); - Reflector.SetFieldValue(cluster, "_descriptionWithChangedTaskCompletionSource", new Cluster.ClusterDescriptionChangeSource(ClusterDescription.CreateInitial(clusterId, __directConnection))); + Reflector.SetFieldValue(cluster, "_expirableClusterDescription", new Cluster.ExpirableClusterDescription(cluster, ClusterDescription.CreateInitial(clusterId, __directConnection))); } private void SetupServerMonitorConnection( diff --git a/tests/MongoDB.Driver.Tests/Core/Logging/EventLoggerTests.cs b/tests/MongoDB.Driver.Tests/Core/Logging/EventLoggerTests.cs index 2d8e97168dd..8d07de219b4 100644 --- a/tests/MongoDB.Driver.Tests/Core/Logging/EventLoggerTests.cs +++ b/tests/MongoDB.Driver.Tests/Core/Logging/EventLoggerTests.cs @@ -94,7 +94,7 @@ private static IEnumerable EventsData() (new LogCategories.Command(), new CommandStartedEvent("test", new Bson.BsonDocument(), new DatabaseNamespace("test"), 1, 1, connectionId)), (new LogCategories.Connection(), new ConnectionCreatedEvent(connectionId, null, 1)), (new LogCategories.SDAM(), new ServerHeartbeatStartedEvent(connectionId, true)), - (new LogCategories.ServerSelection(), new ClusterSelectingServerEvent(clusterDescription, new RandomServerSelector(), default, default)) + (new LogCategories.ServerSelection(), new ClusterSelectingServerEvent(clusterDescription, Mock.Of(), default, default)) }; var booleanValues = new[] { true, false }; diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs index 73c1076d90d..bfb4da43d5f 100644 --- a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs @@ -447,7 +447,7 @@ public void BypassSpawningMongocryptdTest( var exception = Record.Exception(() => adminDatabase.RunCommand(legacyHelloCommand)); exception.Should().BeOfType(); - exception.Message.Should().Contain("A timeout occurred after 1000ms selecting a server").And.Contain("localhost:27021"); + exception.Message.Should().MatchRegex(@".*A timeout occurred after \d+ms selecting a server.*").And.Contain("localhost:27021"); } IMongoClient EnsureEnvironmentAndConfigureTestClientEncrypted()