Beispiel #1
0
        private ClusterDescription RemoveServer(ClusterDescription clusterDescription, EndPoint endPoint, string reason)
        {
            IClusterableServer server;
            var stopwatch = new Stopwatch();

            lock (_serversLock)
            {
                server = _servers.SingleOrDefault(x => EndPointHelper.Equals(x.EndPoint, endPoint));
                if (server == null)
                {
                    return(clusterDescription);
                }

                if (_removingServerEventHandler != null)
                {
                    _removingServerEventHandler(new ClusterRemovingServerEvent(server.ServerId, reason));
                }

                stopwatch.Start();
                _servers.Remove(server);
            }

            server.DescriptionChanged -= ServerDescriptionChangedHandler;
            server.Dispose();
            stopwatch.Stop();

            if (_removedServerEventHandler != null)
            {
                _removedServerEventHandler(new ClusterRemovedServerEvent(server.ServerId, reason, stopwatch.Elapsed));
            }

            return(clusterDescription.WithoutServerDescription(endPoint));
        }
Beispiel #2
0
        /// <inheritdoc/>
        public bool Equals(ServerDescription other)
        {
            if (object.ReferenceEquals(other, null) || other.GetType() != typeof(ServerDescription))
            {
                return(false);
            }

            return
                (_averageRoundTripTime == other._averageRoundTripTime &&
                 object.Equals(_canonicalEndPoint, other._canonicalEndPoint) &&
                 object.Equals(_electionId, other._electionId) &&
                 EndPointHelper.Equals(_endPoint, other._endPoint) &&
                 object.Equals(_heartbeatException, other._heartbeatException) &&
                 _heartbeatInterval == other._heartbeatInterval &&
                 _lastUpdateTimestamp == other._lastUpdateTimestamp &&
                 _lastWriteTimestamp == other._lastWriteTimestamp &&
                 _logicalSessionTimeout == other._logicalSessionTimeout &&
                 _maxBatchCount == other._maxBatchCount &&
                 _maxDocumentSize == other._maxDocumentSize &&
                 _maxMessageSize == other._maxMessageSize &&
                 _maxWireDocumentSize == other._maxWireDocumentSize &&
                 object.Equals(_replicaSetConfig, other._replicaSetConfig) &&
                 _serverId.Equals(other._serverId) &&
                 _state == other._state &&
                 object.Equals(_tags, other._tags) &&
                 _type == other._type &&
                 object.Equals(_version, other._version) &&
                 object.Equals(_wireVersionRange, other._wireVersionRange));
        }
 internal MongoServerInstance GetServerInstance(EndPoint endPoint)
 {
     lock (_serverLock)
     {
         return(_serverInstances.FirstOrDefault(i => EndPointHelper.Equals(i.EndPoint, endPoint)));
     }
 }
Beispiel #4
0
        public bool Equals(ServerDescription x, ServerDescription y)
        {
            var lastUpdateTimestampDelta = Math.Abs((x.LastUpdateTimestamp - y.LastUpdateTimestamp).TotalMilliseconds);
            var tolerance = 1000.0; // 1 second

            return
                (x.AverageRoundTripTime.Equals(y.AverageRoundTripTime) &&
                 object.Equals(x.CanonicalEndPoint, y.CanonicalEndPoint) &&
                 object.Equals(x.ElectionId, y.ElectionId) &&
                 EndPointHelper.Equals(x.EndPoint, y.EndPoint) &&
                 object.Equals(x.HeartbeatException, y.HeartbeatException) &&
                 x.HeartbeatInterval.Equals(y.HeartbeatInterval) &&
                 lastUpdateTimestampDelta <= tolerance &&
                 x.LastWriteTimestamp.Equals(y.LastWriteTimestamp) &&
                 x.MaxBatchCount.Equals(y.MaxBatchCount) &&
                 x.MaxDocumentSize.Equals(y.MaxDocumentSize) &&
                 x.MaxMessageSize.Equals(y.MaxMessageSize) &&
                 x.MaxWireDocumentSize.Equals(y.MaxWireDocumentSize) &&
                 object.Equals(x.ReplicaSetConfig, y.ReplicaSetConfig) &&
                 x.ServerId.Equals(y.ServerId) &&
                 x.State.Equals(y.State) &&
                 object.Equals(x.Tags, y.Tags) &&
                 x.Type.Equals(y.Type) &&
#pragma warning disable CS0618 // Type or member is obsolete
                 object.Equals(x.Version, y.Version) &&
#pragma warning restore CS0618 // Type or member is obsolete
                 object.Equals(x.WireVersionRange, y.WireVersionRange));
        }
