// internal methods
        internal void Connect(TimeSpan timeout)
        {
            var exceptions = new List<Exception>();
            foreach (var address in server.Settings.Servers)
            {
                try
                {
                    var serverInstance = server.Instance;
                    if (serverInstance.Address != address)
                    {
                        serverInstance.Address = address;
                    }
                    serverInstance.Connect(server.Settings.SlaveOk); // TODO: what about timeout?
                    return;
                }
                catch (Exception ex)
                {
                    exceptions.Add(ex);
                }
            }

            var firstAddress = server.Settings.Servers.First();
            var firstException = exceptions.First();
            var message = string.Format("Unable to connect to server {0}: {1}.", firstAddress, firstException.Message);
            var connectionException = new MongoConnectionException(message, firstException);
            connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one
            throw connectionException;
        }
        internal void Connect(
            TimeSpan timeout
        ) {
            server.ClearInstances();

            var exceptions = new List<Exception>();
            foreach (var address in server.Settings.Servers) {
                try {
                    var serverInstance = new MongoServerInstance(server, address);
                    server.AddInstance(serverInstance);
                    try {
                        serverInstance.Connect(server.Settings.SlaveOk); // TODO: what about timeout?
                    } catch {
                        server.RemoveInstance(serverInstance);
                        throw;
                    }

                    return;
                } catch (Exception ex) {
                    exceptions.Add(ex);
                }
            }

            var innerException = exceptions.FirstOrDefault();
            var connectionException = new MongoConnectionException("Unable to connect to server", innerException);
            if (exceptions.Count > 1) {
                connectionException.Data.Add("exceptions", exceptions);
            }
            throw connectionException;
        }
示例#3
0
 private static string MongoConnectionExceptionHandle(MongoConnectionException ex,
                                                      List <TreeNode> trvMongoDb,
                                                      TreeNode connectionNode, string mongoConnKey)
 {
     //暂时不处理任何异常,简单跳过
     //无法连接的理由:
     //1.服务器没有启动
     //2.认证模式不正确
     if (!GuiConfig.IsUseDefaultLanguage)
     {
         connectionNode.Text += "[" +
                                GuiConfig.GetText(
             TextType.ExceptionNotConnected) + "]";
         Utility.ExceptionDeal(ex,
                               GuiConfig.GetText(TextType.ExceptionNotConnected),
                               GuiConfig.GetText(TextType.ExceptionNotConnectedNote));
     }
     else
     {
         connectionNode.Text += "[Exception]";
         Utility.ExceptionDeal(ex, "Not Connected", "Mongo Server may not Startup or Auth Mode is not correct");
     }
     connectionNode.Tag = ConstMgr.ConnectionExceptionTag + ":" + mongoConnKey;
     trvMongoDb.Add(connectionNode);
     return(mongoConnKey);
 }
示例#4
0
        internal void Connect(
            TimeSpan timeout
            )
        {
            server.ClearInstances();

            var exceptions = new List <Exception>();

            foreach (var address in server.Settings.Servers)
            {
                try {
                    var serverInstance = new MongoServerInstance(server, address);
                    server.AddInstance(serverInstance);
                    try {
                        serverInstance.Connect(server.Settings.SlaveOk); // TODO: what about timeout?
                    } catch {
                        server.RemoveInstance(serverInstance);
                        throw;
                    }

                    return;
                } catch (Exception ex) {
                    exceptions.Add(ex);
                }
            }

            var innerException      = exceptions.FirstOrDefault();
            var connectionException = new MongoConnectionException("Unable to connect to server.", innerException);

            if (exceptions.Count > 1)
            {
                connectionException.Data.Add("exceptions", exceptions);
            }
            throw connectionException;
        }
        // internal methods
        internal void Connect(TimeSpan timeout)
        {
            var exceptions = new List <Exception>();

            foreach (var address in server.Settings.Servers)
            {
                try
                {
                    var serverInstance = server.Instance;
                    if (serverInstance.Address != address)
                    {
                        serverInstance.Address = address;
                    }
                    serverInstance.Connect(server.Settings.SlaveOk); // TODO: what about timeout?
                    return;
                }
                catch (Exception ex)
                {
                    exceptions.Add(ex);
                }
            }

            var firstAddress        = server.Settings.Servers.First();
            var firstException      = exceptions.First();
            var message             = string.Format("Unable to connect to server {0}: {1}.", firstAddress, firstException.Message);
            var connectionException = new MongoConnectionException(message, firstException);

            connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one
            throw connectionException;
        }
示例#6
0
        internal void ShouldInvalidateServer_should_return_expected_result_for_exceptionType(string exceptionTypeName, bool expectedResult)
        {
            _subject.Initialize();
            Exception exception;
            var       clusterId     = new ClusterId(1);
            var       serverId      = new ServerId(clusterId, new DnsEndPoint("localhost", 27017));
            var       connectionId  = new ConnectionId(serverId);
            var       command       = new BsonDocument("command", 1);
            var       commandResult = new BsonDocument("ok", 1);

            switch (exceptionTypeName)
            {
            case nameof(EndOfStreamException): exception = new EndOfStreamException(); break;

            case nameof(Exception): exception = new Exception(); break;

            case nameof(IOException): exception = new IOException(); break;

            case nameof(MongoConnectionException): exception = new MongoConnectionException(connectionId, "message"); break;

            case nameof(MongoNodeIsRecoveringException): exception = new MongoNodeIsRecoveringException(connectionId, command, commandResult); break;

            case nameof(MongoNotPrimaryException): exception = new MongoNotPrimaryException(connectionId, command, commandResult); break;

            case nameof(SocketException): exception = new SocketException(); break;

            default: throw new Exception($"Invalid exceptionTypeName: {exceptionTypeName}.");
            }

            var result = _subject.ShouldInvalidateServer(exception);

            result.Should().Be(expectedResult);
        }
