private void OnDescriptionChanged(ServerDescription oldDescription, ServerDescription newDescription)
        {
            var handler = DescriptionChanged;

            if (handler != null)
            {
                var args = new ServerDescriptionChangedEventArgs(oldDescription, newDescription);
                try { handler(this, args); }
                catch { } // ignore exceptions
            }
        }
Example #2
0
        protected override void InitializeSubClass()
        {
            // generate initial server description
            var newDescription = _baseDescription
                                 .With(
                type: ServerType.LoadBalanced,
                reasonChanged: "Initialized",
                state: ServerState.Connected);
            var oldDescription = Interlocked.CompareExchange(ref _currentDescription, value: newDescription, comparand: _currentDescription);
            var eventArgs      = new ServerDescriptionChangedEventArgs(oldDescription, newDescription);

            // propagate event to upper levels, this will be called only once
            TriggerServerDescriptionChanged(this, eventArgs);
        }
        protected override void InitializeSubClass()
        {
            // generate initial server description
            var newDescription = _baseDescription
                                 .With(
                type: ServerType.LoadBalanced,
                reasonChanged: "Initialized",
                state: ServerState.Connected);
            var oldDescription = Interlocked.CompareExchange(ref _currentDescription, value: newDescription, comparand: _currentDescription);
            var eventArgs      = new ServerDescriptionChangedEventArgs(oldDescription, newDescription);

            // mark pool as ready, start the connection creation thread.
            // note that the pool can not be paused after it was marked as ready in LB mode.
            ConnectionPool.SetReady();

            // propagate event to upper levels, this will be called only once
            TriggerServerDescriptionChanged(this, eventArgs);
        }
Example #4
0
        private void OnDescriptionChanged(ServerDescription newDescription)
        {
            var oldDescription = Interlocked.CompareExchange(ref _currentDescription, null, null);

            if (oldDescription.Equals(newDescription))
            {
                return;
            }
            Interlocked.Exchange(ref _currentDescription, newDescription);

            var handler = DescriptionChanged;

            if (handler != null)
            {
                var args = new ServerDescriptionChangedEventArgs(oldDescription, newDescription);
                try { handler(this, args); }
                catch { } // ignore exceptions
            }
        }