Beispiel #5
0
        public async Task Misbehaved_async_method_should_not_deadlock_server_selection()
        {
            RequireServer.Check().ClusterType(ClusterType.ReplicaSet);

            // note: the code below deadlocks because await StartSessionAsync continues when UpdateClusterDescription in Cluster called TrySetResult after finding the secondary
            // but then the sync call to RunCommand blocks waiting for a primary and the call to TrySetResult never returns
            // which in turn prevents SDAM from unwinding back to process the next queued heartbeat event so the primary is never found

            var primary = CoreTestConfiguration.Cluster.Description.Servers.Where(s => s.Type == ServerType.ReplicaSetPrimary).Single();

            void clusterConfigurator(ClusterBuilder builder)
            {
                builder.Subscribe((ServerHeartbeatSucceededEvent heartbeatEvent) =>
                {
                    // ensure that the primary heartbeat is the last to be processed by introducing a small artificial delay
                    if (EndPointHelper.Equals(heartbeatEvent.ConnectionId.ServerId.EndPoint, primary.EndPoint))
                    {
                        Thread.Sleep(TimeSpan.FromSeconds(1));
                    }
                });
            }

            using (var client = DriverTestConfiguration.CreateDisposableClient(clusterConfigurator))
            {
                using (var session = await client.StartSessionAsync().ConfigureAwait(false))
                {
                    var adminDatabase = client.GetDatabase("admin");
                    adminDatabase.RunCommand <BsonDocument>(session, "{ ping : 1 }"); // this async method is misbehaving by calling a blocking sync method
                }
            }
        }
        private void ProcessServerDescriptionChanged(ServerDescriptionChangedEventArgs args)
        {
            var newServers = new List <IClusterableServer>();

            lock (_updateClusterDescriptionLock)
            {
                var newServerDescription  = args.NewServerDescription;
                var newClusterDescription = Description;

                if (!_servers.Any(x => EndPointHelper.Equals(x.EndPoint, newServerDescription.EndPoint)))
                {
                    return;
                }

                if (newServerDescription.State == ServerState.Disconnected)
                {
                    newClusterDescription = newClusterDescription.WithServerDescription(newServerDescription);
                }
                else
                {
                    if (IsServerValidForCluster(newClusterDescription.Type, Settings.ConnectionMode, newServerDescription.Type))
                    {
                        if (newClusterDescription.Type == ClusterType.Unknown)
                        {
                            newClusterDescription = newClusterDescription.WithType(newServerDescription.Type.ToClusterType());
                        }

                        switch (newClusterDescription.Type)
                        {
                        case ClusterType.Standalone:
                            newClusterDescription = ProcessStandaloneChange(newClusterDescription, args);
                            break;

                        case ClusterType.ReplicaSet:
                            newClusterDescription = ProcessReplicaSetChange(newClusterDescription, args, newServers);
                            break;

                        case ClusterType.Sharded:
                            newClusterDescription = ProcessShardedChange(newClusterDescription, args);
                            break;

                        default:
                            throw new MongoInternalException("Unexpected cluster type.");
                        }
                    }
                    else
                    {
                        var reason = $"The server {newServerDescription.EndPoint} with type {newServerDescription.Type} is not valid for cluster type {newClusterDescription.Type}.";
                        newClusterDescription = RemoveServer(newClusterDescription, newServerDescription.EndPoint, reason);
                    }
                }

                UpdateClusterDescription(newClusterDescription);
            }

            foreach (var server in newServers)
            {
                server.Initialize();
            }
        }
