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);
        }
예제 #2
0
        private void ServerDescriptionChanged(object sender, ServerDescriptionChangedEventArgs args)
        {
            var oldClusterDescription = Description;
            ClusterDescription newClusterDescription = oldClusterDescription;

            var newServerDescription = args.NewServerDescription;

            if (newServerDescription.State == ServerState.Disconnected)
            {
                newClusterDescription = Description
                                        .WithServerDescription(newServerDescription);
            }
            else
            {
                var determinedClusterType = DetermineClusterType(newServerDescription);
                if (oldClusterDescription.Type == ClusterType.Unknown)
                {
                    newClusterDescription = newClusterDescription
                                            .WithType(determinedClusterType)
                                            .WithServerDescription(newServerDescription);
                }
                else if (determinedClusterType != oldClusterDescription.Type)
                {
                    newClusterDescription = newClusterDescription
                                            .WithoutServerDescription(newServerDescription.EndPoint);
                }
                else
                {
                    newClusterDescription = newClusterDescription
                                            .WithServerDescription(newServerDescription);
                }
            }

            UpdateClusterDescription(newClusterDescription);
        }
예제 #3
0
 private ClusterDescription ProcessStandaloneChange(ClusterDescription clusterDescription, ServerDescriptionChangedEventArgs args)
 {
     if (Settings.EndPoints.Count > 1)
     {
         return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, "Cluster was provided with multiple endpoints, one of which is a standalone."));
     }
     if (args.NewServerDescription.Type != ServerType.Standalone)
     {
         return(clusterDescription.WithServerDescription(
                    new ServerDescription(args.NewServerDescription.ServerId, args.NewServerDescription.EndPoint)));
     }
     else
     {
         return(clusterDescription.WithServerDescription(args.NewServerDescription));
     }
 }
예제 #4
0
        private ClusterDescription ProcessShardedChange(ClusterDescription clusterDescription, ServerDescriptionChangedEventArgs args)
        {
            if (args.NewServerDescription.Type != ServerType.ShardRouter)
            {
                return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, "Server is not a shard router."));
            }

            return(clusterDescription.WithServerDescription(args.NewServerDescription));
        }
예제 #5
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);
        }
예제 #6
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));
        }
예제 #7
0
        private ClusterDescription EnsureServer(ClusterDescription clusterDescription, EndPoint endPoint)
        {
            if (_state.Value == State.Disposed)
            {
                return(clusterDescription);
            }

            IClusterableServer server;
            Stopwatch          stopwatch = new Stopwatch();

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

                if (Listener != null)
                {
                    Listener.ClusterBeforeAddingServer(ClusterId, endPoint);
                }

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

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

            if (Listener != null)
            {
                Listener.ClusterAfterAddingServer(server.ServerId, stopwatch.Elapsed);
            }

            return(clusterDescription);
        }
예제 #8
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);
        }
예제 #9
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);
        }
예제 #10
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);
        }