/// <summary>
 /// Initializes a new instance of the <see cref="DirectMongoServerProxy"/> class.
 /// </summary>
 /// <param name="sequentialId">The sequential id.</param>
 /// <param name="serverSettings">The server settings.</param>
 /// <param name="instance">The instance.</param>
 /// <param name="connectionAttempt">The connection attempt.</param>
 public DirectMongoServerProxy(int sequentialId, MongoServerProxySettings serverSettings, MongoServerInstance instance, int connectionAttempt)
 {
     _sequentialId = sequentialId;
     _settings = serverSettings;
     _instance = instance;
     _connectionAttempt = connectionAttempt;
 }
        private void ProcessConnectedPrimaryStateChange(MongoServerInstance instance)
        {
            Interlocked.Exchange(ref _primary, instance);
            Interlocked.CompareExchange(ref _replicaSetName, instance.ReplicaSetInformation.Name, null);

            var members       = instance.ReplicaSetInformation.Members;
            var configVersion = instance.ReplicaSetInformation.ConfigVersion;

            if (members.Any() && (!configVersion.HasValue || !_configVersion.HasValue ||
                                  configVersion.Value > _configVersion.Value))
            {
                if (configVersion.HasValue)
                {
                    _configVersion = configVersion.Value;
                }
                // remove instances the primary doesn't know about and add instances we don't know about
                MakeInstancesMatchAddresses(members);
            }
            var instancesMarkedPrimary = Instances.Where(x => x.IsPrimary);

            foreach (var otherInstance in instancesMarkedPrimary)
            {
                if (!otherInstance.Address.Equals(instance.Address))
                {
                    otherInstance.UnsetPrimary();
                }
            }
        }
Beispiel #3
0
        protected BsonBinaryReaderSettings GetNodeAdjustedReaderSettings(MongoServerInstance node)
        {
            var readerSettings = _readerSettings.Clone();

            readerSettings.MaxDocumentSize = node.MaxDocumentSize;
            return(readerSettings);
        }
Beispiel #4
0
        protected BsonBinaryWriterSettings GetNodeAdjustedWriterSettings(MongoServerInstance node)
        {
            var writerSettings = _writerSettings.Clone();

            writerSettings.MaxDocumentSize = node.MaxDocumentSize;
            return(writerSettings);
        }
 public void Setup()
 {
     _server   = Configuration.TestServer;
     _primary  = Configuration.TestServer.Primary;
     _database = Configuration.TestDatabase;
     _database.Drop();
 }
