protected virtual void Dispose(bool disposing) { if (_state.TryChange(State.Disposed)) { #pragma warning disable CS0618 // Type or member is obsolete var connectionModeSwitch = _description.ConnectionModeSwitch; var connectionMode = connectionModeSwitch == ConnectionModeSwitch.UseConnectionMode ? _description.ConnectionMode : default; var directConnection = connectionModeSwitch == ConnectionModeSwitch.UseDirectConnection ? _description.DirectConnection : default; var newClusterDescription = new ClusterDescription( _clusterId, connectionMode, connectionModeSwitch, directConnection, dnsMonitorException: null, ClusterType.Unknown, Enumerable.Empty <ServerDescription>()); #pragma warning restore CS0618 // Type or member is obsolete UpdateClusterDescription(newClusterDescription); _rapidHeartbeatTimer.Dispose(); } }
private async Task WaitForDescriptionChangedAsync(IServerSelector selector, ClusterDescription description, Task descriptionChangedTask, TimeSpan timeout, CancellationToken cancellationToken) { var cancellationTaskCompletionSource = new TaskCompletionSource <bool>(); using (cancellationToken.Register(() => cancellationTaskCompletionSource.TrySetCanceled())) using (var timeoutCancellationTokenSource = new CancellationTokenSource()) { var timeoutTask = Task.Delay(timeout, timeoutCancellationTokenSource.Token); var completedTask = await Task.WhenAny(descriptionChangedTask, timeoutTask, cancellationTaskCompletionSource.Task).ConfigureAwait(false); if (completedTask == timeoutTask) { ThrowTimeoutException(selector, description); } timeoutCancellationTokenSource.Cancel(); if (completedTask == cancellationTaskCompletionSource.Task) { cancellationToken.ThrowIfCancellationRequested(); } await descriptionChangedTask.ConfigureAwait(false); // propagate exceptions } }
public WaitForDescriptionChangedHelper(Cluster cluster, IServerSelector selector, ClusterDescription description, Task descriptionChangedTask, TimeSpan timeout, CancellationToken cancellationToken) { _cluster = cluster; _description = description; _selector = selector; _descriptionChangedTask = descriptionChangedTask; _cancellationToken = cancellationToken; _cancellationTaskCompletionSource = new TaskCompletionSource <bool>(); _cancellationTokenRegistration = cancellationToken.Register(() => _cancellationTaskCompletionSource.TrySetCanceled()); _timeoutCancellationTokenSource = new CancellationTokenSource(); _timeoutTask = Task.Delay(timeout, _timeoutCancellationTokenSource.Token); }
private void ThrowTimeoutException(IServerSelector selector, ClusterDescription description) { var message = BuildTimeoutExceptionMessage(_settings.ServerSelectionTimeout, selector, description); throw new TimeoutException(message); }
private string BuildTimeoutExceptionMessage(TimeSpan timeout, IServerSelector selector, ClusterDescription clusterDescription) { var ms = (int)Math.Round(timeout.TotalMilliseconds); return(string.Format( "A timeout occured after {0}ms selecting a server using {1}. Client view of cluster state is {2}.", ms.ToString(), selector.ToString(), clusterDescription.ToString())); }
// constructors /// <summary> /// Initializes a new instance of the <see cref="ClusterDescriptionChangedEventArgs"/> class. /// </summary> /// <param name="oldClusterDescription">The old cluster description.</param> /// <param name="newClusterDescription">The new cluster description.</param> public ClusterDescriptionChangedEventArgs(ClusterDescription oldClusterDescription, ClusterDescription newClusterDescription) { _oldClusterDescription = Ensure.IsNotNull(oldClusterDescription, "oldClusterDescription"); _newClusterDescription = Ensure.IsNotNull(newClusterDescription, "newClusterDescription"); }
public async Task <IServer> SelectServerAsync(IServerSelector selector, CancellationToken cancellationToken) { ThrowIfDisposedOrNotOpen(); Ensure.IsNotNull(selector, "selector"); var timeoutAt = DateTime.UtcNow + _settings.ServerSelectionTimeout; var serverSelectionWaitQueueEntered = false; if (_settings.PreServerSelector != null || _settings.PostServerSelector != null) { var allSelectors = new List <IServerSelector>(); if (_settings.PreServerSelector != null) { allSelectors.Add(_settings.PreServerSelector); } allSelectors.Add(selector); if (_settings.PostServerSelector != null) { allSelectors.Add(_settings.PostServerSelector); } selector = new CompositeServerSelector(allSelectors); } ClusterDescription description = null; try { var stopwatch = Stopwatch.StartNew(); while (true) { cancellationToken.ThrowIfCancellationRequested(); Task descriptionChangedTask; lock (_descriptionLock) { descriptionChangedTask = _descriptionChangedTaskCompletionSource.Task; description = _description; } if (!serverSelectionWaitQueueEntered && _selectingServerEventHandler != null) { // this is our first time through... _selectingServerEventHandler(new ClusterSelectingServerEvent( description, selector)); } ThrowIfIncompatible(description); var connectedServers = description.Servers.Where(s => s.State == ServerState.Connected); var selectedServers = selector.SelectServers(description, connectedServers).ToList(); while (selectedServers.Count > 0) { var server = selectedServers.Count == 1 ? selectedServers[0] : __randomServerSelector.SelectServers(description, selectedServers).Single(); IClusterableServer selectedServer; if (TryGetServer(server.EndPoint, out selectedServer)) { stopwatch.Stop(); if (_selectedServerEventHandler != null) { _selectedServerEventHandler(new ClusterSelectedServerEvent( description, selector, server, stopwatch.Elapsed)); } return(selectedServer); } selectedServers.Remove(server); } if (!serverSelectionWaitQueueEntered) { EnterServerSelectionWaitQueue(); serverSelectionWaitQueueEntered = true; } var timeoutRemaining = timeoutAt - DateTime.UtcNow; if (timeoutRemaining <= TimeSpan.Zero) { ThrowTimeoutException(selector, description); } await WaitForDescriptionChangedAsync(selector, description, descriptionChangedTask, timeoutRemaining, cancellationToken).ConfigureAwait(false); } } catch (Exception ex) { if (_selectingServerFailedEventHandler != null) { _selectingServerFailedEventHandler(new ClusterSelectingServerFailedEvent( description, selector, ex)); } throw; } finally { if (serverSelectionWaitQueueEntered) { ExitServerSelectionWaitQueue(); } } }
private ClusterDescription ProcessReplicaSetChange(ClusterDescription clusterDescription, ServerDescriptionChangedEventArgs args, List <IClusterableServer> newServers) { if (!args.NewServerDescription.Type.IsReplicaSetMember()) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server is a {0}, not a replica set member.", args.NewServerDescription.Type))); } if (args.NewServerDescription.Type == ServerType.ReplicaSetGhost) { return(clusterDescription.WithServerDescription(args.NewServerDescription)); } if (_replicaSetName == null) { _replicaSetName = args.NewServerDescription.ReplicaSetConfig.Name; } if (_replicaSetName != args.NewServerDescription.ReplicaSetConfig.Name) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server was a member of the '{0}' replica set, but should be '{1}'.", args.NewServerDescription.ReplicaSetConfig.Name, _replicaSetName))); } clusterDescription = clusterDescription.WithServerDescription(args.NewServerDescription); clusterDescription = EnsureServers(clusterDescription, args.NewServerDescription, newServers); if (args.NewServerDescription.CanonicalEndPoint != null && !EndPointHelper.Equals(args.NewServerDescription.CanonicalEndPoint, args.NewServerDescription.EndPoint)) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, "CanonicalEndPoint is different than seed list EndPoint.")); } if (args.NewServerDescription.Type == ServerType.ReplicaSetPrimary) { if (args.NewServerDescription.ReplicaSetConfig.Version != null) { bool isCurrentPrimaryStale = true; if (_maxElectionInfo != null) { isCurrentPrimaryStale = _maxElectionInfo.IsStale(args.NewServerDescription.ReplicaSetConfig.Version.Value, args.NewServerDescription.ElectionId); var isReportedPrimaryStale = _maxElectionInfo.IsFresher( args.NewServerDescription.ReplicaSetConfig.Version.Value, args.NewServerDescription.ElectionId); if (isReportedPrimaryStale && args.NewServerDescription.ElectionId != null) { // we only invalidate the "newly" reported stale primary if electionId was used. lock (_serversLock) { var server = _servers.SingleOrDefault(x => EndPointHelper.Equals(args.NewServerDescription.EndPoint, x.EndPoint)); server.Invalidate(); _sdamInformationEventHandler?.Invoke(new SdamInformationEvent(() => string.Format( @"Invalidating server: Setting ServerType to ""Unknown"" for {0} because it " + @"claimed to be the replica set primary for replica set ""{1}"" but sent a " + @"(setVersion, electionId) tuple of ({2}, {3}) that was less than than the " + @"largest tuple seen, (maxSetVersion, maxElectionId), of ({4}, {5}).", args.NewServerDescription.EndPoint, args.NewServerDescription.ReplicaSetConfig.Name, args.NewServerDescription.ReplicaSetConfig.Version, args.NewServerDescription.ElectionId, _maxElectionInfo.SetVersion, _maxElectionInfo.ElectionId))); return(clusterDescription.WithServerDescription( new ServerDescription(server.ServerId, server.EndPoint))); } } } if (isCurrentPrimaryStale) { if (_maxElectionInfo == null) { _sdamInformationEventHandler?.Invoke(new SdamInformationEvent(() => string.Format( @"Initializing (maxSetVersion, maxElectionId): Saving tuple " + @"(setVersion, electionId) of ({0}, {1}) as (maxSetVersion, maxElectionId) for " + @"replica set ""{2}"" because replica set primary {3} sent ({0}, {1}), the first " + @"(setVersion, electionId) tuple ever seen for replica set ""{4}"".", args.NewServerDescription.ReplicaSetConfig.Version, args.NewServerDescription.ElectionId, args.NewServerDescription.ReplicaSetConfig.Name, args.NewServerDescription.EndPoint, args.NewServerDescription.ReplicaSetConfig.Name))); } else { if (_maxElectionInfo.SetVersion < args.NewServerDescription.ReplicaSetConfig.Version.Value) { _sdamInformationEventHandler?.Invoke(new SdamInformationEvent(() => string.Format( @"Updating stale setVersion: Updating the current " + @"(maxSetVersion, maxElectionId) tuple from ({0}, {1}) to ({2}, {3}) for " + @"replica set ""{4}"" because replica set primary {5} sent ({6}, {7})—a larger " + @"(setVersion, electionId) tuple then the saved tuple, ({0}, {1}).", _maxElectionInfo.SetVersion, _maxElectionInfo.ElectionId, args.NewServerDescription.ReplicaSetConfig.Version, args.NewServerDescription.ElectionId, args.NewServerDescription.ReplicaSetConfig.Name, args.NewServerDescription.EndPoint, args.NewServerDescription.ReplicaSetConfig.Version, args.NewServerDescription.ElectionId))); } else // current primary is stale & setVersion is not stale ⇒ the electionId must be stale { _sdamInformationEventHandler?.Invoke(new SdamInformationEvent(() => string.Format( @"Updating stale electionId: Updating the current " + @"(maxSetVersion, maxElectionId) tuple from ({0}, {1}) to ({2}, {3}) for " + @"replica set ""{4}"" because replica set primary {5} sent ({6}, {7})—" + @"a larger (setVersion, electionId) tuple than the saved tuple, ({0}, {1}).", _maxElectionInfo.SetVersion, _maxElectionInfo.ElectionId, args.NewServerDescription.ReplicaSetConfig.Version, args.NewServerDescription.ElectionId, args.NewServerDescription.ReplicaSetConfig.Name, args.NewServerDescription.EndPoint, args.NewServerDescription.ReplicaSetConfig.Version, args.NewServerDescription.ElectionId))); } } _maxElectionInfo = new ElectionInfo( args.NewServerDescription.ReplicaSetConfig.Version.Value, args.NewServerDescription.ElectionId); } } var currentPrimaryEndPoints = clusterDescription.Servers .Where(x => x.Type == ServerType.ReplicaSetPrimary) .Where(x => !EndPointHelper.Equals(x.EndPoint, args.NewServerDescription.EndPoint)) .Select(x => x.EndPoint) .ToList(); if (currentPrimaryEndPoints.Count > 0) { lock (_serversLock) { var currentPrimaries = _servers.Where(x => EndPointHelper.Contains(currentPrimaryEndPoints, x.EndPoint)); foreach (var currentPrimary in currentPrimaries) { // kick off the server to invalidate itself currentPrimary.Invalidate(); // set it to disconnected in the cluster clusterDescription = clusterDescription.WithServerDescription( new ServerDescription(currentPrimary.ServerId, currentPrimary.EndPoint)); } } } } return(clusterDescription); }
private ClusterDescription ProcessReplicaSetChange(ClusterDescription clusterDescription, ServerDescriptionChangedEventArgs args, List <IClusterableServer> newServers) { if (!args.NewServerDescription.Type.IsReplicaSetMember()) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server is a {0}, not a replica set member.", args.NewServerDescription.Type))); } if (args.NewServerDescription.Type == ServerType.ReplicaSetGhost) { return(clusterDescription.WithServerDescription(args.NewServerDescription)); } if (_replicaSetName == null) { _replicaSetName = args.NewServerDescription.ReplicaSetConfig.Name; } if (_replicaSetName != args.NewServerDescription.ReplicaSetConfig.Name) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server was a member of the '{0}' replica set, but should be '{1}'.", args.NewServerDescription.ReplicaSetConfig.Name, _replicaSetName))); } clusterDescription = clusterDescription.WithServerDescription(args.NewServerDescription); clusterDescription = EnsureServers(clusterDescription, args.NewServerDescription, newServers); if (args.NewServerDescription.CanonicalEndPoint != null && !EndPointHelper.Equals(args.NewServerDescription.CanonicalEndPoint, args.NewServerDescription.EndPoint)) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, "CanonicalEndPoint is different than seed list EndPoint.")); } if (args.NewServerDescription.Type == ServerType.ReplicaSetPrimary) { if (args.NewServerDescription.ReplicaSetConfig.Version != null) { bool isCurrentPrimaryStale = true; if (_maxElectionInfo != null) { isCurrentPrimaryStale = _maxElectionInfo.IsStale(args.NewServerDescription.ReplicaSetConfig.Version.Value, args.NewServerDescription.ElectionId); var isReportedPrimaryStale = !isCurrentPrimaryStale; if (isReportedPrimaryStale && args.NewServerDescription.ElectionId != null) { // we only invalidate the "newly" reported stale primary if electionId was used. lock (_serversLock) { var server = _servers.SingleOrDefault(x => EndPointHelper.Equals(args.NewServerDescription.EndPoint, x.EndPoint)); server.Invalidate(); return(clusterDescription.WithServerDescription( new ServerDescription(server.ServerId, server.EndPoint))); } } } if (isCurrentPrimaryStale) { _maxElectionInfo = new ElectionInfo( args.NewServerDescription.ReplicaSetConfig.Version.Value, args.NewServerDescription.ElectionId); } } var currentPrimaryEndPoints = clusterDescription.Servers .Where(x => x.Type == ServerType.ReplicaSetPrimary) .Where(x => !EndPointHelper.Equals(x.EndPoint, args.NewServerDescription.EndPoint)) .Select(x => x.EndPoint) .ToList(); if (currentPrimaryEndPoints.Count > 0) { lock (_serversLock) { var currentPrimaries = _servers.Where(x => EndPointHelper.Contains(currentPrimaryEndPoints, x.EndPoint)); foreach (var currentPrimary in currentPrimaries) { // kick off the server to invalidate itself currentPrimary.Invalidate(); // set it to disconnected in the cluster clusterDescription = clusterDescription.WithServerDescription( new ServerDescription(currentPrimary.ServerId, currentPrimary.EndPoint)); } } } } return(clusterDescription); }
private ClusterDescription ProcessReplicaSetChange(ClusterDescription clusterDescription, ServerDescriptionChangedEventArgs args) { if (!args.NewServerDescription.Type.IsReplicaSetMember()) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server is a {0}, not a replica set member.", args.NewServerDescription.Type))); } if (args.NewServerDescription.Type == ServerType.ReplicaSetGhost) { return(clusterDescription.WithServerDescription(args.NewServerDescription)); } if (_replicaSetName == null) { _replicaSetName = args.NewServerDescription.ReplicaSetConfig.Name; } if (_replicaSetName != args.NewServerDescription.ReplicaSetConfig.Name) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server was a member of the '{0}' replica set, but should be '{1}'.", args.NewServerDescription.ReplicaSetConfig.Name, _replicaSetName))); } clusterDescription = clusterDescription.WithServerDescription(args.NewServerDescription); clusterDescription = EnsureServers(clusterDescription, args.NewServerDescription); if (args.NewServerDescription.CanonicalEndPoint != null && !EndPointHelper.Equals(args.NewServerDescription.CanonicalEndPoint, args.NewServerDescription.EndPoint)) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, "CanonicalEndPoint is different than seed list EndPoint.")); } if (args.NewServerDescription.Type == ServerType.ReplicaSetPrimary) { if (args.NewServerDescription.ElectionId != null) { if (_maxElectionId != null && _maxElectionId.CompareTo(args.NewServerDescription.ElectionId) > 0) { // ignore this change because we've already seen this election id lock (_serversLock) { var server = _servers.SingleOrDefault(x => EndPointHelper.Equals(args.NewServerDescription.EndPoint, x.EndPoint)); server.Invalidate(); return(clusterDescription.WithServerDescription( new ServerDescription(server.ServerId, server.EndPoint))); } } _maxElectionId = args.NewServerDescription.ElectionId; } var currentPrimaryEndPoints = clusterDescription.Servers .Where(x => x.Type == ServerType.ReplicaSetPrimary) .Where(x => !EndPointHelper.Equals(x.EndPoint, args.NewServerDescription.EndPoint)) .Select(x => x.EndPoint) .ToList(); if (currentPrimaryEndPoints.Count > 0) { lock (_serversLock) { var currentPrimaries = _servers.Where(x => EndPointHelper.Contains(currentPrimaryEndPoints, x.EndPoint)); foreach (var currentPrimary in currentPrimaries) { // kick off the server to invalidate itself currentPrimary.Invalidate(); // set it to disconnected in the cluster clusterDescription = clusterDescription.WithServerDescription( new ServerDescription(currentPrimary.ServerId, currentPrimary.EndPoint)); } } } } return(clusterDescription); }
public IServer SelectServer() { lock (_cluster._descriptionLock) { _descriptionChangedTask = _cluster._descriptionChangedTaskCompletionSource.Task; _description = _cluster._description; } if (!_serverSelectionWaitQueueEntered) { var selectingServerEventHandler = _cluster._selectingServerEventHandler; if (selectingServerEventHandler != null) { // this is our first time through... selectingServerEventHandler(new ClusterSelectingServerEvent( _description, _selector, EventContext.OperationId)); } } MongoIncompatibleDriverException.ThrowIfNotSupported(_description); _connectedServers.Clear(); _connectedServerDescriptions.Clear(); foreach (var description in _description.Servers) { if (description.State == ServerState.Connected && _cluster.TryGetServer(description.EndPoint, out var server)) { _connectedServers.Add(server); _connectedServerDescriptions.Add(description); } } var selectedServersDescriptions = _selector .SelectServers(_description, _connectedServerDescriptions) .ToList(); IServer selectedServer = null; if (selectedServersDescriptions.Count > 0) { var selectedServerDescription = selectedServersDescriptions.Count == 1 ? selectedServersDescriptions[0] : __randomServerSelector.SelectServers(_description, selectedServersDescriptions).Single(); selectedServer = _connectedServers.FirstOrDefault(s => EndPointHelper.Equals(s.EndPoint, selectedServerDescription.EndPoint)); } if (selectedServer != null) { _stopwatch.Stop(); _cluster._selectedServerEventHandler?.Invoke(new ClusterSelectedServerEvent( _description, _selector, selectedServer.Description, _stopwatch.Elapsed, EventContext.OperationId)); } return(selectedServer); }