Beispiel #7
0
        // methods
        /// <inheritdoc/>
        public IEnumerable <ServerDescription> SelectServers(ClusterDescription cluster, IEnumerable <ServerDescription> servers)
        {
            var list = servers.ToList();

            switch (list.Count)
            {
            case 0:
            case 1:
                return(list);

            default:
            {
                // Follow the "Power of Two Choices" approach
                // https://web.archive.org/web/20191212194243/https://www.nginx.com/blog/nginx-power-of-two-choices-load-balancing-algorithm/
                var index1 = ThreadStaticRandom.Next(list.Count);
                var index2 = (index1 + 1 + ThreadStaticRandom.Next(list.Count - 1)) % list.Count;

                var endpoint1 = list[index1].EndPoint;
                var endpoint2 = list[index2].EndPoint;
                var server1   = _clusterableServers.First(s => EndPointHelper.Equals(s.Description.EndPoint, endpoint1));
                var server2   = _clusterableServers.First(s => EndPointHelper.Equals(s.Description.EndPoint, endpoint2));

                var selectedServer = server1.OutstandingOperationsCount < server2.OutstandingOperationsCount ? server1 : server2;

                return(new[] { selectedServer.Description });
            }
            }
        }
Beispiel #8
0
 protected override bool TryGetServer(EndPoint endPoint, out IClusterableServer server)
 {
     lock (_serversLock)
     {
         server = _servers.FirstOrDefault(s => EndPointHelper.Equals(s.EndPoint, endPoint));
         return(server != null);
     }
 }