Beispiel #6
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;
        }
 public void TestFixtureSetup()
 {
     _server        = Configuration.TestServer;
     _adminDatabase = _server.GetDatabase("admin");
     _database      = Configuration.TestDatabase;
     _primary       = _server.Primary;
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="MongoGridFSFileInfo"/> class.
        /// </summary>
        /// <param name="server">The server.</param>
        /// <param name="serverInstance">The server instance.</param>
        /// <param name="databaseName">Name of the database.</param>
        /// <param name="gridFSSettings">The GridFS settings.</param>
        /// <param name="remoteFileName">The remote file name.</param>
        /// <param name="createOptions">The create options.</param>
        public MongoGridFSFileInfo(
            MongoServer server,
            MongoServerInstance serverInstance,
            string databaseName,
            MongoGridFSSettings gridFSSettings,
            string remoteFileName,
            MongoGridFSCreateOptions createOptions)
            : this(server, serverInstance, databaseName, gridFSSettings)
        {
            if (remoteFileName == null)
            {
                throw new ArgumentNullException("remoteFileName");
            }
            if (createOptions == null)
            {
                throw new ArgumentNullException("createOptions");
            }

            _aliases     = createOptions.Aliases;
            _chunkSize   = (createOptions.ChunkSize == 0) ? gridFSSettings.ChunkSize : createOptions.ChunkSize;
            _contentType = createOptions.ContentType;
            _id          = createOptions.Id;
            _metadata    = createOptions.Metadata;
            _name        = remoteFileName;
            _uploadDate  = createOptions.UploadDate;
            _cached      = true; // prevent values from being overwritten by automatic Refresh
        }
        private void ProcessFirstResponse(ConnectResponse response)
        {
            var isMasterResponse = response.IsMasterResult.Response;

            // first response has to match replica set name in settings (if any)
            var replicaSetName = isMasterResponse["setName"].AsString;

            if (_server.Settings.ReplicaSetName != null && replicaSetName != _server.Settings.ReplicaSetName)
            {
                var message = string.Format(
                    "Server at address '{0}' is a member of replica set '{1}' and not '{2}'.",
                    response.ServerInstance.Address, replicaSetName, _server.Settings.ReplicaSetName);
                throw new MongoConnectionException(message);
            }
            _server.ReplicaSetName = replicaSetName;

            // find all valid addresses
            var validAddresses = new HashSet <MongoServerAddress>();

            if (isMasterResponse.Contains("hosts"))
            {
                foreach (string address in isMasterResponse["hosts"].AsBsonArray)
                {
                    validAddresses.Add(MongoServerAddress.Parse(address));
                }
            }
            if (isMasterResponse.Contains("passives"))
            {
                foreach (string address in isMasterResponse["passives"].AsBsonArray)
                {
                    validAddresses.Add(MongoServerAddress.Parse(address));
                }
            }
            if (isMasterResponse.Contains("arbiters"))
            {
                foreach (string address in isMasterResponse["arbiters"].AsBsonArray)
                {
                    validAddresses.Add(MongoServerAddress.Parse(address));
                }
            }

            // remove server instances created from the seed list that turn out to be invalid
            var invalidInstances = _server.Instances.Where(i => !validAddresses.Contains(i.Address)).ToArray(); // force evaluation

            foreach (var invalidInstance in invalidInstances)
            {
                _server.RemoveInstance(invalidInstance);
            }

            // add any server instances that were missing from the seed list
            foreach (var address in validAddresses)
            {
                if (!_server.Instances.Any(i => i.Address == address))
                {
                    var missingInstance = new MongoServerInstance(_server, address);
                    _server.AddInstance(missingInstance);
                    QueueConnect(missingInstance);
                }
            }
        }
        private void CreateActualProxy(MongoServerInstance instance, BlockingQueue <MongoServerInstance> connectionQueue)
        {
            lock (_lock)
            {
                if (instance.InstanceType == MongoServerInstanceType.ReplicaSetMember)
                {
                    _serverProxy = new ReplicaSetMongoServerProxy(_settings, _instances, connectionQueue, _connectionAttempt);
                }
                else if (instance.InstanceType == MongoServerInstanceType.ShardRouter)
                {
                    _serverProxy = new ShardedMongoServerProxy(_settings, _instances, connectionQueue, _connectionAttempt);
                }
                else if (instance.InstanceType == MongoServerInstanceType.StandAlone)
                {
                    var otherInstances = _instances.Where(x => x != instance).ToList();
                    foreach (var otherInstance in otherInstances)
                    {
                        otherInstance.Disconnect();
                    }

                    _serverProxy = new DirectMongoServerProxy(_settings, instance, _connectionAttempt);
                }
                else
                {
                    throw new MongoConnectionException("The type of servers in the host list could not be determined.");
                }
            }
        }
        /// <summary>
        ///     根据路径字符获得服务器
        /// </summary>
        /// <param name="strObjTag">[Tag:Connection/Host@Port/DBName/Collection]</param>
        /// <returns></returns>
        public static MongoServer GetMongoServerBySvrPath(String strObjTag)
        {
            String strSvrPath = SystemManager.GetTagData(strObjTag);

            String[] strPath = strSvrPath.Split("/".ToCharArray());
            if (strPath.Length == 1)
            {
                //[Tag:Connection
                if (_mongoConnSvrLst.ContainsKey(strPath[0]))
                {
                    return(_mongoConnSvrLst[strPath[0]]);
                }
            }
            if (strPath.Length > (int)PathLv.InstanceLv)
            {
                if (strPath[0] == strPath[1])
                {
                    //[Tag:Connection/Connection/DBName/Collection]
                    return(_mongoConnSvrLst[strPath[0]]);
                }
                //[Tag:Connection/Host@Port/DBName/Collection]
                String strInstKey = String.Empty;
                strInstKey = strPath[(int)PathLv.ConnectionLv] + "/" + strPath[(int)PathLv.InstanceLv];
                if (_mongoInstanceLst.ContainsKey(strInstKey))
                {
                    MongoServerInstance mongoInstance = _mongoInstanceLst[strInstKey];
                    return(MongoServer.Create(mongoInstance.Settings));
                }
            }
            return(null);
        }
Beispiel #12
0
        /// <summary>
        /// Ensures that the instance is in the collection.
        /// </summary>
        /// <param name="instance">The instance.</param>
        public void EnsureContains(MongoServerInstance instance)
        {
            lock (_connectedInstancesLock)
            {
                if (_instanceLookup.ContainsKey(instance))
                {
                    return;
                }

                var node = new LinkedListNode <InstanceWithPingTime>(new InstanceWithPingTime
                {
                    Instance = instance,
                    CachedAveragePingTime = instance.AveragePingTime
                });

                if (_instances.Count == 0 || _instances.First.Value.CachedAveragePingTime > node.Value.CachedAveragePingTime)
                {
                    _instances.AddFirst(node);
                }
                else
                {
                    var current = _instances.First;

                    while (current.Next != null && node.Value.CachedAveragePingTime > current.Next.Value.CachedAveragePingTime)
                    {
                        current = current.Next;
                    }

                    _instances.AddAfter(current, node);
                }

                _instanceLookup.Add(instance, node);
                instance.AveragePingTimeChanged += InstanceAveragePingTimeChanged;
            }
        }
        // public methods
        public Exception ToWriteConcernException(MongoServerInstance serverInstance, BulkWriteException bulkWriteException)
        {
            var writeConcernResult = ToWriteConcernResult(bulkWriteException.Result, bulkWriteException);

            writeConcernResult.ServerInstance = serverInstance;

            var exception = ExceptionMapper.Map(writeConcernResult.Response);

            if (exception == null)
            {
                exception = ExceptionMapper.Map(writeConcernResult);
            }
            if (exception == null)
            {
                exception = new WriteConcernException(bulkWriteException.Message, writeConcernResult);
            }

            var writeConcernException = exception as WriteConcernException;

            if (writeConcernException != null)
            {
                writeConcernException.Data["results"] = new List <WriteConcernResult>(new[] { writeConcernResult });
            }

            return(exception); // usually a WriteConcernException unless ExceptionMapper chose a different type
        }
Beispiel #14
0
 public void Setup()
 {
     _server   = LegacyTestConfiguration.Server;
     _primary  = LegacyTestConfiguration.Server.Primary;
     _database = LegacyTestConfiguration.Database;
     _database.Drop();
 }
Beispiel #15
0
        /// <summary>
        ///     Export Collection
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ExportCollectionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!MongoPathCheck())
            {
                return;
            }
            var MongoImportExport        = new MongodbDosCommand.StruImportExport();
            MongoServerInstance Mongosrv = SystemManager.GetCurrentServer().Instance;

            MongoImportExport.HostAddr       = Mongosrv.Address.Host;
            MongoImportExport.Port           = Mongosrv.Address.Port;
            MongoImportExport.DBName         = SystemManager.GetCurrentDataBase().Name;
            MongoImportExport.CollectionName = SystemManager.GetCurrentCollection().Name;
            var dumpFile = new SaveFileDialog {
                Filter = MongoDbHelper.TxtFilter, CheckFileExists = false
            };

            //if the file not exist,the server will create a new one
            if (dumpFile.ShowDialog() == DialogResult.OK)
            {
                MongoImportExport.FileName = dumpFile.FileName;
            }
            MongoImportExport.Direct = MongodbDosCommand.ImprotExport.Export;
            String DosCommand = MongodbDosCommand.GetMongoImportExportCommandLine(MongoImportExport);

            RunCommand(DosCommand);
        }
        // constructors
        public FailPoint(string name, MongoServer server, MongoServerInstance serverInstance)
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }
            if (server == null)
            {
                throw new ArgumentNullException("server");
            }
            if (serverInstance == null)
            {
                throw new ArgumentNullException("serverInstance");
            }

            if (server.RequestServerInstance != null)
            {
                throw new InvalidOperationException("FailPoint cannot be used when you are already in a RequestStart.");
            }

            _name           = name;
            _server         = server;
            _serverInstance = serverInstance;
            _adminDatabase  = server.GetDatabase("admin");
            _request        = server.RequestStart(serverInstance);
        }
 /// <summary>
 /// Indicates if the instance exists in the chooser.
 /// </summary>
 /// <param name="instance">The instance.</param>
 /// <returns>
 ///   <c>true</c> if [contains] [the specified instance]; otherwise, <c>false</c>.
 /// </returns>
 public bool Contains(MongoServerInstance instance)
 {
     lock (_lock)
     {
         return _instances.Contains(instance);
     }
 }
        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;
        }
