// constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="MongoServerInstance"/> class.
        /// </summary>
        /// <param name="settings">The settings.</param>
        /// <param name="address">The address.</param>
        internal MongoServerInstance(MongoServerSettings settings, MongoServerAddress address)
        {
            _settings = settings;
            _address = address;
            _sequentialId = Interlocked.Increment(ref __nextSequentialId);
            _state = MongoServerState.Disconnected;
            _serverInfo = new ServerInformation
            {
                MaxDocumentSize = MongoDefaults.MaxDocumentSize,
                MaxMessageLength = MongoDefaults.MaxMessageLength,
                InstanceType = MongoServerInstanceType.Unknown
            };
            _connectionPool = new MongoConnectionPool(this);
            _pingTimeAggregator = new PingTimeAggregator(5);
            _permanentlyDisconnected = false;
            // Console.WriteLine("MongoServerInstance[{0}]: {1}", sequentialId, address);

            _stateVerificationAcquireConnectionOptions = new MongoConnectionPool.AcquireConnectionOptions
            {
                OkToAvoidWaitingByCreatingNewConnection = false,
                OkToExceedMaxConnectionPoolSize = true,
                OkToExceedWaitQueueSize = true,
                WaitQueueTimeout = TimeSpan.FromSeconds(2)
            };
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ShardedMongoServerProxy"/> class.
        /// </summary>
        /// <param name="server">The server.</param>
        /// <param name="instances">The instances.</param>
        /// <param name="connectionQueue">The state change queue.</param>
        /// <param name="connectionAttempt">The connection attempt.</param>
        /// <remarks>This constructor is used when the instances have already been instructed to connect.</remarks>
        protected MultipleInstanceMongoServerProxy(MongoServer server, IEnumerable<MongoServerInstance> instances, BlockingQueue<MongoServerInstance> connectionQueue, int connectionAttempt)
        {
            _state = MongoServerState.Connecting;
            _server = server;
            _connectedInstances = new ConnectedInstanceCollection();
            _connectionAttempt = connectionAttempt;

            _outstandingInstanceConnections = connectionQueue.Count;
            ThreadPool.QueueUserWorkItem(_ =>
            {
                while (connectionQueue.Count > 0)
                {
                    var instance = connectionQueue.Dequeue();
                    Interlocked.Decrement(ref _outstandingInstanceConnections);
                }
            });

            // It's important to have our own copy of this list because it might get modified during iteration. 
            _instances = instances.ToList();
            foreach (var instance in instances)
            {
                instance.StateChanged += InstanceStateChanged;
                ProcessInstanceStateChange(instance);
            }
        }
Beispiel #3
0
        private void InstanceStateChanged(
            object sender,
            object args
            )
        {
            lock (instances) {
                if (instances.Any(i => i.State == MongoServerState.Connected && i.IsPrimary))
                {
                    // Console.WriteLine("Server state: Connected");
                    state = MongoServerState.Connected;
                    return;
                }

                if (settings.SlaveOk)
                {
                    if (instances.Any(i => i.State == MongoServerState.Connected && (i.IsSecondary || i.IsPassive)))
                    {
                        // Console.WriteLine("Server state: Connected");
                        state = MongoServerState.Connected;
                        return;
                    }
                }

                if (instances.Any(i => i.State == MongoServerState.Connecting))
                {
                    // Console.WriteLine("Server state: Connecting");
                    state = MongoServerState.Connecting;
                    return;
                }

                // Console.WriteLine("Server state: Disconnected");
                state = MongoServerState.Disconnected;
            }
        }
Beispiel #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MultipleInstanceMongoServerProxy"/> class.
        /// </summary>
        /// <param name="settings">The settings.</param>
        /// <param name="instances">The instances.</param>
        /// <param name="connectionQueue">The state change queue.</param>
        /// <param name="connectionAttempt">The connection attempt.</param>
        /// <remarks>This constructor is used when the instances have already been instructed to connect.</remarks>
        protected MultipleInstanceMongoServerProxy(MongoServerSettings settings, IEnumerable <MongoServerInstance> instances, BlockingQueue <MongoServerInstance> connectionQueue, int connectionAttempt)
        {
            _state              = MongoServerState.Connecting;
            _settings           = settings;
            _connectedInstances = new ConnectedInstanceCollection();
            _connectionAttempt  = connectionAttempt;

            _outstandingInstanceConnections = connectionQueue.Count;
            ThreadPool.QueueUserWorkItem(_ =>
            {
                while (connectionQueue.Count > 0)
                {
                    connectionQueue.Dequeue();
                    Interlocked.Decrement(ref _outstandingInstanceConnections);
                }
            });

            // It's important to have our own copy of this list because it might get modified during iteration.
            _instances = instances.ToList();
            foreach (var instance in instances)
            {
                instance.StateChanged += InstanceStateChanged;
                ProcessInstanceStateChange(instance);
            }
        }
        /// <remarks>This method must be called outside of a lock.</remarks>
        private void SetState(MongoServerState newState, ServerInformation newServerInfo)
        {
            bool raiseChangedEvent = false;

            lock (_serverInstanceLock)
            {
                if (_state != newState)
                {
                    _state            = newState;
                    raiseChangedEvent = true;
                }

                if (newState == MongoServerState.Disconnected)
                {
                    _connectionPool.Clear();
                }

                if (_serverInfo != newServerInfo && _serverInfo.IsDifferentFrom(newServerInfo))
                {
                    _serverInfo       = newServerInfo;
                    raiseChangedEvent = true;
                }
            }

            if (raiseChangedEvent)
            {
                OnStateChanged();
            }
        }
        /// <summary>
        /// Disconnects this instance.
        /// </summary>
        internal void Disconnect()
        {
            // Console.WriteLine("MongoServerInstance[{0}]: Disconnect called.", sequentialId);
            lock (_serverInstanceLock)
            {
                if (_stateVerificationTimer != null)
                {
                    _stateVerificationTimer.Dispose();
                    _stateVerificationTimer = null;
                }

                if (_state == MongoServerState.Disconnecting || _state == MongoServerState.Disconnected)
                {
                    return;
                }

                // set the state here because SetState raises an event that should not be raised while holding a lock
                _state = MongoServerState.Disconnecting;
            }

            // we know for certain state has just changed.
            OnStateChanged();

            try
            {
                _connectionPool.Clear();
            }
            finally
            {
                SetState(MongoServerState.Disconnected);
            }
        }
 // constructors
 /// <summary>
 /// Initializes a new instance of the <see cref="DiscoveringMongoServerProxy"/> class.
 /// </summary>
 /// <param name="sequentialId">The sequential id.</param>
 /// <param name="settings">The settings.</param>
 public DiscoveringMongoServerProxy(int sequentialId, MongoServerProxySettings settings)
 {
     _state = MongoServerState.Disconnected;
     _sequentialId = sequentialId;
     _settings = settings;
     _instances = settings.Servers.Select(a => new MongoServerInstance(settings, a)).ToList().AsReadOnly();
 }
        /// <summary>
        /// Determines the state of the server.
        /// </summary>
        /// <param name="currentState">State of the current.</param>
        /// <param name="instances">The instances.</param>
        /// <returns>The server state.</returns>
        protected override MongoServerState DetermineServerState(MongoServerState currentState, IEnumerable <MongoServerInstance> instances)
        {
            if (!instances.Any())
            {
                return(MongoServerState.Disconnected);
            }

            // the order of the tests is significant
            // and resolves ambiguities when more than one state might match
            if (currentState == MongoServerState.Disconnected)
            {
                return(MongoServerState.Disconnected);
            }
            else if (currentState == MongoServerState.Disconnecting)
            {
                if (instances.All(i => i.State == MongoServerState.Disconnected))
                {
                    return(MongoServerState.Disconnected);
                }

                return(MongoServerState.Disconnecting);
            }
            else
            {
                if (instances.Any(i => i.State == MongoServerState.Connected))
                {
                    return(MongoServerState.Connected);
                }

                return(MongoServerState.Connecting);
            }
        }
Beispiel #9
0
        // constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="MongoServerInstance"/> class.
        /// </summary>
        /// <param name="settings">The settings.</param>
        /// <param name="address">The address.</param>
        internal MongoServerInstance(MongoServerSettings settings, MongoServerAddress address)
        {
            _settings     = settings;
            _address      = address;
            _sequentialId = Interlocked.Increment(ref __nextSequentialId);
            _state        = MongoServerState.Disconnected;
            _serverInfo   = new ServerInformation
            {
                MaxDocumentSize  = MongoDefaults.MaxDocumentSize,
                MaxMessageLength = MongoDefaults.MaxMessageLength,
                InstanceType     = MongoServerInstanceType.Unknown
            };
            _connectionPool          = new MongoConnectionPool(this);
            _pingTimeAggregator      = new PingTimeAggregator(5);
            _permanentlyDisconnected = false;
            // Console.WriteLine("MongoServerInstance[{0}]: {1}", sequentialId, address);

            _stateVerificationAcquireConnectionOptions = new MongoConnectionPool.AcquireConnectionOptions
            {
                OkToAvoidWaitingByCreatingNewConnection = false,
                OkToExceedMaxConnectionPoolSize         = true,
                OkToExceedWaitQueueSize = true,
                WaitQueueTimeout        = TimeSpan.FromSeconds(2)
            };
        }
Beispiel #10
0
        /// <summary>
        /// Disconnects the server.
        /// </summary>
        public void Disconnect()
        {
            lock (_lock)
            {
                if (_state == MongoServerState.Disconnected || _state == MongoServerState.Disconnecting)
                {
                    return;
                }

                _state = MongoServerState.Disconnecting;
                try
                {
                    _connectedInstances.Clear();
                    foreach (var instance in _instances)
                    {
                        try
                        {
                            instance.Disconnect();
                        }
                        catch { } // ignore disconnection errors
                    }
                }
                finally
                {
                    _state = MongoServerState.Disconnected;
                }
            }
        }
Beispiel #11
0
 internal void ClearInstances()
 {
     lock (instances) {
         instances.ForEach(i => { i.StateChanged -= InstanceStateChanged; });
         instances.Clear();
         state = MongoServerState.Disconnected;
     }
 }
        /// <summary>
        /// Connects this instance.
        /// </summary>
        internal void Connect()
        {
            // Console.WriteLine("MongoServerInstance[{0}]: Connect() called.", sequentialId);
            lock (_serverInstanceLock)
            {
                if (_permanentlyDisconnected || _state == MongoServerState.Connecting || _state == MongoServerState.Connected)
                {
                    return;
                }

                _connectException = null;

                // set the state manually here because SetState raises an event that shouldn't be raised
                // while holding a lock.
                _state = MongoServerState.Connecting;
            }

            // We know for certain that the state just changed
            OnStateChanged();

            try
            {
                var connection = _connectionPool.AcquireConnection(null);
                try
                {
                    Ping(connection);
                    LookupServerInformation(connection);
                }
                finally
                {
                    _connectionPool.ReleaseConnection(connection);
                }
                SetState(MongoServerState.Connected);
            }
            catch (Exception ex)
            {
                lock (_serverInstanceLock)
                {
                    _connectException = ex;
                }
                _connectionPool.Clear();
                Interlocked.Exchange(ref _connectException, ex);
                SetState(MongoServerState.Disconnected);
                throw;
            }
            finally
            {
                lock (_serverInstanceLock)
                {
                    if (_stateVerificationTimer == null)
                    {
                        _stateVerificationTimer = new Timer(o => StateVerificationTimerCallback(), null, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10));
                    }
                }
            }
        }
        private MongoServerState state; // always use property to set value so event gets raised
        #endregion

        #region constructors
        internal MongoServerInstance(
            MongoServer server,
            MongoServerAddress address
        ) {
            this.server = server;
            this.address = address;
            this.maxDocumentSize = MongoDefaults.MaxDocumentSize;
            this.maxMessageLength = MongoDefaults.MaxMessageLength;
            this.state = MongoServerState.Disconnected;
        }
        internal void Connect(
            bool slaveOk
            )
        {
            if (state != MongoServerState.Disconnected)
            {
                var message = string.Format("MongoServerInstance.Connect called when state is: {0}", state);
                throw new InvalidOperationException(message);
            }

            State            = MongoServerState.Connecting;
            connectException = null;
            try {
                endPoint = address.ToIPEndPoint(server.Settings.AddressFamily);

                var connectionPool = new MongoConnectionPool(this);
                try {
                    var connection = connectionPool.AcquireConnection(null);
                    try {
                        try {
                            var isMasterCommand = new CommandDocument("ismaster", 1);
                            isMasterResult = connection.RunCommand("admin.$cmd", QueryFlags.SlaveOk, isMasterCommand);
                        } catch (MongoCommandException ex) {
                            isMasterResult = ex.CommandResult;
                            throw;
                        }

                        isPrimary   = isMasterResult.Response["ismaster", false].ToBoolean();
                        isSecondary = isMasterResult.Response["secondary", false].ToBoolean();
                        isPassive   = isMasterResult.Response["passive", false].ToBoolean();
                        isArbiter   = isMasterResult.Response["arbiterOnly", false].ToBoolean();
                        if (!isPrimary && !slaveOk)
                        {
                            throw new MongoConnectionException("Server is not a primary and SlaveOk is false");
                        }

                        maxDocumentSize  = isMasterResult.Response["maxBsonObjectSize", MongoDefaults.MaxDocumentSize].ToInt32();
                        maxMessageLength = Math.Max(MongoDefaults.MaxMessageLength, maxDocumentSize + 1024); // derived from maxDocumentSize
                    } finally {
                        connectionPool.ReleaseConnection(connection);
                    }
                } catch {
                    connectionPool.Close();
                    throw;
                }

                State = MongoServerState.Connected;
                this.connectionPool = connectionPool;
            } catch (Exception ex) {
                State            = MongoServerState.Disconnected;
                connectException = ex;
                throw;
            }
        }
        private MongoServerState _state; // always use property to set value so event gets raised

        // constructors
        internal MongoServerInstance(MongoServer server, MongoServerAddress address)
        {
            _server = server;
            _address = address;
            _sequentialId = Interlocked.Increment(ref __nextSequentialId);
            _maxDocumentSize = MongoDefaults.MaxDocumentSize;
            _maxMessageLength = MongoDefaults.MaxMessageLength;
            _state = MongoServerState.Disconnected;
            _connectionPool = new MongoConnectionPool(this);
            // Console.WriteLine("MongoServerInstance[{0}]: {1}", sequentialId, address);
        }