示例#7
0
        public void Connect(
            TimeSpan timeout
            )
        {
            var exceptions = new List <Exception>();

            foreach (var endPoint in server.EndPoints)
            {
                try {
                    Connect(endPoint, timeout);
                    return;
                } catch (Exception ex) {
                    exceptions.Add(ex);
                }
            }

            var innerException      = exceptions.FirstOrDefault();
            var connectionException = new MongoConnectionException("Unable to connect to server", innerException);

            if (exceptions.Count > 1)
            {
                connectionException.Data.Add("exceptions", exceptions);
            }
            throw connectionException;
        }
示例#8
0
        public void GetChannel_should_update_topology_and_clear_connection_pool_on_network_error_or_timeout(
            [Values("TimedOutSocketException", "NetworkUnreachableSocketException")] string errorType,
            [Values(false, true)] bool async)
        {
            var serverId           = new ServerId(_clusterId, _endPoint);
            var connectionId       = new ConnectionId(serverId);
            var innerMostException = CoreExceptionHelper.CreateException(errorType);

            var openConnectionException = new MongoConnectionException(connectionId, "Oops", new IOException("Cry", innerMostException));
            var mockConnection          = new Mock <IConnectionHandle>();

            mockConnection.Setup(c => c.Open(It.IsAny <CancellationToken>())).Throws(openConnectionException);
            mockConnection.Setup(c => c.OpenAsync(It.IsAny <CancellationToken>())).ThrowsAsync(openConnectionException);

            var connectionFactory = new Mock <IConnectionFactory>();

            connectionFactory.Setup(cf => cf.CreateConnection(serverId, _endPoint)).Returns(mockConnection.Object);

            var mockExceptionHandler   = new Mock <IConnectionExceptionHandler>();
            var connectionPoolSettings = new ConnectionPoolSettings();
            var connectionPool         = new ExclusiveConnectionPool(serverId, _endPoint, connectionPoolSettings, connectionFactory.Object, new EventAggregator(), mockExceptionHandler.Object);

            var mockConnectionPoolFactory = new Mock <IConnectionPoolFactory>();

            mockConnectionPoolFactory
            .Setup(f => f.CreateConnectionPool(It.IsAny <ServerId>(), _endPoint, It.IsAny <IConnectionExceptionHandler>()))
            .Returns(connectionPool);
            var mockMonitorServerDescription = new ServerDescription(serverId, _endPoint);
            var mockServerMonitor            = new Mock <IServerMonitor>();

            mockServerMonitor.SetupGet(m => m.Description).Returns(mockMonitorServerDescription);
            mockServerMonitor.SetupGet(m => m.Lock).Returns(new object());
            var mockServerMonitorFactory = new Mock <IServerMonitorFactory>();

            mockServerMonitorFactory.Setup(f => f.Create(It.IsAny <ServerId>(), _endPoint)).Returns(mockServerMonitor.Object);

            var subject = new DefaultServer(_clusterId, _clusterClock, _clusterConnectionMode, _connectionModeSwitch, _directConnection, _settings, _endPoint, mockConnectionPoolFactory.Object, mockServerMonitorFactory.Object, _capturedEvents, _serverApi);

            connectionPool._connectionExceptionHandler(subject);
            subject.Initialize();
            connectionPool.SetReady();

            IChannelHandle channel = null;
            Exception      exception;

            if (async)
            {
                exception = Record.Exception(() => channel = subject.GetChannelAsync(CancellationToken.None).GetAwaiter().GetResult());
            }
            else
            {
                exception = Record.Exception(() => channel = subject.GetChannel(CancellationToken.None));
            }

            channel.Should().BeNull();
            exception.Should().Be(openConnectionException);
            subject.Description.Type.Should().Be(ServerType.Unknown);
            subject.Description.ReasonChanged.Should().Contain("ChannelException during handshake");
        }
        public void GetChannel_should_not_update_topology_and_clear_connection_pool_on_MongoConnectionException(
            [Values("TimedOutSocketException", "NetworkUnreachableSocketException")] string errorType,
            [Values(false, true)] bool async)
        {
            var serverId                       = new ServerId(_clusterId, _endPoint);
            var connectionId                   = new ConnectionId(serverId);
            var innerMostException             = CoreExceptionHelper.CreateException(errorType);
            var mockConnectionExceptionHandler = new Mock <IConnectionExceptionHandler>();

            var openConnectionException = new MongoConnectionException(connectionId, "Oops", new IOException("Cry", innerMostException));
            var mockConnection          = new Mock <IConnectionHandle>();

            mockConnection.Setup(c => c.Open(It.IsAny <CancellationToken>())).Throws(openConnectionException);
            mockConnection.Setup(c => c.OpenAsync(It.IsAny <CancellationToken>())).ThrowsAsync(openConnectionException);

            var connectionFactory = new Mock <IConnectionFactory>();

            connectionFactory.Setup(cf => cf.CreateConnection(serverId, _endPoint)).Returns(mockConnection.Object);

            var connectionPoolSettings = new ConnectionPoolSettings();
            var connectionPool         = new ExclusiveConnectionPool(serverId, _endPoint, connectionPoolSettings, connectionFactory.Object, new EventAggregator(), mockConnectionExceptionHandler.Object);

            var mockConnectionPoolFactory = new Mock <IConnectionPoolFactory>();

            mockConnectionPoolFactory
            .Setup(f => f.CreateConnectionPool(It.IsAny <ServerId>(), _endPoint, It.IsAny <IConnectionExceptionHandler>()))
            .Returns(connectionPool);

            var subject = new LoadBalancedServer(_clusterId, _clusterClock, _settings, _endPoint, mockConnectionPoolFactory.Object, _capturedEvents, _serverApi);

            subject.Initialize();

            IChannelHandle channel = null;
            Exception      exception;

            if (async)
            {
                exception = Record.Exception(() => channel = subject.GetChannelAsync(CancellationToken.None).GetAwaiter().GetResult());
            }
            else
            {
                exception = Record.Exception(() => channel = subject.GetChannel(CancellationToken.None));
            }

            channel.Should().BeNull();
            exception.Should().Be(openConnectionException);
            subject.Description.Type.Should().Be(ServerType.LoadBalanced);
            subject.Description.ReasonChanged.Should().Be("Initialized");
            subject.Description.State.Should().Be(ServerState.Connected);

            _mockConnectionPool.Verify(c => c.Clear(It.IsAny <bool>()), Times.Never);
        }