Beispiel #19
0
 public void OneTimeSetUp()
 {
     _server   = LegacyTestConfiguration.Server;
     _primary  = LegacyTestConfiguration.Server.Primary;
     _database = LegacyTestConfiguration.Database;
     // TODO: DropDatabase
     //_database.Drop();
 }
Beispiel #20
0
 // constructors
 internal MongoConnection(MongoConnectionPool connectionPool)
 {
     this.serverInstance = connectionPool.ServerInstance;
     this.connectionPool = connectionPool;
     this.generationId   = connectionPool.GenerationId;
     this.createdAt      = DateTime.UtcNow;
     this.state          = MongoConnectionState.Initial;
 }
 // constructors
 internal MongoConnection(MongoConnectionPool connectionPool)
 {
     _serverInstance = connectionPool.ServerInstance;
     _connectionPool = connectionPool;
     _generationId   = connectionPool.GenerationId;
     _createdAt      = DateTime.UtcNow;
     _state          = MongoConnectionState.Initial;
 }
 public void TestFixtureSetUp()
 {
     _primary        = Configuration.TestServer.Primary;
     _collection     = Configuration.TestCollection;
     _collectionName = Configuration.TestCollection.Name;
     _database       = Configuration.TestDatabase;
     _databaseName   = Configuration.TestDatabase.Name;
 }