Example #5
0
        private void OnDescriptionChanged(object sender, ServerDescriptionChangedEventArgs e)
        {
            if (e.NewServerDescription.HeartbeatException != null)
            {
                _connectionPool.Clear();
            }

            if (_descriptionChangedEventHandler != null)
            {
                _descriptionChangedEventHandler(new ServerDescriptionChangedEvent(e.OldServerDescription, e.NewServerDescription));
            }

            var handler = DescriptionChanged;

            if (handler != null)
            {
                try { handler(this, e); }
                catch { } // ignore exceptions
            }
        }
        // private methods
        private void OnMonitorDescriptionChanged(object sender, ServerDescriptionChangedEventArgs e)
        {
            var currentDescription = _currentDescription;

            var heartbeatException = e.NewServerDescription.HeartbeatException;
            // The heartbeat commands are hello (or legacy hello) + buildInfo. These commands will throw a MongoCommandException on
            // {ok: 0}, but a reply (with a potential topologyVersion) will still have been received.
            // Not receiving a reply to the heartbeat commands implies a network error or a "HeartbeatFailed" type
            // exception (i.e. ServerDescription.WithHeartbeatException was called), in which case we should immediately
            // set the description to "Unknown"// (which is what e.NewServerDescription will be in such a case)
            var heartbeatReplyNotReceived = heartbeatException != null && !(heartbeatException is MongoCommandException);

            // We cannot use FresherThan(e.NewServerDescription.TopologyVersion, currentDescription.TopologyVersion)
            // because due to how TopologyVersions comparisons are defined, IsStalerThanOrEqualTo(x, y) does not imply
            // FresherThan(y, x)
            if (heartbeatReplyNotReceived ||
                TopologyVersion.IsStalerThanOrEqualTo(currentDescription.TopologyVersion, e.NewServerDescription.TopologyVersion))
            {
                SetDescription(e.NewServerDescription, forceClearConnectionPool: false);
            }
        }
        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);
        }
        private void OnDescriptionChanged(ServerDescription newDescription)
        {
            var oldDescription = Interlocked.CompareExchange(ref _currentDescription, null, null);
            if (oldDescription.Equals(newDescription))
            {
                return;
            }
            Interlocked.Exchange(ref _currentDescription, newDescription);

            var handler = DescriptionChanged;
            if (handler != null)
            {
                var args = new ServerDescriptionChangedEventArgs(oldDescription, newDescription);
                try { handler(this, args); }
                catch { } // ignore exceptions
            }
        }
        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);
        }
        private void ServerDescriptionChanged(object sender, ServerDescriptionChangedEventArgs args)
        {
            var newServerDescription = args.NewServerDescription;
            var newClusterDescription = Description;

            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());
                    }

                    newClusterDescription = newClusterDescription.WithServerDescription(newServerDescription);
                }
                else
                {
                    newClusterDescription = newClusterDescription.WithoutServerDescription(newServerDescription.EndPoint);
                }
            }

            UpdateClusterDescription(newClusterDescription);
        }
        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;
        }
        private ClusterDescription ProcessReplicaSetChange(ClusterDescription clusterDescription, ServerDescriptionChangedEventArgs args, List<IClusterableServer> newServers)
        {
            if (!args.NewServerDescription.Type.IsReplicaSetMember())
            {
                return RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server is a {0}, not a replica set member.", args.NewServerDescription.Type));
            }

            if (args.NewServerDescription.Type == ServerType.ReplicaSetGhost)
            {
                return clusterDescription.WithServerDescription(args.NewServerDescription);
            }

            if (_replicaSetName == null)
            {
                _replicaSetName = args.NewServerDescription.ReplicaSetConfig.Name;
            }

            if (_replicaSetName != args.NewServerDescription.ReplicaSetConfig.Name)
            {
                return RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server was a member of the '{0}' replica set, but should be '{1}'.", args.NewServerDescription.ReplicaSetConfig.Name, _replicaSetName));
            }

            clusterDescription = clusterDescription.WithServerDescription(args.NewServerDescription);
            clusterDescription = EnsureServers(clusterDescription, args.NewServerDescription, newServers);

            if (args.NewServerDescription.CanonicalEndPoint != null &&
                !EndPointHelper.Equals(args.NewServerDescription.CanonicalEndPoint, args.NewServerDescription.EndPoint))
            {
                return RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, "CanonicalEndPoint is different than seed list EndPoint.");
            }

            if (args.NewServerDescription.Type == ServerType.ReplicaSetPrimary)
            {
                if (args.NewServerDescription.ReplicaSetConfig.Version != null)
                {
                    bool isCurrentPrimaryStale = true;
                    if (_maxElectionInfo != null)
                    {
                        isCurrentPrimaryStale = _maxElectionInfo.IsStale(args.NewServerDescription.ReplicaSetConfig.Version.Value, args.NewServerDescription.ElectionId);
                        var isReportedPrimaryStale = !isCurrentPrimaryStale;

                        if (isReportedPrimaryStale && args.NewServerDescription.ElectionId != null)
                        {
                            // we only invalidate the "newly" reported stale primary if electionId was used.
                            lock (_serversLock)
                            {
                                var server = _servers.SingleOrDefault(x => EndPointHelper.Equals(args.NewServerDescription.EndPoint, x.EndPoint));
                                server.Invalidate();
                                return clusterDescription.WithServerDescription(
                                    new ServerDescription(server.ServerId, server.EndPoint));
                            }
                        }
                    }

                    if (isCurrentPrimaryStale)
                    {
                        _maxElectionInfo = new ElectionInfo(
                            args.NewServerDescription.ReplicaSetConfig.Version.Value,
                            args.NewServerDescription.ElectionId);
                    }
                }

                var currentPrimaryEndPoints = clusterDescription.Servers
                    .Where(x => x.Type == ServerType.ReplicaSetPrimary)
                    .Where(x => !EndPointHelper.Equals(x.EndPoint, args.NewServerDescription.EndPoint))
                    .Select(x => x.EndPoint)
                    .ToList();

                if (currentPrimaryEndPoints.Count > 0)
                {
                    lock (_serversLock)
                    {
                        var currentPrimaries = _servers.Where(x => EndPointHelper.Contains(currentPrimaryEndPoints, x.EndPoint));
                        foreach (var currentPrimary in currentPrimaries)
                        {
                            // kick off the server to invalidate itself
                            currentPrimary.Invalidate();
                            // set it to disconnected in the cluster
                            clusterDescription = clusterDescription.WithServerDescription(
                                new ServerDescription(currentPrimary.ServerId, currentPrimary.EndPoint));
                        }
                    }
                }
            }

            return clusterDescription;
        }
        private 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);
        }
 private void ServerDescriptionChangedHandler(object sender, ServerDescriptionChangedEventArgs args)
 {
     _serverDescriptionChangedQueue.Enqueue(args);
 }
 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);
     }
 }
        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 => !x.EndPoint.Equals(args.NewServerDescription.EndPoint))
                    .Select(x => x.EndPoint)
                    .ToList();

                if (currentPrimaryEndPoints.Count > 0)
                {
                    lock (_serversLock)
                    {
                        var currentPrimaries = _servers.Where(x => currentPrimaryEndPoints.Contains(x.EndPoint));
                        foreach (var currentPrimary in currentPrimaries)
                        {
                            // kick off the server to invalidate itself
                            currentPrimary.Invalidate();
                            // set it to disconnected in the cluster
                            clusterDescription = clusterDescription.WithServerDescription(
                                new ServerDescription(currentPrimary.ServerId, currentPrimary.EndPoint));
                        }
                    }
                }
            }

            return clusterDescription;
        }
        private void ProcessServerDescriptionChanged(ServerDescriptionChangedEventArgs args)
        {
            var currentClusterDescription = Description;
            var currentServerDescription = args.OldServerDescription;
            var newServerDescription = args.NewServerDescription;

            var currentServer = _servers.SingleOrDefault(x => x.EndPoint.Equals(newServerDescription.EndPoint));
            if (currentServer == null)
            {
                return;
            }

            ClusterDescription newClusterDescription;
            if (args.NewServerDescription.State == ServerState.Disconnected)
            {
                newClusterDescription = currentClusterDescription.WithServerDescription(args.NewServerDescription);
            }
            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:
                        newClusterDescription = ProcessStandaloneChange(currentClusterDescription, args);
                        break;
                    default:
                        newClusterDescription = currentClusterDescription.WithServerDescription(newServerDescription);
                        break;
                }
            }

            UpdateClusterDescription(newClusterDescription);
        }