示例#10
0
        internal void Connect(
            TimeSpan timeout
            )
        {
            timeoutAt = DateTime.UtcNow + timeout;

            // connect to all servers in the seed list in parallel (they will report responses back through the responseQueue)
            server.ClearInstances();
            foreach (var address in server.Settings.Servers)
            {
                QueueConnect(address);
            }

            // process the responses as they come back and return as soon as we have connected to the primary
            // any remaining responses after the primary will be processed in the background

            while (responses.Count < connects.Count)
            {
                var timeRemaining = timeoutAt - DateTime.UtcNow;
                var response      = responseQueue.Dequeue(timeRemaining);
                if (response == null)
                {
                    break; // we timed out
                }

                ProcessResponse(response);

                // return as soon as we've connected to the primary
                var serverInstance = response.ServerInstance;
                if (serverInstance.State == MongoServerState.Connected && serverInstance.IsPrimary)
                {
                    // make sure this serverInstance is still an instance of this server
                    // it might have been removed if the connection string used a DNS alias for the host
                    // (in which case we have already queued a connect using the official host name and should see that response shortly)
                    if (server.Instances.Contains(serverInstance))
                    {
                        // process any additional responses in the background
                        ThreadPool.QueueUserWorkItem(ProcessAdditionalResponsesWorkItem);
                        return;
                    }
                }
            }

            var exceptions     = responses.Select(r => r.ServerInstance.ConnectException).Where(e => e != null).ToArray();
            var innerException = exceptions.FirstOrDefault();
            var exception      = new MongoConnectionException("Unable to connect to server.", innerException);

            exception.Data.Add("InnerExceptions", exceptions);
            throw exception;
        }
        /// <summary>
        /// Connects to the server respecting the timeout and readPreference.
        /// </summary>
        /// <param name="timeout">The timeout.</param>
        /// <param name="readPreference">The read preference.</param>
        public void Connect(TimeSpan timeout, ReadPreference readPreference)
        {
            if (_instance.State != MongoServerState.Connected)
            {
                lock (_stateLock)
                {
                    if (_instance.State != MongoServerState.Connected)
                    {
                        _connectionAttempt++;
                        var exceptions = new List <Exception>();
                        foreach (var address in _settings.Servers)
                        {
                            try
                            {
                                _instance.Address = address;
                                _instance.Connect(); // TODO: what about timeout?

                                if (_settings.ReplicaSetName != null &&
                                    (_instance.InstanceType != MongoServerInstanceType.ReplicaSetMember || _instance.ReplicaSetInformation.Name != _settings.ReplicaSetName))
                                {
                                    exceptions.Add(new MongoConnectionException(string.Format("The server '{0}' is not a member of replica set '{1}'.", address, _settings.ReplicaSetName)));
                                    _instance.Disconnect();
                                    continue;
                                }

                                if (_instance.IsMasterResult.MyAddress != null)
                                {
                                    _instance.Address = _instance.IsMasterResult.MyAddress;
                                }
                                return;
                            }
                            catch (Exception ex)
                            {
                                exceptions.Add(ex);
                            }
                        }

                        var firstAddress        = _settings.Servers.First();
                        var firstException      = exceptions.First();
                        var message             = string.Format("Unable to connect to server {0}: {1}.", firstAddress, firstException.Message);
                        var connectionException = new MongoConnectionException(message, firstException);
                        connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one
                        throw connectionException;
                    }
                }
            }
        }