Beispiel #23
0
 // private methods
 private void AddInstance(MongoServerInstance instance)
 {
     lock (_lock)
     {
         _instances.Add(instance);
         instance.StateChanged += InstanceStateChanged;
         ProcessInstanceStateChange(instance);
     }
 }
        internal MongoConnectionPool(
            MongoServerInstance serverInstance
        ) {
            this.server = serverInstance.Server;
            this.serverInstance = serverInstance;

            poolSize = 0;
            timer = new Timer(TimerCallback, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(10));
        }
Beispiel #25
0
 public MongoDatabaseTests()
 {
     _server        = LegacyTestConfiguration.Server;
     _primary       = LegacyTestConfiguration.Server.Primary;
     _database      = LegacyTestConfiguration.Database;
     _adminDatabase = _server.GetDatabase("admin");
     // TODO: DropDatabase
     //_database.Drop();
 }
Beispiel #26
0
        internal MongoConnectionPool(
            MongoServerInstance serverInstance
            )
        {
            this.server         = serverInstance.Server;
            this.serverInstance = serverInstance;

            poolSize = 0;
            timer    = new Timer(TimerCallback, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(10));
        }
        private void ProcessConnectedSecondaryStateChange(MongoServerInstance instance)
        {
            var address = instance.ReplicaSetInformation.Primary;

            if (address != null)
            {
                // make sure the primary exists in the instance list
                EnsureInstanceWithAddress(address);
            }
        }
        // constructors
        internal MongoConnectionPool(MongoServerInstance serverInstance)
        {
            _server = serverInstance.Server;
            _serverInstance = serverInstance;
            _poolSize = 0;

            var dueTime = TimeSpan.FromSeconds(0);
            var period = TimeSpan.FromSeconds(10);
            _timer = new Timer(TimerCallback, null, dueTime, period);
        }
 /// <summary>
 /// Processes the connected instance state change.
 /// </summary>
 /// <param name="instance">The instance.</param>
 protected override void ProcessConnectedInstanceStateChange(MongoServerInstance instance)
 {
     if (instance.IsPrimary)
     {
         ProcessConnectedPrimaryStateChange(instance);
     }
     else
     {
         ProcessConnectedSecondaryStateChange(instance);
     }
 }
        // constructors
        internal MongoConnectionPool(MongoServerInstance serverInstance)
        {
            _server         = serverInstance.Server;
            _serverInstance = serverInstance;
            _poolSize       = 0;

            var dueTime = TimeSpan.FromSeconds(0);
            var period  = TimeSpan.FromSeconds(10);

            _timer = new Timer(TimerCallback, null, dueTime, period);
        }
        private void QueueConnect(MongoServerInstance serverInstance)
        {
            var args = new ConnectArgs
            {
                ServerInstance = serverInstance,
                ResponseQueue  = _responseQueue
            };

            ThreadPool.QueueUserWorkItem(ConnectWorkItem, args);
            _connects.Add(args);
        }
 // constructors
 public MongoGridFSFileInfoSerializer(
     MongoServer server,
     MongoServerInstance serverInstance,
     string databaseName,
     MongoGridFSSettings gridFSSettings)
 {
     _server         = server;
     _serverInstance = serverInstance;
     _databaseName   = databaseName;
     _gridFSSettings = gridFSSettings;
 }