Beispiel #16
0
        private MongoServerState _state; // always use property to set value so event gets raised

        // constructors
        internal MongoServerInstance(MongoServer server, MongoServerAddress address)
        {
            _server           = server;
            _address          = address;
            _sequentialId     = Interlocked.Increment(ref __nextSequentialId);
            _maxDocumentSize  = MongoDefaults.MaxDocumentSize;
            _maxMessageLength = MongoDefaults.MaxMessageLength;
            _state            = MongoServerState.Disconnected;
            _connectionPool   = new MongoConnectionPool(this);
            // Console.WriteLine("MongoServerInstance[{0}]: {1}", sequentialId, address);
        }
Beispiel #17
0
 internal void SetState(MongoServerState state)
 {
     lock (_serverInstanceLock)
     {
         if (_state != state)
         {
             _state = state;
             OnStateChanged();
         }
     }
 }
Beispiel #18
0
        /// <summary>
        /// Connects to the server. Normally there is no need to call this method as
        /// the driver will connect to the server automatically when needed.
        /// </summary>
        /// <param name="timeout">How long to wait before timing out.</param>
        public virtual void Connect(
            TimeSpan timeout
            )
        {
            lock (serverLock) {
                if (state != MongoServerState.Connected)
                {
                    state = MongoServerState.Connecting;
                    try {
                        switch (settings.ConnectionMode)
                        {
                        case ConnectionMode.Direct:
                            var directConnector = new DirectConnector(this);
                            directConnector.Connect(timeout);
                            primaryConnectionPool    = new MongoConnectionPool(this, directConnector.Connection);
                            secondaryConnectionPools = null;
                            replicaSet       = null;
                            maxDocumentSize  = directConnector.MaxDocumentSize;
                            maxMessageLength = directConnector.MaxMessageLength;
                            break;

                        case ConnectionMode.ReplicaSet:
                            var replicaSetConnector = new ReplicaSetConnector(this);
                            replicaSetConnector.Connect(timeout);
                            primaryConnectionPool = new MongoConnectionPool(this, replicaSetConnector.PrimaryConnection);
                            if (settings.SlaveOk && replicaSetConnector.SecondaryConnections.Count > 0)
                            {
                                secondaryConnectionPools = new List <MongoConnectionPool>();
                                foreach (var connection in replicaSetConnector.SecondaryConnections)
                                {
                                    var secondaryConnectionPool = new MongoConnectionPool(this, connection);
                                    secondaryConnectionPools.Add(secondaryConnectionPool);
                                }
                            }
                            else
                            {
                                secondaryConnectionPools = null;
                            }
                            replicaSet       = replicaSetConnector.ReplicaSet;
                            maxDocumentSize  = replicaSetConnector.MaxDocumentSize;
                            maxMessageLength = replicaSetConnector.MaxMessageLength;
                            break;

                        default:
                            throw new MongoInternalException("Invalid ConnectionMode");
                        }
                        state = MongoServerState.Connected;
                    } catch {
                        state = MongoServerState.Disconnected;
                        throw;
                    }
                }
            }
        }
        private MongoServerState state; // always use property to set value so event gets raised
        #endregion

        #region constructors
        internal MongoServerInstance(
            MongoServer server,
            MongoServerAddress address
            )
        {
            this.server           = server;
            this.address          = address;
            this.maxDocumentSize  = MongoDefaults.MaxDocumentSize;
            this.maxMessageLength = MongoDefaults.MaxMessageLength;
            this.state            = MongoServerState.Disconnected;
        }
 // constructors
 internal MongoServerInstance(MongoServer server, MongoServerAddress address)
 {
     this.server = server;
     this.address = address;
     this.sequentialId = Interlocked.Increment(ref nextSequentialId);
     this.maxDocumentSize = MongoDefaults.MaxDocumentSize;
     this.maxMessageLength = MongoDefaults.MaxMessageLength;
     this.state = MongoServerState.Disconnected;
     this.connectionPool = new MongoConnectionPool(this);
     this.tags = new HashSet<string>();
     // Console.WriteLine("MongoServerInstance[{0}]: {1}", sequentialId, address);
 }
 internal void Disconnect()
 {
     if (state != MongoServerState.Disconnected)
     {
         try {
             connectionPool.Close();
             connectionPool = null;
         } finally {
             State = MongoServerState.Disconnected;
         }
     }
 }
 /// <summary>
 /// Connects to the instances 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)
 {
     try
     {
         EnsureInstanceManager(timeout);
     }
     catch
     {
         _state = MongoServerState.Disconnected;
         throw;
     }
     _serverProxy.Connect(timeout, readPreference);
 }
        /// <summary>
        /// Sets the state.
        /// </summary>
        /// <param name="state">The state.</param>
        internal void SetState(MongoServerState state)
        {
            lock (_serverInstanceLock)
            {
                if (_state == state)
                {
                    return;
                }

                _state = state;
            }

            OnStateChanged();
        }
 internal void SetState(MongoServerState state, bool isPrimary, bool isSecondary, bool isPassive, bool isArbiter)
 {
     lock (serverInstanceLock)
     {
         if (this.state != state || this.isPrimary != isPrimary || this.isSecondary != isSecondary || this.isPassive != isPassive || this.isArbiter != isArbiter)
         {
             this.state       = state;
             this.isPrimary   = isPrimary;
             this.isSecondary = isSecondary;
             this.isPassive   = isPassive;
             this.isArbiter   = isArbiter;
             OnStateChanged();
         }
     }
 }
 // private methods
 private void EnsureInstanceManager(TimeSpan timeout)
 {
     if (_serverProxy == null)
     {
         lock (_lock)
         {
             if (_serverProxy == null)
             {
                 _connectionAttempt++;
                 _state = MongoServerState.Connecting;
                 Discover(timeout);
             }
         }
     }
 }
 internal void Disconnect()
 {
     if (state != MongoServerState.Disconnected)
     {
         try {
             // if we fail during Connect the connectionPool field will still be null
             if (connectionPool != null)
             {
                 connectionPool.Close();
                 connectionPool = null;
             }
         } finally {
             State = MongoServerState.Disconnected;
         }
     }
 }