示例#12
0
        internal void ShouldInvalidateServer_should_return_expected_result_for_exceptionType(string exceptionTypeName, bool expectedResult)
        {
            _subject.Initialize();
            Exception exception;
            var       clusterId                = new ClusterId(1);
            var       serverId                 = new ServerId(clusterId, new DnsEndPoint("localhost", 27017));
            var       connectionId             = new ConnectionId(serverId);
            var       command                  = new BsonDocument("command", 1);
            var       notWritablePrimaryResult = new BsonDocument {
                { "code", ServerErrorCode.NotWritablePrimary }
            };
            var nodeIsRecoveringResult = new BsonDocument("code", ServerErrorCode.InterruptedAtShutdown);

            switch (exceptionTypeName)
            {
            case nameof(EndOfStreamException): exception = new EndOfStreamException(); break;

            case nameof(Exception): exception = new Exception(); break;

            case nameof(IOException): exception = new IOException(); break;

            case nameof(MongoConnectionException): exception = new MongoConnectionException(connectionId, "message"); break;

            case nameof(MongoNodeIsRecoveringException): exception = new MongoNodeIsRecoveringException(connectionId, command, notWritablePrimaryResult); break;

            case nameof(MongoNotPrimaryException): exception = new MongoNotPrimaryException(connectionId, command, nodeIsRecoveringResult); break;

            case nameof(SocketException): exception = new SocketException(); break;

            case "MongoConnectionExceptionWithSocketTimeout":
                var innermostException = new SocketException((int)SocketError.TimedOut);
                var innerException     = new IOException("Execute Order 66", innermostException);
                exception = new MongoConnectionException(connectionId, "Yes, Lord Sidious", innerException);
                break;

            case nameof(TimeoutException): exception = new TimeoutException(); break;

            case nameof(MongoExecutionTimeoutException): exception = new MongoExecutionTimeoutException(connectionId, "message"); break;

            default: throw new Exception($"Invalid exceptionTypeName: {exceptionTypeName}.");
            }

            var result = _subject.ShouldInvalidateServer(Mock.Of <IConnection>(), exception, new ServerDescription(_subject.ServerId, _subject.EndPoint), out _);

            result.Should().Be(expectedResult);
        }
        internal void Connect(
            TimeSpan timeout
        ) {
            timeoutAt = DateTime.UtcNow + timeout;

            // connect to all servers in the seed list in parallel (they will report responses back through the responseQueue)
            server.ClearInstances();
            foreach (var address in server.Settings.Servers) {
                QueueConnect(address);
            }

            // process the responses as they come back and return as soon as we have connected to the primary
            // any remaining responses after the primary will be processed in the background

            while (responses.Count < connects.Count) {
                var timeRemaining = timeoutAt - DateTime.UtcNow;
                var response = responseQueue.Dequeue(timeRemaining);
                if (response == null) {
                    break; // we timed out
                }

                ProcessResponse(response);

                // return as soon as we've connected to the primary
                var serverInstance = response.ServerInstance;
                if (serverInstance.State == MongoServerState.Connected && serverInstance.IsPrimary) {
                    // make sure this serverInstance is still an instance of this server
                    // it might have been removed if the connection string used a DNS alias for the host
                    // (in which case we have already queued a connect using the official host name and should see that response shortly)
                    if (server.Instances.Contains(serverInstance)) {
                        // process any additional responses in the background
                        ThreadPool.QueueUserWorkItem(ProcessAdditionalResponsesWorkItem);
                        return;
                    }
                }
            }

            var exceptions = responses.Select(r => r.ServerInstance.ConnectException).Where(e => e != null).ToArray();
            var innerException = exceptions.FirstOrDefault();
            var exception = new MongoConnectionException("Unable to connect to server.", innerException);
            exception.Data.Add("InnerExceptions", exceptions);
            throw exception;
        }
        public void Connect(
            TimeSpan timeout
        )
        {
            var exceptions = new List<Exception>();
            foreach (var endPoint in server.EndPoints) {
                try {
                    Connect(endPoint, timeout);
                    return;
                } catch (Exception ex) {
                    exceptions.Add(ex);
                }
            }

            var innerException = exceptions.FirstOrDefault();
            var connectionException = new MongoConnectionException("Unable to connect to server", innerException);
            if (exceptions.Count > 1) {
                connectionException.Data.Add("exceptions", exceptions);
            }
            throw connectionException;
        }
示例#15
0
        private void ThrowConnectionException(ReadPreference readPreference)
        {
            List <Exception> exceptions;

            lock (_lock)
            {
                exceptions = _instances.Select(x => x.ConnectException).Where(x => x != null).ToList();
            }
            var    firstException = exceptions.FirstOrDefault();
            string message;

            if (firstException == null)
            {
                message = string.Format("Unable to connect to a member of the replica set matching the read preference {0}", readPreference);
            }
            else
            {
                message = string.Format("Unable to connect to a member of the replica set matching the read preference {0}: {1}.", readPreference, firstException.Message);
            }
            var connectionException = new MongoConnectionException(message, firstException);

            connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one
            throw connectionException;
        }
示例#16
0
 // private methods
 private void EnrichExceptionDetails(MongoConnectionException ex)
 {
     // should be refactored in CSHARP-3720
     ex.Generation = _generation;
     ex.ServiceId  = _connection?.Description?.ServiceId;
 }
        private void ThrowConnectionException(ReadPreference readPreference)
        {
            List<Exception> exceptions;
            lock (_lock)
            {
                exceptions = _instances.Select(x => x.ConnectException).Where(x => x != null).ToList();
            }
            var firstException = exceptions.FirstOrDefault();
            string message;

            if (firstException == null)
            {
                message = string.Format("Unable to connect to a member of the replica set matching the read preference {0}", readPreference);
            }
            else
            {
                message = string.Format("Unable to connect to a member of the replica set matching the read preference {0}: {1}.", readPreference, firstException.Message);
            }
            var connectionException = new MongoConnectionException(message, firstException);
            connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one
            throw connectionException;
        }