Beispiel #33
0
 private void RemoveInstance(MongoServerInstance instance)
 {
     _connectedInstances.Remove(instance);
     lock (_lock)
     {
         _instances.Remove(instance);
         instance.StateChanged -= InstanceStateChanged;
         instance.DisconnectPermanently();
         ProcessInstanceStateChange(instance);
     }
 }
 /// <summary>
 /// Gets a list of primary and secondary instances.
 /// </summary>
 /// <param name="primary">The current primary.</param>
 /// <returns>The list of primary and secondary instances.</returns>
 public List<InstanceWithPingTime> GetPrimaryAndSecondaries(MongoServerInstance primary)
 {
     lock (_connectedInstancesLock)
     {
         // note: make copies of InstanceWithPingTime values because they can change after we return
         return _instances
             .Where(x => x.Instance == primary || x.Instance.IsSecondary)
             .Select(x => new InstanceWithPingTime { Instance = x.Instance, CachedAveragePingTime = x.CachedAveragePingTime })
             .ToList();
     }
 }
        /// <summary>
        /// Determines whether the instance is a valid.  If not, the instance is removed.
        /// </summary>
        /// <param name="instance">The instance.</param>
        /// <returns>
        ///   <c>true</c> if the instance is valid; otherwise, <c>false</c>.
        /// </returns>
        protected override bool IsValidInstance(MongoServerInstance instance)
        {
            if (instance.InstanceType != MongoServerInstanceType.ReplicaSetMember)
            {
                return(false);
            }

            // read _replicaSetName in a thread-safe way
            var replicaSetName = Interlocked.CompareExchange(ref _replicaSetName, null, null);

            return(replicaSetName == null || replicaSetName == instance.ReplicaSetInformation.Name);
        }
        private void ProcessConnectedPrimaryStateChange(MongoServerInstance instance)
        {
            Interlocked.CompareExchange(ref _replicaSetName, instance.ReplicaSetInformation.Name, null);

            var members = instance.ReplicaSetInformation.Members;

            if (members.Any())
            {
                // remove instances the primary doesn't know about and add instances we don't know about
                MakeInstancesMatchAddresses(members);
            }
        }
        // constructors
        internal MongoConnectionPool(MongoServerInstance serverInstance)
        {
            _settings = serverInstance.Settings;
            _serverInstance = serverInstance;
            _poolSize = 0;

            _defaultAcquireConnectionOptions = new AcquireConnectionOptions
            {
                OkToAvoidWaitingByCreatingNewConnection = true,
                OkToExceedMaxConnectionPoolSize = false,
                OkToExceedWaitQueueSize = false,
                WaitQueueTimeout = _settings.WaitQueueTimeout
            };
        }
 // public methods
 /// <summary>
 /// Adds the specified instance.
 /// </summary>
 /// <param name="instance">The instance.</param>
 public void Add(MongoServerInstance instance)
 {
     lock (_lock)
     {
         var index = _instances.FindIndex(x => x.AveragePingTime >= instance.AveragePingTime);
         if (index == -1)
         {
             _instances.Add(instance);
         }
         else
         {
             _instances.Insert(index + 1, instance);
         }
         instance.AveragePingTimeChanged += InstanceAveragePingTimeChanged;
     }
 }
 /// <summary>
 /// Determines whether the instance is a valid.  If not, the instance is removed.
 /// </summary>
 /// <param name="instance">The instance.</param>
 /// <returns>
 ///   <c>true</c> if the instance is valid; otherwise, <c>false</c>.
 /// </returns>
 protected abstract bool IsValidInstance(MongoServerInstance instance);
 /// <summary>
 /// Determines whether the instance is a valid.  If not, the instance is removed.
 /// </summary>
 /// <param name="instance">The instance.</param>
 /// <returns>
 ///   <c>true</c> if the instance is valid; otherwise, <c>false</c>.
 /// </returns>
 protected override bool IsValidInstance(MongoServerInstance instance)
 {
     return instance.InstanceType == MongoServerInstanceType.ShardRouter;
 }
        /// <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);
                    }
                }
            }
        }
 // constructors
 /// <summary>
 /// Initializes a new instance of the <see cref="DirectMongoServerProxy"/> class.
 /// </summary>
 /// <param name="settings">The settings.</param>
 public DirectMongoServerProxy(MongoServerSettings settings)
 {
     _settings = settings;
     _instance = new MongoServerInstance(settings, settings.Servers.First());
 }
        private void ProcessInstanceStateChange(MongoServerInstance instance)
        {
            lock (_lock)
            {
                if (instance.State == MongoServerState.Connected && _instances.Contains(instance))
                {
                    if (!IsValidInstance(instance))
                    {
                        RemoveInstance(instance);
                        // TODO: log this...
                        return;
                    }

                    if (instance.IsMasterResult.MyAddress != null && instance.Address != instance.IsMasterResult.MyAddress)
                    {
                        // NOTE: if this gets set inside the MongoServerInstance, then there is a race condition that could cause
                        // the instance to get added more than once to the list because the changes occur under different locks.
                        // I don't like this and would rather it be in the MongoServerInstance, but haven't figured out how to do
                        // it yet.
                        // One solution is for every instance change to check to see if two instances exist in the list and remove
                        // the other one, as the current one is more up-to-date.
                        instance.Address = instance.IsMasterResult.MyAddress;
                    }

                    if (!_connectedInstances.Contains(instance))
                    {
                        _connectedInstances.Add(instance);
                    }

                    ProcessConnectedInstanceStateChange(instance);
                }
                else
                {
                    _connectedInstances.Remove(instance);
                }

                SetState(DetermineServerState(_state, _instances));
            }
        }
 private void ConnectInstance(MongoServerInstance instance)
 {
     Interlocked.Increment(ref _outstandingInstanceConnections);
     ThreadPool.QueueUserWorkItem(_ =>
     {
         try
         {
             instance.Connect();
         }
         catch
         {
             // instance is keeping it's last ConnectionException
         }
         finally
         {
             Interlocked.Decrement(ref _outstandingInstanceConnections);
         }
     });
 }
 private void RemoveInstance(MongoServerInstance instance)
 {
     _connectedInstances.Remove(instance);
     lock (_lock)
     {
         _instances.Remove(instance);
         instance.StateChanged -= InstanceStateChanged;
         instance.DisconnectPermanently();
         ProcessInstanceStateChange(instance);
     }
 }
 private void QueueConnect(MongoServerInstance serverInstance)
 {
     var args = new ConnectArgs
     {
         ServerInstance = serverInstance,
         ResponseQueue = _responseQueue
     };
     ThreadPool.QueueUserWorkItem(ConnectWorkItem, args);
     _connects.Add(args);
 }
 /// <summary>
 /// Processes the connected instance state change.
 /// </summary>
 /// <param name="instance">The instance.</param>
 protected override void ProcessConnectedInstanceStateChange(MongoServerInstance instance)
 {
     if (instance.IsPrimary)
     {
         ProcessConnectedPrimaryStateChange(instance);
     }
     else
     {
         ProcessConnectedSecondaryStateChange(instance);
     }
 }
        private void ProcessConnectedPrimaryStateChange(MongoServerInstance instance)
        {
            Interlocked.CompareExchange(ref _replicaSetName, instance.ReplicaSetInformation.Name, null);

            var members = instance.ReplicaSetInformation.Members;
            if (members.Any())
            {
                // remove instances the primary doesn't know about and add instances we don't know about
                MakeInstancesMatchAddresses(members);
            }
            var instancesMarkedPrimary = Instances.Where(x => x.IsPrimary);
            foreach (var otherInstance in instancesMarkedPrimary)
            {
                if (!otherInstance.Address.Equals(instance.Address))
                {
                    otherInstance.UnsetPrimary();
                }
            }
        }
        private void ProcessFirstResponse(ConnectResponse response)
        {
            var isMasterResponse = response.IsMasterResult.Response;

            // first response has to match replica set name in settings (if any)
            var replicaSetName = isMasterResponse["setName"].AsString;
            if (_server.Settings.ReplicaSetName != null && replicaSetName != _server.Settings.ReplicaSetName)
            {
                var message = string.Format(
                    "Server at address '{0}' is a member of replica set '{1}' and not '{2}'.",
                    response.ServerInstance.Address, replicaSetName, _server.Settings.ReplicaSetName);
                throw new MongoConnectionException(message);
            }
            _server.ReplicaSetName = replicaSetName;

            // find all valid addresses
            var validAddresses = new HashSet<MongoServerAddress>();
            if (isMasterResponse.Contains("hosts"))
            {
                foreach (string address in isMasterResponse["hosts"].AsBsonArray)
                {
                    validAddresses.Add(MongoServerAddress.Parse(address));
                }
            }
            if (isMasterResponse.Contains("passives"))
            {
                foreach (string address in isMasterResponse["passives"].AsBsonArray)
                {
                    validAddresses.Add(MongoServerAddress.Parse(address));
                }
            }
            if (isMasterResponse.Contains("arbiters"))
            {
                foreach (string address in isMasterResponse["arbiters"].AsBsonArray)
                {
                    validAddresses.Add(MongoServerAddress.Parse(address));
                }
            }

            // remove server instances created from the seed list that turn out to be invalid
            var invalidInstances = _server.Instances.Where(i => !validAddresses.Contains(i.Address)).ToArray(); // force evaluation
            foreach (var invalidInstance in invalidInstances)
            {
                _server.RemoveInstance(invalidInstance);
            }

            // add any server instances that were missing from the seed list
            foreach (var address in validAddresses)
            {
                if (!_server.Instances.Any(i => i.Address == address))
                {
                    var missingInstance = new MongoServerInstance(_server, address);
                    _server.AddInstance(missingInstance);
                    QueueConnect(missingInstance);
                }
            }
        }
 private void ProcessConnectedSecondaryStateChange(MongoServerInstance instance)
 {
     var address = instance.ReplicaSetInformation.Primary;
     if (address != null)
     {
         // make sure the primary exists in the instance list
         EnsureInstanceWithAddress(address);
     }
 }
        private void ProcessInstanceStateChange(MongoServerInstance instance)
        {
            List<MongoServerInstance> currentInstances;
            MongoServerState currentState;

            lock (_lock)
            {
                currentInstances = _instances;
                currentState = _state;
            }

            if (currentInstances.Contains(instance))
            {
                if (instance.State == MongoServerState.Connected)
                {
                    if (!IsValidInstance(instance))
                    {
                        RemoveInstance(instance);
                        return;
                    }

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

            SetState(DetermineServerState(currentState, currentInstances));
        }
        private void CreateActualProxy(MongoServerInstance instance, BlockingQueue<MongoServerInstance> connectionQueue)
        {
            lock (_lock)
            {
                if (instance.InstanceType == MongoServerInstanceType.ReplicaSetMember)
                {
                    _serverProxy = new ReplicaSetMongoServerProxy(_settings, _instances, connectionQueue, _connectionAttempt);
                }
                else if (instance.InstanceType == MongoServerInstanceType.ShardRouter)
                {
                    _serverProxy = new ShardedMongoServerProxy(_settings, _instances, connectionQueue, _connectionAttempt);
                }
                else if (instance.InstanceType == MongoServerInstanceType.StandAlone)
                {
                    var otherInstances = _instances.Where(x => x != instance).ToList();
                    foreach (var otherInstance in otherInstances)
                    {
                        otherInstance.Disconnect();
                    }

                    _serverProxy = new DirectMongoServerProxy(_settings, instance, _connectionAttempt);
                }
                else
                {
                    throw new MongoConnectionException("The type of servers in the host list could not be determined.");
                }
            }
        }
 /// <summary>
 /// Processes the connected instance state change.
 /// </summary>
 /// <param name="instance">The instance.</param>
 protected virtual void ProcessConnectedInstanceStateChange(MongoServerInstance instance)
 { }
        /// <summary>
        /// Ensures that the instance is in the collection.
        /// </summary>
        /// <param name="instance">The instance.</param>
        public void EnsureContains(MongoServerInstance instance)
        {
            lock (_connectedInstancesLock)
            {
                if (_instanceLookup.ContainsKey(instance))
                {
                    return;
                }

                var node = new LinkedListNode<InstanceWithPingTime>(new InstanceWithPingTime
                {
                    Instance = instance,
                    CachedAveragePingTime = instance.AveragePingTime
                });

                if (_instances.Count == 0 || _instances.First.Value.CachedAveragePingTime > node.Value.CachedAveragePingTime)
                {
                    _instances.AddFirst(node);
                }
                else
                {
                    var current = _instances.First;

                    while (current.Next != null && node.Value.CachedAveragePingTime > current.Next.Value.CachedAveragePingTime)
                    {
                        current = current.Next;
                    }

                    _instances.AddAfter(current, node);
                }

                _instanceLookup.Add(instance, node);
                instance.AveragePingTimeChanged += InstanceAveragePingTimeChanged;
            }
        }
 // private methods
 private void AddInstance(MongoServerInstance instance)
 {
     lock (_lock)
     {
         _instances.Add(instance);
         instance.StateChanged += InstanceStateChanged;
         ProcessInstanceStateChange(instance);
     }
 }
        /// <summary>
        /// Removes the specified instance.
        /// </summary>
        /// <param name="instance">The instance.</param>
        public void Remove(MongoServerInstance instance)
        {
            lock (_connectedInstancesLock)
            {
                LinkedListNode<InstanceWithPingTime> node;
                if (!_instanceLookup.TryGetValue(instance, out node))
                {
                    return;
                }

                instance.AveragePingTimeChanged -= InstanceAveragePingTimeChanged;
                _instanceLookup.Remove(instance);
                _instances.Remove(node);
            }
        }
        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);
            }
        }
        /// <summary>
        /// Determines whether the instance is a valid.  If not, the instance is removed.
        /// </summary>
        /// <param name="instance">The instance.</param>
        /// <returns>
        ///   <c>true</c> if the instance is valid; otherwise, <c>false</c>.
        /// </returns>
        protected override bool IsValidInstance(MongoServerInstance instance)
        {
            if (instance.InstanceType != MongoServerInstanceType.ReplicaSetMember)
            {
                return false;
            }

            // read _replicaSetName in a thread-safe way
            var replicaSetName = Interlocked.CompareExchange(ref _replicaSetName, null, null);

            return replicaSetName == null || 
                instance.ReplicaSetInformation.Name == null || 
                replicaSetName == instance.ReplicaSetInformation.Name;
        }
 /// <summary>
 /// Ensures that an instance with the address exists.
 /// </summary>
 /// <param name="address">The address.</param>
 protected void EnsureInstanceWithAddress(MongoServerAddress 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)
             {
                 SetState(MongoServerState.Connecting);
                 ConnectInstance(instance);
             }
         }
     }
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="DirectMongoServerProxy"/> class.
 /// </summary>
 /// <param name="serverSettings">The server settings.</param>
 /// <param name="instance">The instance.</param>
 /// <param name="connectionAttempt">The connection attempt.</param>
 public DirectMongoServerProxy(MongoServerSettings serverSettings, MongoServerInstance instance, int connectionAttempt)
 {
     _settings = serverSettings;
     _instance = instance;
     _connectionAttempt = connectionAttempt;
 }