Beispiel #9
0
        // constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="ServerDescription" /> class.
        /// </summary>
        /// <param name="serverId">The server identifier.</param>
        /// <param name="endPoint">The end point.</param>
        /// <param name="reasonChanged">The reason the server description was last changed.</param>
        /// <param name="averageRoundTripTime">The average round trip time.</param>
        /// <param name="canonicalEndPoint">The canonical end point.</param>
        /// <param name="electionId">The election identifier.</param>
        /// <param name="heartbeatException">The heartbeat exception.</param>
        /// <param name="heartbeatInterval">The heartbeat interval.</param>
        /// <param name="helloOk">Whether the server supports the hello command.</param>
        /// <param name="lastHeartbeatTimestamp">The last heartbeat timestamp.</param>
        /// <param name="lastUpdateTimestamp">The last update timestamp.</param>
        /// <param name="lastWriteTimestamp">The last write timestamp.</param>
        /// <param name="logicalSessionTimeout">The logical session timeout.</param>
        /// <param name="maxBatchCount">The maximum batch count.</param>
        /// <param name="maxDocumentSize">The maximum size of a document.</param>
        /// <param name="maxMessageSize">The maximum size of a message.</param>
        /// <param name="maxWireDocumentSize">The maximum size of a wire document.</param>
        /// <param name="replicaSetConfig">The replica set configuration.</param>
        /// <param name="state">The server state.</param>
        /// <param name="tags">The replica set tags.</param>
        /// <param name="topologyVersion">The topology version.</param>
        /// <param name="type">The server type.</param>
        /// <param name="version">The server version.</param>
        /// <param name="wireVersionRange">The wire version range.</param>
        /// <exception cref="ArgumentException">EndPoint and ServerId.EndPoint must match.</exception>
        public ServerDescription(
            ServerId serverId,
            EndPoint endPoint,
            Optional <string> reasonChanged          = default(Optional <string>),
            Optional <TimeSpan> averageRoundTripTime = default(Optional <TimeSpan>),
            Optional <EndPoint> canonicalEndPoint    = default(Optional <EndPoint>),
            Optional <ElectionId> electionId         = default(Optional <ElectionId>),
            Optional <Exception> heartbeatException  = default(Optional <Exception>),
            Optional <TimeSpan> heartbeatInterval    = default(Optional <TimeSpan>),
            Optional <bool> helloOk = default(Optional <bool>),
            Optional <DateTime?> lastHeartbeatTimestamp = default(Optional <DateTime?>),
            Optional <DateTime> lastUpdateTimestamp     = default(Optional <DateTime>),
            Optional <DateTime?> lastWriteTimestamp     = default(Optional <DateTime?>),
            Optional <TimeSpan?> logicalSessionTimeout  = default(Optional <TimeSpan?>),
            Optional <int> maxBatchCount                 = default(Optional <int>),
            Optional <int> maxDocumentSize               = default(Optional <int>),
            Optional <int> maxMessageSize                = default(Optional <int>),
            Optional <int> maxWireDocumentSize           = default(Optional <int>),
            Optional <ReplicaSetConfig> replicaSetConfig = default(Optional <ReplicaSetConfig>),
            Optional <ServerState> state                 = default(Optional <ServerState>),
            Optional <TagSet> tags = default(Optional <TagSet>),
            Optional <TopologyVersion> topologyVersion = default(Optional <TopologyVersion>),
            Optional <ServerType> type               = default(Optional <ServerType>),
            Optional <SemanticVersion> version       = default(Optional <SemanticVersion>),
            Optional <Range <int> > wireVersionRange = default(Optional <Range <int> >))
        {
            Ensure.IsNotNull(endPoint, nameof(endPoint));
            Ensure.IsNotNull(serverId, nameof(serverId));
            if (!EndPointHelper.Equals(endPoint, serverId.EndPoint))
            {
                throw new ArgumentException("EndPoint and ServerId.EndPoint must match.");
            }

            _averageRoundTripTime = averageRoundTripTime.WithDefault(TimeSpan.Zero);
            _canonicalEndPoint    = canonicalEndPoint.WithDefault(null);
            _electionId           = electionId.WithDefault(null);
            _endPoint             = endPoint;
            _heartbeatException   = heartbeatException.WithDefault(null);
            _heartbeatInterval    = heartbeatInterval.WithDefault(TimeSpan.Zero);
            _helloOk = helloOk.WithDefault(false);
            _lastHeartbeatTimestamp = lastHeartbeatTimestamp.WithDefault(null);
            _lastUpdateTimestamp    = lastUpdateTimestamp.WithDefault(DateTime.UtcNow);
            _lastWriteTimestamp     = lastWriteTimestamp.WithDefault(null);
            _logicalSessionTimeout  = logicalSessionTimeout.WithDefault(null);
            _maxBatchCount          = maxBatchCount.WithDefault(1000);
            _maxDocumentSize        = maxDocumentSize.WithDefault(4 * 1024 * 1024);
            _maxMessageSize         = maxMessageSize.WithDefault(Math.Max(_maxDocumentSize + 1024, 16000000));
            _maxWireDocumentSize    = maxWireDocumentSize.WithDefault(_maxDocumentSize + 16 * 1024);
            _reasonChanged          = reasonChanged.WithDefault("NotSpecified");
            _replicaSetConfig       = replicaSetConfig.WithDefault(null);
            _serverId         = serverId;
            _state            = state.WithDefault(ServerState.Disconnected);
            _tags             = tags.WithDefault(null);
            _topologyVersion  = topologyVersion.WithDefault(null);
            _type             = type.WithDefault(ServerType.Unknown);
            _version          = version.WithDefault(null);
            _wireVersionRange = wireVersionRange.WithDefault(null);
        }
 // methods
 /// <inheritdoc/>
 public bool Equals(ServerId other)
 {
     if (other == null)
     {
         return(false);
     }
     return
         (_clusterId.Equals(other._clusterId) &&
          EndPointHelper.Equals(_endPoint, other._endPoint));
 }
 private void AssertServers(List <ServerDescription> actual, List <ServerDescription> expected)
 {
     if (expected.Count == 0)
     {
         actual.Count.Should().Be(0);
     }
     else
     {
         actual.Should().OnlyContain(x => expected.Any(y => EndPointHelper.Equals(x.EndPoint, y.EndPoint)));
     }
 }
        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.Type == ServerType.ReplicaSetPrimary &&
                args.OldServerDescription.Type != ServerType.ReplicaSetPrimary)
            {
                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);
        }
Beispiel #13
0
        /// <summary>
        /// Gets the server description.
        /// </summary>
        /// <returns>The server description.</returns>
        public ServerDescription GetServerDescription()
        {
            var serverDescription = _cluster.Description.Servers.FirstOrDefault(s => EndPointHelper.Equals(s.EndPoint, _endPoint));

            if (serverDescription == null)
            {
                throw new InvalidOperationException(string.Format(
                                                        "Cluster does not contain a server with end point: '{0}'.",
                                                        _endPoint));
            }
            return(serverDescription);
        }