示例#18
0
        // internal methods
        internal void Connect(TimeSpan timeout, ConnectWaitFor waitFor)
        {
            _timeoutAt = DateTime.UtcNow + timeout;

            // connect to all server instances in parallel (they will report responses back through the responseQueue)
            // the set of Instances initially comes from the seed list, but is adjusted to the official set once connected
            foreach (var serverInstance in _server.Instances)
            {
                QueueConnect(serverInstance);
            }

            // process the responses as they come back and return as soon as we have connected to the primary
            // any remaining responses after the primary will be processed in the background

            while (_responses.Count < _connects.Count)
            {
                var timeRemaining = _timeoutAt - DateTime.UtcNow;
                var response      = _responseQueue.Dequeue(timeRemaining);
                if (response == null)
                {
                    break; // we timed out
                }

                ProcessResponse(response);

                // return as soon as we can (according to the waitFor mode specified)
                bool exitEarly = false;
                switch (waitFor)
                {
                case ConnectWaitFor.All:
                    if (_server.Instances.All(i => i.State == MongoServerState.Connected))
                    {
                        exitEarly = true;
                    }
                    break;

                case ConnectWaitFor.AnySlaveOk:
                    // don't check for IsPassive because IsSecondary is also true for passives (and only true if not in recovery mode)
                    if (_server.Instances.Any(i => (i.IsPrimary || i.IsSecondary) && i.State == MongoServerState.Connected))
                    {
                        exitEarly = true;
                    }
                    break;

                case ConnectWaitFor.Primary:
                    var primary = _server.Primary;
                    if (primary != null && primary.State == MongoServerState.Connected)
                    {
                        exitEarly = true;
                    }
                    break;

                default:
                    throw new ArgumentException("Invalid ConnectWaitFor value.");
                }

                if (exitEarly)
                {
                    if (_responses.Count < _connects.Count)
                    {
                        // process any additional responses in the background
                        ThreadPool.QueueUserWorkItem(ProcessAdditionalResponsesWorkItem);
                    }
                    return;
                }
            }

            string waitForString;

            switch (waitFor)
            {
            case ConnectWaitFor.All: waitForString = "all members"; break;

            case ConnectWaitFor.AnySlaveOk: waitForString = "any slaveOk member"; break;

            case ConnectWaitFor.Primary: waitForString = "the primary member"; break;

            default: throw new ArgumentException("Invalid ConnectWaitFor value.");
            }

            var    exceptions     = _responses.Select(r => r.ServerInstance.ConnectException).Where(e => e != null).ToArray();
            var    firstException = exceptions.FirstOrDefault();
            string message;

            if (firstException == null)
            {
                message = string.Format("Unable to connect to {0} of the replica set.", waitForString);
            }
            else
            {
                message = string.Format("Unable to connect to {0} of the replica set: {1}.", waitForString, firstException.Message);
            }
            var connectionException = new MongoConnectionException(message, firstException);

            connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one
            throw connectionException;
        }
        // internal methods
        internal void Connect(TimeSpan timeout, ConnectWaitFor waitFor)
        {
            _timeoutAt = DateTime.UtcNow + timeout;

            // connect to all server instances in parallel (they will report responses back through the responseQueue)
            // the set of Instances initially comes from the seed list, but is adjusted to the official set once connected
            foreach (var serverInstance in _server.Instances)
            {
                QueueConnect(serverInstance);
            }

            // process the responses as they come back and return as soon as we have connected to the primary
            // any remaining responses after the primary will be processed in the background

            while (_responses.Count < _connects.Count)
            {
                var timeRemaining = _timeoutAt - DateTime.UtcNow;
                var response = _responseQueue.Dequeue(timeRemaining);
                if (response == null)
                {
                    break; // we timed out
                }

                ProcessResponse(response);

                // return as soon as we can (according to the waitFor mode specified)
                bool exitEarly = false;
                switch (waitFor)
                {
                    case ConnectWaitFor.All:
                        if (_server.Instances.All(i => i.State == MongoServerState.Connected))
                        {
                            exitEarly = true;
                        }
                        break;
                    case ConnectWaitFor.AnySlaveOk:
                        if (_server.Instances.Any(i => (i.IsPrimary || i.IsSecondary || i.IsPassive) && i.State == MongoServerState.Connected))
                        {
                            exitEarly = true;
                        }
                        break;
                    case ConnectWaitFor.Primary:
                        var primary = _server.Primary;
                        if (primary != null && primary.State == MongoServerState.Connected)
                        {
                            exitEarly = true;
                        }
                        break;
                    default:
                        throw new ArgumentException("Invalid ConnectWaitFor value.");
                }

                if (exitEarly)
                {
                    if (_responses.Count < _connects.Count)
                    {
                        // process any additional responses in the background
                        ThreadPool.QueueUserWorkItem(ProcessAdditionalResponsesWorkItem);
                    }
                    return;
                }
            }

            string waitForString;
            switch (waitFor)
            {
                case ConnectWaitFor.All: waitForString = "all members"; break;
                case ConnectWaitFor.AnySlaveOk: waitForString = "any slaveOk member"; break;
                case ConnectWaitFor.Primary: waitForString = "the primary member"; break;
                default: throw new ArgumentException("Invalid ConnectWaitFor value.");
            }

            var exceptions = _responses.Select(r => r.ServerInstance.ConnectException).Where(e => e != null).ToArray();
            var firstException = exceptions.FirstOrDefault();
            string message;
            if (firstException == null)
            {
                message = string.Format("Unable to connect to {0} of the replica set.", waitForString);
            }
            else
            {
                message = string.Format("Unable to connect to {0} of the replica set: {1}.", waitForString, firstException.Message);
            }
            var connectionException = new MongoConnectionException(message, firstException);
            connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one
            throw connectionException;
        }
 /// <summary>
 /// GetThreatLevel of MongoConnectionException
 /// </summary>
 /// <param name="exceptione"></param>
 /// <returns>Level</returns>
 public LogLevels.Levels GetThreatLevel(MongoConnectionException exceptione)
 {
     return(LogLevels.Levels.Error);
 }
