/// <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;
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="MultipleInstanceMongoServerProxy"/> class.
        /// </summary>
        /// <param name="sequentialId">The sequential id.</param>
        /// <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(int sequentialId, MongoServerProxySettings settings, IEnumerable<MongoServerInstance> instances, BlockingQueue<MongoServerInstance> connectionQueue, int connectionAttempt)
        {
            _state = MongoServerState.Connecting;
            _sequentialId = sequentialId;
            _settings = settings;
            _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);
            }
        }
        // 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(MongoServerProxySettings 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)
            };
        }
 // 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();
 }
        // private methods
        private IMongoServerProxy CreateInstance(int sequentialId, MongoServerProxySettings settings)
        {
            var connectionMode = settings.ConnectionMode;
            if (settings.ConnectionMode == ConnectionMode.Automatic)
            {
                if (settings.ReplicaSetName != null)
                {
                    connectionMode = ConnectionMode.ReplicaSet;
                }
                else if (settings.Servers.Count() == 1)
                {
                    connectionMode = ConnectionMode.Direct;
                }
            }

            switch (connectionMode)
            {
                case ConnectionMode.Direct:
                    return new DirectMongoServerProxy(sequentialId, settings);
                case ConnectionMode.ReplicaSet:
                    return new ReplicaSetMongoServerProxy(sequentialId, settings);
                case ConnectionMode.ShardRouter:
                    return new ShardedMongoServerProxy(sequentialId, settings);
                default:
                    return new DiscoveringMongoServerProxy(sequentialId, settings);
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="MultipleInstanceMongoServerProxy"/> class.
        /// </summary>
        /// <param name="sequentialId">The sequential id.</param>
        /// <param name="settings">The settings.</param>
        protected MultipleInstanceMongoServerProxy(int sequentialId, MongoServerProxySettings settings)
        {
            _sequentialId = sequentialId;
            _settings = settings;
            _connectedInstances = new ConnectedInstanceCollection();
            _instances = new List<MongoServerInstance>();

            MakeInstancesMatchAddresses(settings.Servers);
        }
 // public methods
 /// <summary>
 /// Creates an IMongoServerProxy of some type that depends on the settings (or returns an existing one if one has already been created with these settings).
 /// </summary>
 /// <param name="settings">The settings.</param>
 /// <returns>An IMongoServerProxy.</returns>
 public IMongoServerProxy Create(MongoServerProxySettings settings)
 {
     lock (_lock)
     {
         IMongoServerProxy proxy;
         if (!_proxies.TryGetValue(settings, out proxy))
         {
             proxy = CreateInstance(_nextSequentialId++, settings);
             _proxies.Add(settings, proxy);
         }
         return proxy;
     }
 }
        // constructors
        internal MongoConnectionPool(MongoServerInstance serverInstance)
        {
            _settings = serverInstance.Settings;
            _serverInstance = serverInstance;
            _poolSize = 0;

            _defaultAcquireConnectionOptions = new AcquireConnectionOptions
            {
                OkToAvoidWaitingByCreatingNewConnection = true,
                OkToExceedMaxConnectionPoolSize = false,
                OkToExceedWaitQueueSize = false,
                WaitQueueTimeout = _settings.WaitQueueTimeout
            };
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ShardedMongoServerProxy"/> class.
 /// </summary>
 /// <param name="sequentialId">The sequential id.</param>
 /// <param name="settings">The settings.</param>
 /// <param name="instances">The instances.</param>
 /// <param name="stateChangedQueue">The state changed queue.</param>
 /// <param name="connectionAttempt">The connection attempt.</param>
 public ShardedMongoServerProxy(int sequentialId, MongoServerProxySettings settings, IEnumerable<MongoServerInstance> instances, BlockingQueue<MongoServerInstance> stateChangedQueue, int connectionAttempt)
     : base(sequentialId, settings, instances, stateChangedQueue, connectionAttempt)
 { }
 // constructors
 /// <summary>
 /// Initializes a new instance of the <see cref="ShardedMongoServerProxy"/> class.
 /// </summary>
 /// <param name="sequentialId">The sequential id.</param>
 /// <param name="settings">The settings.</param>
 public ShardedMongoServerProxy(int sequentialId, MongoServerProxySettings settings)
     : base(sequentialId, settings)
 { }
 // constructors
 /// <summary>
 /// Initializes a new instance of the <see cref="DirectMongoServerProxy"/> class.
 /// </summary>
 /// <param name="sequentialId">The sequential id.</param>
 /// <param name="settings">The settings.</param>
 public DirectMongoServerProxy(int sequentialId, MongoServerProxySettings settings)
 {
     _sequentialId = sequentialId;
     _settings = settings;
     _instance = new MongoServerInstance(settings, settings.Servers.First());
 }
 // constructors
 /// <summary>
 /// Initializes a new instance of the <see cref="ReplicaSetMongoServerProxy"/> class.
 /// </summary>
 /// <param name="sequentialId">The sequential id.</param>
 /// <param name="settings">The settings.</param>
 public ReplicaSetMongoServerProxy(int sequentialId, MongoServerProxySettings settings)
     : base(sequentialId, settings)
 {
     _replicaSetName = settings.ReplicaSetName;
 }