Beispiel #27
0
        /// <summary>
        /// Connects to the instances 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)
        {
            var timeoutAt = DateTime.UtcNow + timeout;

            while (DateTime.UtcNow < timeoutAt)
            {
                if (ChooseServerInstance(_connectedInstances, readPreference) != null)
                {
                    return;
                }

                if (Interlocked.CompareExchange(ref _outstandingInstanceConnections, 0, 0) > 0)
                {
                    Thread.Sleep(TimeSpan.FromMilliseconds(20));
                    continue;
                }

                lock (_lock)
                {
                    // test this again (kinda like the double lock check pattern).  This value may
                    // be different and we don't want to issue another round of connects needlessly.
                    if (Interlocked.CompareExchange(ref _outstandingInstanceConnections, 0, 0) > 0)
                    {
                        Thread.Sleep(TimeSpan.FromMilliseconds(20));
                        continue;
                    }

                    // if we are already fully connected and an instance still isn't chosen,
                    // then one simply doesn't exist, so we'll break immediately and throw a
                    // connection exception.
                    if (_state == MongoServerState.Connected)
                    {
                        break;
                    }

                    _state = MongoServerState.Connecting;
                    _connectionAttempt++;

                    foreach (var instance in _instances)
                    {
                        ConnectInstance(instance);
                    }
                }
            }

            ThrowConnectionException(readPreference);
        }
 // constructors
 /// <summary>
 /// Initializes a new instance of the <see cref="MongoServerInstance"/> class.
 /// </summary>
 /// <param name="server">The server.</param>
 /// <param name="address">The address.</param>
 internal MongoServerInstance(MongoServer server, MongoServerAddress address)
 {
     _server       = server;
     _address      = address;
     _sequentialId = Interlocked.Increment(ref __nextSequentialId);
     _state        = MongoServerState.Disconnected;
     _serverInfo   = new ServerInformation
     {
         MaxDocumentSize  = MongoDefaults.MaxDocumentSize,
         MaxMessageLength = MongoDefaults.MaxMessageLength,
         InstanceType     = MongoServerInstanceType.Unknown
     };
     _connectionPool          = new MongoConnectionPool(this);
     _pingTimeAggregator      = new PingTimeAggregator(5);
     _permanentlyDisconnected = false;
     // Console.WriteLine("MongoServerInstance[{0}]: {1}", sequentialId, address);
 }
 // constructors
 /// <summary>
 /// Initializes a new instance of the <see cref="MongoServerInstance"/> class.
 /// </summary>
 /// <param name="settings">The settings.</param>
 /// <param name="address">The address.</param>
 internal MongoServerInstance(MongoServerSettings settings, MongoServerAddress address)
 {
     _settings = settings;
     _address = address;
     _sequentialId = Interlocked.Increment(ref __nextSequentialId);
     _state = MongoServerState.Disconnected;
     _serverInfo = new ServerInformation
     {
         MaxDocumentSize = MongoDefaults.MaxDocumentSize,
         MaxMessageLength = MongoDefaults.MaxMessageLength,
         InstanceType = MongoServerInstanceType.Unknown
     };
     _connectionPool = new MongoConnectionPool(this);
     _pingTimeAggregator = new PingTimeAggregator(5);
     _permanentlyDisconnected = false;
     // Console.WriteLine("MongoServerInstance[{0}]: {1}", sequentialId, address);
 }