示例#21
0
        public void HandleChannelException_should_update_topology_as_expected_on_network_error_or_timeout(
            string errorType, bool shouldUpdateTopology)
        {
            var       serverId     = new ServerId(_clusterId, _endPoint);
            var       connectionId = new ConnectionId(serverId);
            Exception innerMostException;

            switch (errorType)
            {
            case "MongoConnectionExceptionWithSocketTimeout":
                innerMostException = new SocketException((int)SocketError.TimedOut);
                break;

            case nameof(MongoConnectionException):
                innerMostException = new SocketException((int)SocketError.NetworkUnreachable);
                break;

            default: throw new ArgumentException("Unknown error type.");
            }

            var operationUsingChannelException = new MongoConnectionException(connectionId, "Oops", new IOException("Cry", innerMostException));
            var mockConnection = new Mock <IConnectionHandle>();
            var isMasterResult = new IsMasterResult(new BsonDocument {
                { "compressors", new BsonArray() }
            });
            // the server version doesn't matter when we're not testing MongoNotPrimaryExceptions, but is needed when
            // Server calls ShouldClearConnectionPoolForException
            var buildInfoResult = new BuildInfoResult(new BsonDocument {
                { "version", "4.4.0" }
            });

            mockConnection.SetupGet(c => c.Description)
            .Returns(new ConnectionDescription(new ConnectionId(serverId, 0), isMasterResult, buildInfoResult));
            var mockConnectionPool = new Mock <IConnectionPool>();

            mockConnectionPool.Setup(p => p.AcquireConnection(It.IsAny <CancellationToken>())).Returns(mockConnection.Object);
            mockConnectionPool.Setup(p => p.AcquireConnectionAsync(It.IsAny <CancellationToken>())).ReturnsAsync(mockConnection.Object);
            var mockConnectionPoolFactory = new Mock <IConnectionPoolFactory>();

            mockConnectionPoolFactory
            .Setup(f => f.CreateConnectionPool(It.IsAny <ServerId>(), _endPoint))
            .Returns(mockConnectionPool.Object);
            var mockMonitorServerInitialDescription = new ServerDescription(serverId, _endPoint).With(reasonChanged: "Initial D", type: ServerType.Unknown);
            var mockServerMonitor = new Mock <IServerMonitor>();

            mockServerMonitor.SetupGet(m => m.Description).Returns(mockMonitorServerInitialDescription);
            mockServerMonitor.SetupGet(m => m.Lock).Returns(new object());
            var mockServerMonitorFactory = new Mock <IServerMonitorFactory>();

            mockServerMonitorFactory.Setup(f => f.Create(It.IsAny <ServerId>(), _endPoint)).Returns(mockServerMonitor.Object);
            var subject = new DefaultServer(_clusterId, _clusterClock, _clusterConnectionMode, _connectionModeSwitch, _directConnection, _settings, _endPoint, mockConnectionPoolFactory.Object, mockServerMonitorFactory.Object, _capturedEvents, _serverApi);

            subject.Initialize();
            var heartbeatDescription = mockMonitorServerInitialDescription.With(reasonChanged: "Heartbeat", type: ServerType.Standalone);

            mockServerMonitor.Setup(m => m.Description).Returns(heartbeatDescription);
            mockServerMonitor.Raise(
                m => m.DescriptionChanged += null,
                new ServerDescriptionChangedEventArgs(mockMonitorServerInitialDescription, heartbeatDescription));
            subject.Description.Should().Be(heartbeatDescription);

            subject.HandleChannelException(mockConnection.Object, operationUsingChannelException);

            if (shouldUpdateTopology)
            {
                subject.Description.Type.Should().Be(ServerType.Unknown);
                subject.Description.ReasonChanged.Should().Contain("ChannelException");
            }
            else
            {
                subject.Description.Should().Be(heartbeatDescription);
            }
        }
        /// <summary>
        /// Connects to the server respecting the timeout and readPreference.
        /// </summary>
        /// <param name="timeout">The timeout.</param>
        /// <param name="readPreference">The read preference.</param>
        public void Connect(TimeSpan timeout, ReadPreference readPreference)
        {
            if (_instance.State != MongoServerState.Connected)
            {
                lock (_stateLock)
                {
                    if (_instance.State != MongoServerState.Connected)
                    {
                        _connectionAttempt++;
                        var exceptions = new List<Exception>();
                        foreach (var address in _settings.Servers)
                        {
                            try
                            {
                                _instance.Address = address;
                                _instance.Connect(); // TODO: what about timeout?

                                if (_settings.ReplicaSetName != null &&
                                    (_instance.InstanceType != MongoServerInstanceType.ReplicaSetMember || _instance.ReplicaSetInformation.Name != _settings.ReplicaSetName))
                                {
                                    exceptions.Add(new MongoConnectionException(string.Format("The server '{0}' is not a member of replica set '{1}'.", address, _settings.ReplicaSetName)));
                                    _instance.Disconnect();
                                    continue;
                                }

                                if (_instance.IsMasterResult.MyAddress != null)
                                {
                                    _instance.Address = _instance.IsMasterResult.MyAddress;
                                }
                                return;
                            }
                            catch (Exception ex)
                            {
                                exceptions.Add(ex);
                            }
                        }

                        var firstAddress = _settings.Servers.First();
                        var firstException = exceptions.First();
                        var message = string.Format("Unable to connect to server {0}: {1}.", firstAddress, firstException.Message);
                        var connectionException = new MongoConnectionException(message, firstException);
                        connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one
                        throw connectionException;
                    }
                }
            }
        }
        public void Connect(
            TimeSpan timeout
        ) {
            // query all servers in seed list in parallel (they will report responses back through the responsesQueue)
            var responsesQueue = QueueSeedListQueries();

            // process the responses as they come back and stop as soon as we find the primary (unless SlaveOk is true)
            // stragglers will continue to report responses to the responsesQueue but no one will read them
            // and eventually it will all get garbage collected

            var exceptions = new List<Exception>();
            var timeoutAt = DateTime.UtcNow + timeout;
            while (responses.Count < queries.Count) {
                var timeRemaining = timeoutAt - DateTime.UtcNow;
                var response = responsesQueue.Dequeue(timeRemaining);
                if (response == null) {
                    break; // we timed out
                }
                responses.Add(response.Address, response);

                if (response.Exception != null) {
                    exceptions.Add(response.Exception);
                    continue;
                }

                if (response.IsPrimary) {
                    primaryConnection = response.Connection;
                    replicaSet = GetHostAddresses(response);
                    maxDocumentSize = response.MaxDocumentSize;
                    maxMessageLength = response.MaxMessageLength;
                    if (!server.Settings.SlaveOk) {
                        break; // if we're not going to use the secondaries no need to wait for their replies
                    }
                } else {
                    if (server.Settings.SlaveOk) {
                        secondaryConnections.Add(response.Connection);
                    } else {
                        response.Connection.Close();
                    }
                }

                // look for additional members of the replica set that might not have been in the seed list and query them also
                foreach (var address in GetHostAddresses(response)) {
                    if (!queries.Contains(address)) {
                        var args = new QueryNodeParameters {
                            Address = address,
                            EndPoint = address.ToIPEndPoint(server.Settings.AddressFamily),
                            ResponseQueue = responsesQueue
                        };
                        ThreadPool.QueueUserWorkItem(QueryNodeWorkItem, args);
                        queries.Add(address);
                    }
                }
            }

            if (primaryConnection == null) {
                var innerException = exceptions.FirstOrDefault();
                var exception = new MongoConnectionException("Unable to connect to server", innerException);
                if (exceptions.Count > 1) {
                    exception.Data.Add("InnerExceptions", exceptions);
                }
                throw exception;
            }
        }