Beispiel #14
0
 protected override bool TryGetServer(EndPoint endPoint, out IClusterableServer server)
 {
     if (EndPointHelper.Equals(_server.EndPoint, endPoint))
     {
         server = _server;
         return(true);
     }
     else
     {
         server = null;
         return(false);
     }
 }
        private void ProcessServerDescriptionChanged(ServerDescriptionChangedEventArgs args)
        {
            var currentClusterDescription = Description;
            var currentServerDescription  = args.OldServerDescription;
            var newServerDescription      = args.NewServerDescription;

            var currentServer = _servers.SingleOrDefault(x => EndPointHelper.Equals(x.EndPoint, newServerDescription.EndPoint));

            if (currentServer == null)
            {
                return;
            }

            ClusterDescription newClusterDescription;

            if (newServerDescription.State == ServerState.Disconnected)
            {
                newClusterDescription = currentClusterDescription.WithServerDescription(args.NewServerDescription);
            }
            else if (newServerDescription.Type == ServerType.Standalone)
            {
                newClusterDescription = currentClusterDescription.WithoutServerDescription(args.NewServerDescription.EndPoint);
            }
            else
            {
                if (currentClusterDescription.Type == ClusterType.Unknown)
                {
                    currentClusterDescription = currentClusterDescription.WithType(args.NewServerDescription.Type.ToClusterType());
                }

                switch (currentClusterDescription.Type)
                {
                case ClusterType.ReplicaSet:
                    newClusterDescription = ProcessReplicaSetChange(currentClusterDescription, args);
                    break;

                case ClusterType.Sharded:
                    newClusterDescription = ProcessShardedChange(currentClusterDescription, args);
                    break;

                case ClusterType.Standalone:
                    throw new MongoInternalException("MultiServerCluster does not support a standalone state.");

                default:
                    newClusterDescription = currentClusterDescription.WithServerDescription(newServerDescription);
                    break;
                }
            }

            UpdateClusterDescription(newClusterDescription);
        }
Beispiel #16
0
        /// <summary>
        /// Returns a new ClusterDescription with a ServerDescription removed.
        /// </summary>
        /// <param name="endPoint">The end point of the server description to remove.</param>
        /// <returns>A ClusterDescription.</returns>
        public ClusterDescription WithoutServerDescription(EndPoint endPoint)
        {
            var oldServerDescription = _servers.SingleOrDefault(s => s.EndPoint == endPoint);

            if (oldServerDescription == null)
            {
                return(this);
            }

            return(new ClusterDescription(
                       _clusterId,
                       _type,
                       _servers.Where(s => !EndPointHelper.Equals(s.EndPoint, endPoint))));
        }
 /// <summary>
 /// Determines whether the specified <see cref="ServerDescription" /> can be considered as equal to decide should we publish sdam events or not.
 /// </summary>
 /// <param name="other">The other server description.</param>
 /// <returns><c>true</c>, if sdam events should be suppressed, otherwise <c>false</c>.</returns>
 public bool SdamEquals(ServerDescription other)
 {
     return
         (EndPointHelper.Equals(_endPoint, other._endPoint) &&
          _type == other.Type &&
          object.Equals(_wireVersionRange, other._wireVersionRange) &&
          EndPointHelper.Equals(_canonicalEndPoint, other._canonicalEndPoint) &&                         // me
          EndPointHelper.SequenceEquals(_replicaSetConfig?.Members, other._replicaSetConfig?.Members) && // hosts, passives, arbiters
          object.Equals(_tags, other._tags) &&
          _replicaSetConfig?.Name == other._replicaSetConfig?.Name &&                                    // setName
          _replicaSetConfig?.Version == other._replicaSetConfig?.Version &&                              // setVersion
          object.Equals(_electionId, other._electionId) &&
          EndPointHelper.Equals(_replicaSetConfig?.Primary, other._replicaSetConfig?.Primary) &&         // primary
          _logicalSessionTimeout == other._logicalSessionTimeout);
 }