Beispiel #30
0
        private void ProcessInstanceStateChange(MongoServerInstance instance)
        {
            lock (_lock)
            {
                if (_instances.Contains(instance))
                {
                    if (instance.State == MongoServerState.Connected)
                    {
                        if (!IsValidInstance(instance))
                        {
                            RemoveInstance(instance);
                            return;
                        }

                        var myAddress = instance.IsMasterResult.MyAddress;
                        if (myAddress != null && instance.Address != myAddress)
                        {
                            if (!_instances.Any(x => x.Address == myAddress))
                            {
                                instance.Address = myAddress;
                            }
                            else
                            {
                                // we need to get rid of the duplicate.
                                RemoveInstance(instance);
                                return;
                            }
                        }

                        if (_state != MongoServerState.Disconnecting && _state != MongoServerState.Disconnected)
                        {
                            _connectedInstances.EnsureContains(instance);
                            ProcessConnectedInstanceStateChange(instance);
                        }
                    }
                    else
                    {
                        _connectedInstances.Remove(instance);
                        ProcessDisconnectedInstanceStateChange(instance);
                    }
                }

                _state = DetermineServerState(_state, _instances);
            }
        }
        /// <summary>
        /// Determines the state of the server.
        /// </summary>
        /// <param name="currentState">State of the current.</param>
        /// <param name="instances">The instances.</param>
        /// <returns>The server state.</returns>
        protected override MongoServerState DetermineServerState(MongoServerState currentState, IEnumerable <MongoServerInstance> instances)
        {
            if (!instances.Any())
            {
                return(MongoServerState.Disconnected);
            }

            // the order of the tests is significant
            // and resolves ambiguities when more than one state might match
            if (currentState == MongoServerState.Disconnecting)
            {
                if (instances.All(i => i.State == MongoServerState.Disconnected))
                {
                    return(MongoServerState.Disconnected);
                }
            }
            else
            {
                if (instances.All(i => i.State == MongoServerState.Disconnected))
                {
                    return(MongoServerState.Disconnected);
                }
                else if (instances.All(i => i.State == MongoServerState.Connected))
                {
                    return(MongoServerState.Connected);
                }
                else if (instances.Any(i => i.State == MongoServerState.Connecting))
                {
                    return(MongoServerState.Connecting);
                }
                else if (instances.Any(i => i.State == MongoServerState.Unknown))
                {
                    return(MongoServerState.Unknown);
                }
                else if (instances.Any(i => i.State == MongoServerState.Connected))
                {
                    return(MongoServerState.ConnectedToSubset);
                }

                throw new MongoInternalException("Unexpected server instance states.");
            }

            return(currentState);
        }
        /// <summary>
        /// Determines the state of the server.
        /// </summary>
        /// <param name="currentState">State of the current.</param>
        /// <param name="instances">The instances.</param>
        /// <returns>The server state.</returns>
        protected override MongoServerState DetermineServerState(MongoServerState currentState, IEnumerable<MongoServerInstance> instances)
        {
            if (!instances.Any())
            {
                return MongoServerState.Disconnected;
            }

            // the order of the tests is significant
            // and resolves ambiguities when more than one state might match
            if (currentState == MongoServerState.Disconnecting)
            {
                if (instances.All(i => i.State == MongoServerState.Disconnected))
                {
                    return MongoServerState.Disconnected;
                }
            }
            else
            {
                if (instances.All(i => i.State == MongoServerState.Disconnected))
                {
                    return MongoServerState.Disconnected;
                }
                else if (instances.All(i => i.State == MongoServerState.Connected))
                {
                    return MongoServerState.Connected;
                }
                else if (instances.Any(i => i.State == MongoServerState.Connecting))
                {
                    return MongoServerState.Connecting;
                }
                else if (instances.Any(i => i.State == MongoServerState.Unknown))
                {
                    return MongoServerState.Unknown;
                }
                else if (instances.Any(i => i.State == MongoServerState.Connected))
                {
                    return MongoServerState.ConnectedToSubset;
                }

                throw new MongoInternalException("Unexpected server instance states.");
            }

            return currentState;
        }