示例#24
0
        private void ApplyApplicationError(BsonDocument applicationError)
        {
            var expectedKeys = new[]
            {
                "address",
                "generation", // optional
                "maxWireVersion",
                "when",
                "type",
                "response" // optional
            };

            JsonDrivenHelper.EnsureAllFieldsAreValid(applicationError, expectedKeys);
            var       address            = applicationError["address"].AsString;
            var       endPoint           = EndPointHelper.Parse(address);
            var       server             = (Server)_serverFactory.GetServer(endPoint);
            var       connectionId       = new ConnectionId(server.ServerId);
            var       type               = applicationError["type"].AsString;
            var       maxWireVersion     = applicationError["maxWireVersion"].AsInt32;
            Exception simulatedException = null;

            switch (type)
            {
            case "command":
                var response = applicationError["response"].AsBsonDocument;
                var command  = new BsonDocument("Link", "start!");
                simulatedException = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(connectionId, command, response, "errmsg");
                Ensure.IsNotNull(simulatedException, nameof(simulatedException));
                break;

            case "network":
            {
                var innerException = CoreExceptionHelper.CreateException("IOExceptionWithNetworkUnreachableSocketException");
                simulatedException = new MongoConnectionException(connectionId, "Ignorance, yet knowledge.", innerException);
                break;
            }

            case "timeout":
            {
                var innerException = CoreExceptionHelper.CreateException("IOExceptionWithTimedOutSocketException");
                simulatedException = new MongoConnectionException(connectionId, "Chaos, yet harmony.", innerException);
                break;
            }

            default:
                throw new ArgumentException($"Unsupported value of {type} for type");
            }

            var mockConnection = new Mock <IConnectionHandle>();
            var isMasterResult = new IsMasterResult(new BsonDocument {
                { "compressors", new BsonArray() }
            });
            var serverVersion   = WireVersionHelper.MapWireVersionToServerVersion(maxWireVersion);
            var buildInfoResult = new BuildInfoResult(new BsonDocument {
                { "version", serverVersion }
            });

            mockConnection.SetupGet(c => c.Description)
            .Returns(new ConnectionDescription(connectionId, isMasterResult, buildInfoResult));
            var generation = applicationError.Contains("generation") ? applicationError["generation"].AsInt32 : 0;

            mockConnection.SetupGet(c => c.Generation).Returns(generation);
            var when = applicationError["when"].AsString;

            switch (when)
            {
            case "beforeHandshakeCompletes":
                server.HandleBeforeHandshakeCompletesException(mockConnection.Object, simulatedException);
                break;

            case "afterHandshakeCompletes":
                server.HandleChannelException(mockConnection.Object, simulatedException);
                break;

            default:
                throw new ArgumentException($"Unsupported value of {when} for when.");
            }
        }