Beispiel #18
0
        public void Description_should_contain_expected_server_description()
        {
            var subject = CreateSubject();

            subject.Description.Servers.Should().BeEmpty();
            subject.Initialize();
            _capturedEvents.Clear();

            PublishDescription(_endPoint);

            var description = subject.Description;

            description.Servers.Should().ContainSingle(s => EndPointHelper.Equals(s.EndPoint, _endPoint) && s.State == ServerState.Connected);

            _capturedEvents.Next().Should().BeOfType <ClusterDescriptionChangedEvent>();
            _capturedEvents.Any().Should().BeFalse();
        }
        private void ProcessServerDescriptionChanged(ServerDescriptionChangedEventArgs args)
        {
            var newServerDescription  = args.NewServerDescription;
            var newClusterDescription = Description;

            if (!_servers.Any(x => EndPointHelper.Equals(x.EndPoint, newServerDescription.EndPoint)))
            {
                return;
            }

            if (newServerDescription.State == ServerState.Disconnected)
            {
                newClusterDescription = newClusterDescription.WithServerDescription(newServerDescription);
            }
            else
            {
                if (IsServerValidForCluster(newClusterDescription.Type, Settings.ConnectionMode, newServerDescription.Type))
                {
                    if (newClusterDescription.Type == ClusterType.Unknown)
                    {
                        newClusterDescription = newClusterDescription.WithType(newServerDescription.Type.ToClusterType());
                    }

                    switch (newClusterDescription.Type)
                    {
                    case ClusterType.ReplicaSet:
                        newClusterDescription = ProcessReplicaSetChange(newClusterDescription, args);
                        break;

                    case ClusterType.Sharded:
                        newClusterDescription = ProcessShardedChange(newClusterDescription, args);
                        break;

                    default:
                        throw new MongoInternalException("Unexpected cluster type.");
                    }
                }
                else
                {
                    newClusterDescription = newClusterDescription.WithoutServerDescription(newServerDescription.EndPoint);
                }
            }

            UpdateClusterDescription(newClusterDescription);
        }
Beispiel #20
0
        /// <summary>
        /// Returns a new ClusterDescription with a ServerDescription removed.
        /// </summary>
        /// <param name="endPoint">The end point of the server description to remove.</param>
        /// <returns>A ClusterDescription.</returns>
        public ClusterDescription WithoutServerDescription(EndPoint endPoint)
        {
            var oldServerDescription = _servers.SingleOrDefault(s => s.EndPoint == endPoint);

            if (oldServerDescription == null)
            {
                return(this);
            }

            return(new ClusterDescription(
                       _clusterId,
                       _connectionMode,
                       _connectionModeSwitch,
                       _directConnection,
                       _dnsMonitorException,
                       _type,
                       _servers.Where(s => !EndPointHelper.Equals(s.EndPoint, endPoint))));
        }