Beispiel #33
0
 /// <summary>
 /// Disconnects from the server. Normally there is no need to call this method so
 /// you should be sure to have a good reason to call it.
 /// </summary>
 public virtual void Disconnect()
 {
     // normally called from a connection when there is a SocketException
     // but anyone can call it if they want to close all sockets to the server
     lock (serverLock) {
         if (state == MongoServerState.Connected)
         {
             primaryConnectionPool.Close();
             primaryConnectionPool = null;
             if (secondaryConnectionPools != null)
             {
                 foreach (var secondaryConnectionPool in secondaryConnectionPools)
                 {
                     secondaryConnectionPool.Close();
                 }
                 secondaryConnectionPools = null;
             }
             state = MongoServerState.Disconnected;
         }
     }
 }
        /// <summary>
        /// Ensures that an instance with the address exists.
        /// </summary>
        /// <param name="address">The address.</param>
        protected void EnsureInstanceWithAddress(MongoServerAddress address)
        {
            if (address == null)
            {
                throw new ArgumentNullException("address");
            }

            lock (_lock)
            {
                if (!_instances.Any(x => x.Address == address))
                {
                    var instance = new MongoServerInstance(_server, address);
                    AddInstance(instance);
                    if (_state != MongoServerState.Disconnecting && _state != MongoServerState.Disconnected)
                    {
                        _state = MongoServerState.Connecting;
                        ConnectInstance(instance);
                    }
                }
            }
        }
        /// <summary>
        /// Sets the state.
        /// </summary>
        /// <param name="state">The state.</param>
        internal void SetState(MongoServerState state)
        {
            lock (_serverInstanceLock)
            {
                if (_state == state)
                {
                    return;
                }

                _state = state;
            }

            OnStateChanged();
        }
        internal void Connect(
            bool slaveOk
        ) {
            if (state != MongoServerState.Disconnected) {
                var message = string.Format("MongoServerInstance.Connect can only be called when state is Disconnected, not when state is {0}.", state);
                throw new InvalidOperationException(message);
            }

            State = MongoServerState.Connecting;
            connectException = null;
            try {
                endPoint = address.ToIPEndPoint(server.Settings.AddressFamily);

                var connectionPool = new MongoConnectionPool(this);
                try {
                    var connection = connectionPool.AcquireConnection(null);
                    try {
                        try {
                            var isMasterCommand = new CommandDocument("ismaster", 1);
                            isMasterResult = connection.RunCommand("admin.$cmd", QueryFlags.SlaveOk, isMasterCommand);
                        } catch (MongoCommandException ex) {
                            isMasterResult = ex.CommandResult;
                            throw;
                        }

                        isPrimary = isMasterResult.Response["ismaster", false].ToBoolean();
                        isSecondary = isMasterResult.Response["secondary", false].ToBoolean();
                        isPassive = isMasterResult.Response["passive", false].ToBoolean();
                        isArbiter = isMasterResult.Response["arbiterOnly", false].ToBoolean();
                        if (!isPrimary && !slaveOk) {
                            throw new MongoConnectionException("Server is not a primary and SlaveOk is false.");
                        }

                        maxDocumentSize = isMasterResult.Response["maxBsonObjectSize", MongoDefaults.MaxDocumentSize].ToInt32();
                        maxMessageLength = Math.Max(MongoDefaults.MaxMessageLength, maxDocumentSize + 1024); // derived from maxDocumentSize

                        var buildInfoCommand = new CommandDocument("buildinfo", 1);
                        var buildInfoResult = connection.RunCommand("admin.$cmd", QueryFlags.SlaveOk, buildInfoCommand);
                        buildInfo = new MongoServerBuildInfo(
                            buildInfoResult.Response["bits"].ToInt32(), // bits
                            buildInfoResult.Response["gitVersion"].AsString, // gitVersion
                            buildInfoResult.Response["sysInfo"].AsString, // sysInfo
                            buildInfoResult.Response["version"].AsString // versionString
                        );
                    } finally {
                        connectionPool.ReleaseConnection(connection);
                    }
                } catch {
                    connectionPool.Close();
                    throw;
                }

                State = MongoServerState.Connected;
                this.connectionPool = connectionPool;
            } catch (Exception ex) {
                State = MongoServerState.Disconnected;
                connectException = ex;
                throw;
            }
        }
 /// <summary>
 /// Determines the state of the server.
 /// </summary>
 /// <param name="currentState">State of the current.</param>
 /// <param name="instances">The instances.</param>
 /// <returns>The state of the server.</returns>
 protected abstract MongoServerState DetermineServerState(MongoServerState currentState, IEnumerable<MongoServerInstance> instances);
        /// <summary>
        /// Connects to the instances 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)
        {
            var timeoutAt = DateTime.UtcNow + timeout;
            while (DateTime.UtcNow < timeoutAt)
            {
                if (ChooseServerInstance(_connectedInstances, readPreference) != null)
                {
                    return;
                }

                if (Interlocked.CompareExchange(ref _outstandingInstanceConnections, 0, 0) > 0)
                {
                    Thread.Sleep(TimeSpan.FromMilliseconds(20));
                    continue;
                }

                lock (_lock)
                {
                    // test this again (kinda like the double lock check pattern).  This value may
                    // be different and we don't want to issue another round of connects needlessly.
                    if (Interlocked.CompareExchange(ref _outstandingInstanceConnections, 0, 0) > 0)
                    {
                        Thread.Sleep(TimeSpan.FromMilliseconds(20));
                        continue;
                    }

                    // if we are already fully connected and an instance still isn't chosen,
                    // then one simply doesn't exist, so we'll break immediately and throw a
                    // connection exception.
                    if (_state == MongoServerState.Connected)
                    {
                        break;
                    }

                    _state = MongoServerState.Connecting;
                    _connectionAttempt++;

                    foreach (var instance in _instances)
                    {
                        ConnectInstance(instance);
                    }
                }
            }

            ThrowConnectionException(readPreference);
        }
        /// <summary>
        /// Disconnects this instance.
        /// </summary>
        internal void Disconnect()
        {
            // Console.WriteLine("MongoServerInstance[{0}]: Disconnect called.", sequentialId);
            lock (_serverInstanceLock)
            {
                if (_stateVerificationTimer != null)
                {
                    _stateVerificationTimer.Dispose();
                    _stateVerificationTimer = null;
                }

                if (_state == MongoServerState.Disconnecting || _state == MongoServerState.Disconnected)
                {
                    return;
                }

                // set the state here because SetState raises an event that should not be raised while holding a lock
                _state = MongoServerState.Disconnecting;
            }

            // we know for certain state has just changed.
            OnStateChanged(); 

            try
            {
                _connectionPool.Clear();
            }
            finally
            {
                SetState(MongoServerState.Disconnected);
            }
        }
        /// <summary>
        /// Determines the state of the server.
        /// </summary>
        /// <param name="currentState">State of the current.</param>
        /// <param name="instances">The instances.</param>
        /// <returns>The server state.</returns>
        protected override MongoServerState DetermineServerState(MongoServerState currentState, IEnumerable<MongoServerInstance> instances)
        {
            if (!instances.Any())
            {
                return MongoServerState.Disconnected;
            }

            // the order of the tests is significant
            // and resolves ambiguities when more than one state might match
            if (currentState == MongoServerState.Disconnected)
            {
                return MongoServerState.Disconnected;
            }
            else if (currentState == MongoServerState.Disconnecting)
            {
                if (instances.All(i => i.State == MongoServerState.Disconnected))
                {
                    return MongoServerState.Disconnected;
                }

                return MongoServerState.Disconnecting;
            }
            else
            {
                if (instances.Any(i => i.State == MongoServerState.Connected))
                {
                    return MongoServerState.Connected;
                }

                return MongoServerState.Connecting;
            }
        }
        private void ProcessInstanceStateChange(MongoServerInstance instance)
        {
            lock (_lock)
            {
                if (_instances.Contains(instance))
                {
                    if (instance.State == MongoServerState.Connected)
                    {
                        if (!IsValidInstance(instance))
                        {
                            RemoveInstance(instance);
                            return;
                        }

                        if (instance.Address != instance.IsMasterResult.MyAddress)
                        {
                            if (!_instances.Any(x => x.Address == instance.IsMasterResult.MyAddress))
                            {
                                instance.Address = instance.IsMasterResult.MyAddress;
                            }
                            else
                            {
                                // we need to get rid of the duplicate.
                                RemoveInstance(instance);
                                return;
                            }
                        }

                        if (_state != MongoServerState.Disconnecting && _state != MongoServerState.Disconnected)
                        {
                            _connectedInstances.EnsureContains(instance);
                            ProcessConnectedInstanceStateChange(instance);
                        }
                    }
                    else
                    {
                        _connectedInstances.Remove(instance);
                    }
                }

                _state = DetermineServerState(_state, _instances);
            }
        }
        private void SetState(MongoServerState state, ServerInformation serverInfo)
        {
            var currentServerInfo = Interlocked.CompareExchange(ref _stateInfo, null, null);

            bool raiseChangedEvent = false;
            lock (_stateLock)
            {
                if (_state != state)
                {
                    _state = state;
                    raiseChangedEvent = true;
                }

                if (state == MongoServerState.Disconnected)
                {
                    _connectionPool.Clear();
                }

                if (currentServerInfo != serverInfo && currentServerInfo.IsDifferentFrom(serverInfo))
                {
                    Interlocked.Exchange(ref _stateInfo, serverInfo);
                    raiseChangedEvent = true;
                }
            }

            if (raiseChangedEvent)
            {
                OnStateChanged();
            }
        }
 // private methods
 private void EnsureInstanceManager(TimeSpan timeout)
 {
     if (_serverProxy == null)
     {
         lock (_lock)
         {
             if (_serverProxy == null)
             {
                 _connectionAttempt++;
                 _state = MongoServerState.Connecting;
                 Discover(timeout);
             }
         }
     }
 }
 /// <summary>
 /// Connects to the instances 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)
 {
     try
     {
         EnsureInstanceManager(timeout);
     }
     catch
     {
         _state = MongoServerState.Disconnected;
         throw;
     }
     _serverProxy.Connect(timeout, readPreference);
 }
 private void SetState(MongoServerState state)
 {
     lock (_lock)
     {
         _state = state;
     }
 }
 internal void SetState(MongoServerState state)
 {
     lock (_serverInstanceLock)
     {
         if (_state != state)
         {
             _state = state;
             OnStateChanged();
         }
     }
 }
 internal void SetState(
     MongoServerState state,
     bool isPrimary,
     bool isSecondary,
     bool isPassive,
     bool isArbiter)
 {
     lock (_serverInstanceLock)
     {
         if (_state != state || _isPrimary != isPrimary || _isSecondary != isSecondary || _isPassive != isPassive || _isArbiter != isArbiter)
         {
             _state = state;
             _isPrimary = isPrimary;
             _isSecondary = isSecondary;
             _isPassive = isPassive;
             _isArbiter = isArbiter;
             OnStateChanged();
         }
     }
 }
 // constructors
 /// <summary>
 /// Initializes a new instance of the <see cref="DiscoveringMongoServerProxy"/> class.
 /// </summary>
 /// <param name="settings">The settings.</param>
 public DiscoveringMongoServerProxy(MongoServerSettings settings)
 {
     _state     = MongoServerState.Disconnected;
     _settings  = settings;
     _instances = settings.Servers.Select(a => new MongoServerInstance(settings, a)).ToList().AsReadOnly();
 }
        private void SetState(
            MongoServerState state,
            MongoServerInstanceType instanceType,
            bool isPrimary,
            bool isSecondary,
            bool isPassive,
            bool isArbiter,
            ReplicaSetInformation replicaSetInformation)
        {
            lock (_serverInstanceLock)
            {
                bool changed = false;
                bool replicaSetInformationIsDifferent = false;
                if ((_replicaSetInformation == null && replicaSetInformation != null) || (_replicaSetInformation != replicaSetInformation))
                {
                    replicaSetInformationIsDifferent = true;
                }
                if (_state != state || _instanceType != instanceType || replicaSetInformationIsDifferent || _isPrimary != isPrimary || _isSecondary != isSecondary || _isPassive != isPassive || _isArbiter != isArbiter)
                {
                    changed = true;
                    _state = state;
                    _instanceType = instanceType;
                    if (_replicaSetInformation != replicaSetInformation)
                    {
                        _replicaSetInformation = replicaSetInformation;
                    }
                    _isPrimary = isPrimary;
                    _isSecondary = isSecondary;
                    _isPassive = isPassive;
                    _isArbiter = isArbiter;
                }

                if (changed)
                {
                    if (_state == MongoServerState.Disconnected)
                    {
                        _connectionPool.Clear();
                    }
                    OnStateChanged();
                }
            }
        }
 /// <summary>
 /// Sets the state.
 /// </summary>
 /// <param name="state">The state.</param>
 internal void SetState(MongoServerState state)
 {
     lock(_serverInstanceLock)
     {
         SetState(state, _instanceType, _isPrimary, _isSecondary, _isPassive, _isArbiter, _replicaSetInformation);
     }
 }
        /// <summary>
        /// Connects this instance.
        /// </summary>
        internal void Connect()
        {
            // Console.WriteLine("MongoServerInstance[{0}]: Connect() called.", sequentialId);
            lock (_serverInstanceLock)
            {
                if (_permanentlyDisconnected || _state == MongoServerState.Connecting || _state == MongoServerState.Connected)
                {
                    return;
                }

                _connectException = null;

                // set the state manually here because SetState raises an event that shouldn't be raised
                // while holding a lock.
                _state = MongoServerState.Connecting;
            }

            // We know for certain that the state just changed
            OnStateChanged();

            try
            {
                var connection = _connectionPool.AcquireConnection(null, null);
                try
                {
                    Ping(connection);
                    LookupServerInformation(connection);
                }
                finally
                {
                    _connectionPool.ReleaseConnection(connection);
                }
                SetState(MongoServerState.Connected);
            }
            catch (Exception ex)
            {
                lock (_serverInstanceLock)
                {
                    _connectException = ex;
                }
                _connectionPool.Clear();
                Interlocked.Exchange(ref _connectException, ex);
                SetState(MongoServerState.Disconnected);
                throw;
            }
            finally
            {
                lock (_serverInstanceLock)
                {
                    if (_stateVerificationTimer == null)
                    {
                        _stateVerificationTimer = new Timer(o => StateVerificationTimerCallback(), null, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10));
                    }
                }
            }
        }