示例#25
0
        public void Connect(
            TimeSpan timeout
            )
        {
            // query all servers in seed list in parallel (they will report responses back through the responsesQueue)
            var responsesQueue = QueueSeedListQueries();

            // process the responses as they come back and stop as soon as we find the primary (unless SlaveOk is true)
            // stragglers will continue to report responses to the responsesQueue but no one will read them
            // and eventually it will all get garbage collected

            var exceptions = new List <Exception>();
            var timeoutAt  = DateTime.UtcNow + timeout;

            while (responses.Count < queries.Count)
            {
                var timeRemaining = timeoutAt - DateTime.UtcNow;
                var response      = responsesQueue.Dequeue(timeRemaining);
                if (response == null)
                {
                    break; // we timed out
                }
                responses.Add(response.Address, response);

                if (response.Exception != null)
                {
                    exceptions.Add(response.Exception);
                    continue;
                }

                if (response.IsPrimary)
                {
                    primaryConnection = response.Connection;
                    replicaSet        = GetHostAddresses(response);
                    maxDocumentSize   = response.MaxDocumentSize;
                    maxMessageLength  = response.MaxMessageLength;
                    if (!server.Settings.SlaveOk)
                    {
                        break; // if we're not going to use the secondaries no need to wait for their replies
                    }
                }
                else
                {
                    if (server.Settings.SlaveOk)
                    {
                        secondaryConnections.Add(response.Connection);
                    }
                    else
                    {
                        response.Connection.Close();
                    }
                }

                // look for additional members of the replica set that might not have been in the seed list and query them also
                foreach (var address in GetHostAddresses(response))
                {
                    if (!queries.Contains(address))
                    {
                        var args = new QueryNodeParameters {
                            Address       = address,
                            EndPoint      = address.ToIPEndPoint(server.Settings.AddressFamily),
                            ResponseQueue = responsesQueue
                        };
                        ThreadPool.QueueUserWorkItem(QueryNodeWorkItem, args);
                        queries.Add(address);
                    }
                }
            }

            if (primaryConnection == null)
            {
                var innerException = exceptions.FirstOrDefault();
                var exception      = new MongoConnectionException("Unable to connect to server", innerException);
                if (exceptions.Count > 1)
                {
                    exception.Data.Add("InnerExceptions", exceptions);
                }
                throw exception;
            }
        }
示例#26
0
        public void GetChannel_should_update_topology_and_clear_connection_pool_on_network_error_or_timeout(
            [Values("timedout", "networkunreachable")] string errorType,
            [Values(false, true)] bool async)
        {
            var serverId           = new ServerId(_clusterId, _endPoint);
            var connectionId       = new ConnectionId(serverId);
            var innerMostException = CoreExceptionHelper.CreateSocketException(errorType);

            var openConnectionException = new MongoConnectionException(connectionId, "Oops", new IOException("Cry", innerMostException));
            var mockConnection          = new Mock <IConnectionHandle>();

            mockConnection.Setup(c => c.Open(It.IsAny <CancellationToken>())).Throws(openConnectionException);
            mockConnection.Setup(c => c.OpenAsync(It.IsAny <CancellationToken>())).ThrowsAsync(openConnectionException);
            var mockConnectionPool = new Mock <IConnectionPool>();

            mockConnectionPool.Setup(p => p.AcquireConnection(It.IsAny <CancellationToken>())).Returns(mockConnection.Object);
            mockConnectionPool.Setup(p => p.AcquireConnectionAsync(It.IsAny <CancellationToken>())).ReturnsAsync(mockConnection.Object);
            var mockConnectionPoolFactory = new Mock <IConnectionPoolFactory>();

            mockConnectionPoolFactory
            .Setup(f => f.CreateConnectionPool(It.IsAny <ServerId>(), _endPoint))
            .Returns(mockConnectionPool.Object);
            var mockMonitorServerDescription = new ServerDescription(serverId, _endPoint);
            var mockServerMonitor            = new Mock <IServerMonitor>();

            mockServerMonitor.SetupGet(m => m.Description).Returns(mockMonitorServerDescription);
            mockServerMonitor
            .Setup(m => m.Invalidate(It.IsAny <string>()))
            .Callback((string reason) => MockMonitorInvalidate(reason));
            var mockServerMonitorFactory = new Mock <IServerMonitorFactory>();

            mockServerMonitorFactory.Setup(f => f.Create(It.IsAny <ServerId>(), _endPoint)).Returns(mockServerMonitor.Object);

            var subject = new Server(_clusterId, _clusterClock, _clusterConnectionMode, _settings, _endPoint, mockConnectionPoolFactory.Object, mockServerMonitorFactory.Object, _capturedEvents);

            subject.Initialize();

            IChannelHandle channel = null;
            Exception      exception;

            if (async)
            {
                exception = Record.Exception(() => channel = subject.GetChannelAsync(CancellationToken.None).GetAwaiter().GetResult());
            }
            else
            {
                exception = Record.Exception(() => channel = subject.GetChannel(CancellationToken.None));
            }

            channel.Should().BeNull();
            exception.Should().Be(openConnectionException);
            subject.Description.Type.Should().Be(ServerType.Unknown);
            subject.Description.ReasonChanged.Should().Contain("ChannelException during handshake");
            mockServerMonitor.Verify(m => m.Invalidate(It.IsAny <string>()), Times.Once);
            mockConnectionPool.Verify(p => p.Clear(), Times.Once);

            void MockMonitorInvalidate(string reason)
            {
                var currentDescription = mockServerMonitor.Object.Description;

                mockServerMonitor.SetupGet(m => m.Description).Returns(currentDescription.With(reason));
            }
        }