Beispiel #21
0
        // constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="ServerDescription" /> class.
        /// </summary>
        /// <param name="serverId">The server identifier.</param>
        /// <param name="endPoint">The end point.</param>
        /// <param name="averageRoundTripTime">The average round trip time.</param>
        /// <param name="canonicalEndPoint">The canonical end point.</param>
        /// <param name="electionId">The election identifier.</param>
        /// <param name="heartbeatException">The heartbeat exception.</param>
        /// <param name="maxBatchCount">The maximum batch count.</param>
        /// <param name="maxDocumentSize">The maximum size of a document.</param>
        /// <param name="maxMessageSize">The maximum size of a message.</param>
        /// <param name="maxWireDocumentSize">The maximum size of a wire document.</param>
        /// <param name="replicaSetConfig">The replica set configuration.</param>
        /// <param name="state">The server state.</param>
        /// <param name="tags">The replica set tags.</param>
        /// <param name="type">The server type.</param>
        /// <param name="version">The server version.</param>
        /// <param name="wireVersionRange">The wire version range.</param>
        /// <exception cref="System.ArgumentException">EndPoint and ServerId.EndPoint must match.</exception>
        public ServerDescription(
            ServerId serverId,
            EndPoint endPoint,
            Optional <TimeSpan> averageRoundTripTime     = default(Optional <TimeSpan>),
            Optional <EndPoint> canonicalEndPoint        = default(Optional <EndPoint>),
            Optional <ElectionId> electionId             = default(Optional <ElectionId>),
            Optional <Exception> heartbeatException      = default(Optional <Exception>),
            Optional <int> maxBatchCount                 = default(Optional <int>),
            Optional <int> maxDocumentSize               = default(Optional <int>),
            Optional <int> maxMessageSize                = default(Optional <int>),
            Optional <int> maxWireDocumentSize           = default(Optional <int>),
            Optional <ReplicaSetConfig> replicaSetConfig = default(Optional <ReplicaSetConfig>),
            Optional <ServerState> state                 = default(Optional <ServerState>),
            Optional <TagSet> tags                   = default(Optional <TagSet>),
            Optional <ServerType> type               = default(Optional <ServerType>),
            Optional <SemanticVersion> version       = default(Optional <SemanticVersion>),
            Optional <Range <int> > wireVersionRange = default(Optional <Range <int> >))
        {
            Ensure.IsNotNull(endPoint, "endPoint");
            Ensure.IsNotNull(serverId, "serverId");
            if (!EndPointHelper.Equals(endPoint, serverId.EndPoint))
            {
                throw new ArgumentException("EndPoint and ServerId.EndPoint must match.");
            }

            _averageRoundTripTime = averageRoundTripTime.WithDefault(TimeSpan.Zero);
            _canonicalEndPoint    = canonicalEndPoint.WithDefault(null);
            _electionId           = electionId.WithDefault(null);
            _endPoint             = endPoint;
            _heartbeatException   = heartbeatException.WithDefault(null);
            _maxBatchCount        = maxBatchCount.WithDefault(1000);
            _maxDocumentSize      = maxDocumentSize.WithDefault(4 * 1024 * 1024);
            _maxMessageSize       = maxMessageSize.WithDefault(Math.Max(_maxDocumentSize + 1024, 16000000));
            _maxWireDocumentSize  = maxWireDocumentSize.WithDefault(_maxDocumentSize + 16 * 1024);
            _replicaSetConfig     = replicaSetConfig.WithDefault(null);
            _serverId             = serverId;
            _state            = state.WithDefault(ServerState.Disconnected);
            _tags             = tags.WithDefault(null);
            _type             = type.WithDefault(ServerType.Unknown);
            _version          = version.WithDefault(null);
            _wireVersionRange = wireVersionRange.WithDefault(null);
        }
Beispiel #22
0
        private void VerifyOutcome(BsonDocument outcome)
        {
            var description = _cluster.Description;

            var expectedServers = outcome["servers"].AsBsonDocument.Elements.Select(x => new
            {
                EndPoint    = EndPointHelper.Parse(x.Name),
                Description = (BsonDocument)x.Value
            });

            var actualServers = description.Servers.Select(x => x.EndPoint);

            actualServers.Should().BeEquivalentTo(expectedServers.Select(x => x.EndPoint));

            foreach (var actualServer in description.Servers)
            {
                var expectedServer = expectedServers.Single(x => EndPointHelper.Equals(x.EndPoint, actualServer.EndPoint));
                VerifyServer(actualServer, expectedServer.Description);
            }
        }
        private IDisposable RequestStart(IServerSelector serverSelector, ReadPreference readPreference)
        {
            var request = __threadStaticRequest;

            if (request != null)
            {
                var selected = serverSelector.SelectServers(_cluster.Description, new[] { request.ServerDescription }).ToList();
                if (selected.Count == 0)
                {
                    throw new InvalidOperationException("A nested call to RequestStart was made that is not compatible with the existing request.");
                }
                request.NestingLevel++;
                return(new RequestStartResult(this));
            }

            IReadBindingHandle channelBinding;
            ConnectionId       connectionId;
            var server = _cluster.SelectServer(serverSelector, CancellationToken.None);

            using (var channel = server.GetChannel(CancellationToken.None))
            {
                if (readPreference.ReadPreferenceMode == ReadPreferenceMode.Primary)
                {
                    channelBinding = new ReadWriteBindingHandle(new ChannelReadWriteBinding(server, channel.Fork(), NoCoreSession.NewHandle()));
                }
                else
                {
                    channelBinding = new ReadBindingHandle(new ChannelReadBinding(server, channel.Fork(), readPreference, NoCoreSession.NewHandle()));
                }
                connectionId = channel.ConnectionDescription.ConnectionId;
            }

            var serverDescription = server.Description;
            var serverInstance    = _serverInstances.Single(i => EndPointHelper.Equals(i.EndPoint, serverDescription.EndPoint));
            var session           = _operationExecutor.StartImplicitSession(CancellationToken.None);

            __threadStaticRequest = new Request(serverDescription, serverInstance, channelBinding, connectionId, session);

            return(new RequestStartResult(this));
        }