Beispiel #52
0
 /// <summary>
 /// Determines the state of the server.
 /// </summary>
 /// <param name="currentState">State of the current.</param>
 /// <param name="instances">The instances.</param>
 /// <returns>The state of the server.</returns>
 protected abstract MongoServerState DetermineServerState(MongoServerState currentState, IEnumerable <MongoServerInstance> instances);
        /// <summary>
        /// Disconnects the server.
        /// </summary>
        public void Disconnect()
        {
            lock (_lock)
            {
                if (_state == MongoServerState.Disconnected || _state == MongoServerState.Disconnecting)
                {
                    return;
                }

                _state = MongoServerState.Disconnecting;
                try
                {
                    _connectedInstances.Clear();
                    foreach (var instance in _instances)
                    {
                        try
                        {
                            instance.Disconnect();
                        }
                        catch { } // ignore disconnection errors
                    }
                }
                finally
                {
                    _state = MongoServerState.Disconnected;
                }
            }
        }
        /// <remarks>This method must be called outside of a lock.</remarks>
        private void SetState(MongoServerState newState, ServerInformation newServerInfo)
        {
            bool raiseChangedEvent = false;
            lock (_serverInstanceLock)
            {
                if (_state != newState)
                {
                    _state = newState;
                    raiseChangedEvent = true;
                }

                if (newState == MongoServerState.Disconnected)
                {
                    _connectionPool.Clear();
                }

                if (_serverInfo != newServerInfo && _serverInfo.IsDifferentFrom(newServerInfo))
                {
                    _serverInfo = newServerInfo;
                    raiseChangedEvent = true;
                }
            }

            if (raiseChangedEvent)
            {
                OnStateChanged();
            }
        }
        /// <summary>
        /// Ensures that an instance with the address exists.
        /// </summary>
        /// <param name="address">The address.</param>
        protected void EnsureInstanceWithAddress(MongoServerAddress address)
        {
            if (address == null)
            {
                throw new ArgumentNullException("address");
            }

            lock (_lock)
            {
                if (!_instances.Any(x => x.Address == address))
                {
                    var instance = new MongoServerInstance(_server, address);
                    AddInstance(instance);
                    if (_state != MongoServerState.Disconnecting && _state != MongoServerState.Disconnected)
                    {
                        _state = MongoServerState.Connecting;
                        ConnectInstance(instance);
                    }
                }
            }
        }
 internal void Disconnect() {
     if (state != MongoServerState.Disconnected) {
         try {
             // if we fail during Connect the connectionPool field will still be null
             if (connectionPool != null) {
                 connectionPool.Close();
                 connectionPool = null;
             }
         } finally {
             State = MongoServerState.Disconnected;
         }
     }
 }
 // constructors
 /// <summary>
 /// Initializes a new instance of the <see cref="MongoServerInstance"/> class.
 /// </summary>
 /// <param name="server">The server.</param>
 /// <param name="address">The address.</param>
 internal MongoServerInstance(MongoServer server, MongoServerAddress address)
 {
     _server = server;
     _address = address;
     _sequentialId = Interlocked.Increment(ref __nextSequentialId);
     _maxDocumentSize = MongoDefaults.MaxDocumentSize;
     _maxMessageLength = MongoDefaults.MaxMessageLength;
     _state = MongoServerState.Disconnected;
     _instanceType = MongoServerInstanceType.Unknown;
     _connectionPool = new MongoConnectionPool(this);
     _pingTimeAggregator = new PingTimeAggregator(5);
     _stateVerificationTimer = new Timer(o => StateVerificationTimerCallback(), null, TimeSpan.Zero, TimeSpan.FromSeconds(10));
     // Console.WriteLine("MongoServerInstance[{0}]: {1}", sequentialId, address);
 }
 /// <summary>
 /// Sets the state.
 /// </summary>
 /// <param name="state">The state.</param>
 internal void SetState(MongoServerState state)
 {
     SetState(state, Interlocked.CompareExchange(ref _stateInfo, null, null));
 }