Beispiel #24
0
        private ClusterDescription EnsureServer(ClusterDescription clusterDescription, EndPoint endPoint, List <IClusterableServer> newServers)
        {
            if (_state.Value == State.Disposed)
            {
                return(clusterDescription);
            }

            IClusterableServer server;
            Stopwatch          stopwatch = new Stopwatch();

            lock (_serversLock)
            {
                if (_servers.Any(n => EndPointHelper.Equals(n.EndPoint, endPoint)))
                {
                    return(clusterDescription);
                }

                if (_addingServerEventHandler != null)
                {
                    _addingServerEventHandler(new ClusterAddingServerEvent(ClusterId, endPoint));
                }

                stopwatch.Start();
                server = CreateServer(endPoint);
                server.DescriptionChanged += ServerDescriptionChangedHandler;
                _servers.Add(server);
                newServers.Add(server);
            }

            clusterDescription = clusterDescription.WithServerDescription(server.Description);
            stopwatch.Stop();

            if (_addedServerEventHandler != null)
            {
                _addedServerEventHandler(new ClusterAddedServerEvent(server.ServerId, stopwatch.Elapsed));
            }

            return(clusterDescription);
        }
Beispiel #25
0
        private ClusterDescription ProcessStandaloneChange(ClusterDescription clusterDescription, ServerDescriptionChangedEventArgs args)
        {
            if (args.NewServerDescription.Type != ServerType.Unknown)
            {
                if (args.NewServerDescription.Type == ServerType.Standalone)
                {
                    foreach (var endPoint in clusterDescription.Servers.Select(s => s.EndPoint).ToList())
                    {
                        if (!EndPointHelper.Equals(endPoint, args.NewServerDescription.EndPoint))
                        {
                            clusterDescription = RemoveServer(clusterDescription, endPoint, "Removing all other end points once a standalone is discovered.");
                        }
                    }
                }
                else
                {
                    return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, "Server is not a standalone server."));
                }
            }

            return(clusterDescription.WithServerDescription(args.NewServerDescription));
        }
Beispiel #26
0
        /// <inheritdoc/>
        public bool Equals(ServerDescription rhs)
        {
            if (object.ReferenceEquals(rhs, null) || rhs.GetType() != typeof(ServerDescription))
            {
                return(false);
            }

            return
                (_averageRoundTripTime == rhs._averageRoundTripTime &&
                 EndPointHelper.Equals(_endPoint, rhs._endPoint) &&
                 object.Equals(_heartbeatException, rhs._heartbeatException) &&
                 _maxBatchCount == rhs._maxBatchCount &&
                 _maxDocumentSize == rhs._maxDocumentSize &&
                 _maxMessageSize == rhs._maxMessageSize &&
                 _maxWireDocumentSize == rhs._maxWireDocumentSize &&
                 object.Equals(_replicaSetConfig, rhs._replicaSetConfig) &&
                 _serverId.Equals(rhs._serverId) &&
                 _state == rhs._state &&
                 object.Equals(_tags, rhs._tags) &&
                 _type == rhs._type &&
                 object.Equals(_version, rhs._version) &&
                 object.Equals(_wireVersionRange, rhs._wireVersionRange));
        }
Beispiel #27
0
            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);
            }
Beispiel #28
0
        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);
        }
Beispiel #29
0
        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);
        }
Beispiel #30
0
        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);
        }