// constructors
        internal MongoConnectionPool(MongoServerInstance serverInstance)
        {
            _settings = serverInstance.Settings;
            _serverInstance = serverInstance;
            _poolSize = 0;

            _defaultAcquireConnectionOptions = new AcquireConnectionOptions
            {
                OkToAvoidWaitingByCreatingNewConnection = true,
                OkToExceedMaxConnectionPoolSize = false,
                OkToExceedWaitQueueSize = false,
                WaitQueueTimeout = _settings.WaitQueueTimeout
            };
        }
Example #2
0
        // constructors
        internal MongoConnectionPool(MongoServerInstance serverInstance)
        {
            _settings       = serverInstance.Settings;
            _serverInstance = serverInstance;
            _poolSize       = 0;

            _defaultAcquireConnectionOptions = new AcquireConnectionOptions
            {
                OkToAvoidWaitingByCreatingNewConnection = true,
                OkToExceedMaxConnectionPoolSize         = false,
                OkToExceedWaitQueueSize = false,
                WaitQueueTimeout        = _settings.WaitQueueTimeout
            };
        }
        internal MongoConnection AcquireConnection(AcquireConnectionOptions options)
        {
            MongoConnection connectionToClose = null;
            try
            {
                DateTime timeoutAt = DateTime.UtcNow + options.WaitQueueTimeout;

                lock (_connectionPoolLock)
                {
                    if (_waitQueueSize >= _settings.WaitQueueSize && !options.OkToExceedWaitQueueSize)
                    {
                        throw new MongoConnectionException("Too many threads are already waiting for a connection.");
                    }

                    _waitQueueSize += 1;
                    try
                    {
                        while (true)
                        {
                            if (_availableConnections.Count > 0)
                            {
                                var connection = _availableConnections[_availableConnections.Count - 1];
                                if (connection.IsExpired())
                                {
                                    connectionToClose = connection;
                                    connection = new MongoConnection(this);
                                }

                                _availableConnections.RemoveAt(_availableConnections.Count - 1);
                                return connection;
                            }

                            // avoid waiting by creating a new connection if options allow it
                            if (options.OkToAvoidWaitingByCreatingNewConnection)
                            {
                                if (_poolSize < _settings.MaxConnectionPoolSize || options.OkToExceedMaxConnectionPoolSize)
                                {
                                    // make sure connection is created successfully before incrementing poolSize
                                    // connection will be opened later outside of the lock
                                    var connection = new MongoConnection(this);
                                    _poolSize += 1;
                                    return connection;
                                }
                            }

                            // wait for a connection to be released
                            var timeRemaining = timeoutAt - DateTime.UtcNow;
                            if (timeRemaining > TimeSpan.Zero)
                            {
                                // other methods should call Monitor.Pulse whenever:
                                // 1. an available connection is added _availableConnections
                                // 2. the _poolSize changes
                                Monitor.Wait(_connectionPoolLock, timeRemaining);
                            }
                            else
                            {
                                if (options.OkToExceedMaxConnectionPoolSize)
                                {
                                    // make sure connection is created successfully before incrementing poolSize
                                    // connection will be opened later outside of the lock
                                    var connection = new MongoConnection(this);
                                    _poolSize += 1;
                                    return connection;
                                }
                                else
                                {
                                    throw new TimeoutException("Timeout waiting for a MongoConnection.");
                                }
                            }
                        }
                    }
                    finally
                    {
                        _waitQueueSize -= 1;
                    }
                }
            }
            finally
            {
                if (connectionToClose != null)
                {
                    try
                    {
                        connectionToClose.Close();
                    }
                    catch
                    {
                        // ignore exceptions
                    }
                }
            }
        }
Example #4
0
        internal MongoConnection AcquireConnection(AcquireConnectionOptions options)
        {
            MongoConnection connectionToClose = null;

            try
            {
                DateTime timeoutAt = DateTime.UtcNow + options.WaitQueueTimeout;

                lock (_connectionPoolLock)
                {
                    if (_waitQueueSize >= _settings.WaitQueueSize && !options.OkToExceedWaitQueueSize)
                    {
                        throw new MongoConnectionException("Too many threads are already waiting for a connection.");
                    }

                    _waitQueueSize += 1;
                    try
                    {
                        while (true)
                        {
                            if (_availableConnections.Count > 0)
                            {
                                var connection = _availableConnections[_availableConnections.Count - 1];
                                if (connection.IsExpired())
                                {
                                    connectionToClose = connection;
                                    connection        = new MongoConnection(this);
                                }

                                _availableConnections.RemoveAt(_availableConnections.Count - 1);
                                return(connection);
                            }

                            // avoid waiting by creating a new connection if options allow it
                            if (options.OkToAvoidWaitingByCreatingNewConnection)
                            {
                                if (_poolSize < _settings.MaxConnectionPoolSize || options.OkToExceedMaxConnectionPoolSize)
                                {
                                    // make sure connection is created successfully before incrementing poolSize
                                    // connection will be opened later outside of the lock
                                    var connection = new MongoConnection(this);
                                    _poolSize += 1;
                                    return(connection);
                                }
                            }

                            // wait for a connection to be released
                            var timeRemaining = timeoutAt - DateTime.UtcNow;
                            if (timeRemaining > TimeSpan.Zero)
                            {
                                // other methods should call Monitor.Pulse whenever:
                                // 1. an available connection is added _availableConnections
                                // 2. the _poolSize changes
                                Monitor.Wait(_connectionPoolLock, timeRemaining);
                            }
                            else
                            {
                                if (options.OkToExceedMaxConnectionPoolSize)
                                {
                                    // make sure connection is created successfully before incrementing poolSize
                                    // connection will be opened later outside of the lock
                                    var connection = new MongoConnection(this);
                                    _poolSize += 1;
                                    return(connection);
                                }
                                else
                                {
                                    throw new TimeoutException("Timeout waiting for a MongoConnection.");
                                }
                            }
                        }
                    }
                    finally
                    {
                        _waitQueueSize -= 1;
                    }
                }
            }
            finally
            {
                if (connectionToClose != null)
                {
                    try
                    {
                        connectionToClose.Close();
                    }
                    catch
                    {
                        // ignore exceptions
                    }
                }
            }
        }
        internal MongoConnection AcquireConnection(string databaseName, MongoCredentials credentials, AcquireConnectionOptions options)
        {
            MongoConnection connectionToClose = null;
            try
            {
                DateTime timeoutAt = DateTime.UtcNow + options.WaitQueueTimeout;

                lock (_connectionPoolLock)
                {
                    if (_waitQueueSize >= _settings.WaitQueueSize && !options.OkToExceedWaitQueueSize)
                    {
                        throw new MongoConnectionException("Too many threads are already waiting for a connection.");
                    }

                    _waitQueueSize += 1;
                    try
                    {
                        while (true)
                        {
                            if (_availableConnections.Count > 0)
                            {
                                // first try to find the most recently used connection that is already authenticated for this database
                                for (int i = _availableConnections.Count - 1; i >= 0; i--)
                                {
                                    var connection = _availableConnections[i];
                                    if (connection.IsExpired())
                                    {
                                        _availableConnections.RemoveAt(i);
                                        connectionToClose = connection;
                                        return new MongoConnection(this);
                                    }
                                    else if (connection.IsAuthenticated(databaseName, credentials))
                                    {
                                        _availableConnections.RemoveAt(i);
                                        return connection;
                                    }
                                }

                                // otherwise find the most recently used connection that can be authenticated for this database
                                for (int i = _availableConnections.Count - 1; i >= 0; i--)
                                {
                                    var connection = _availableConnections[i];
                                    if (connection.CanAuthenticate(databaseName, credentials))
                                    {
                                        _availableConnections.RemoveAt(i);
                                        return connection;
                                    }
                                }

                                // otherwise replace the least recently used connection with a brand new one
                                // if this happens a lot the connection pool size should be increased
                                connectionToClose = _availableConnections[0];
                                _availableConnections.RemoveAt(0);
                                return new MongoConnection(this);
                            }

                            // avoid waiting by creating a new connection if options allow it
                            if (options.OkToAvoidWaitingByCreatingNewConnection)
                            {
                                if (_poolSize < _settings.MaxConnectionPoolSize || options.OkToExceedMaxConnectionPoolSize)
                                {
                                    // make sure connection is created successfully before incrementing poolSize
                                    // connection will be opened later outside of the lock
                                    var connection = new MongoConnection(this);
                                    _poolSize += 1;
                                    return connection;
                                }
                            }

                            // wait for a connection to be released
                            var timeRemaining = timeoutAt - DateTime.UtcNow;
                            if (timeRemaining > TimeSpan.Zero)
                            {
                                // other methods should call Monitor.Pulse whenever:
                                // 1. an available connection is added _availableConnections
                                // 2. the _poolSize changes
                                Monitor.Wait(_connectionPoolLock, timeRemaining);
                            }
                            else
                            {
                                if (options.OkToExceedMaxConnectionPoolSize)
                                {
                                    // make sure connection is created successfully before incrementing poolSize
                                    // connection will be opened later outside of the lock
                                    var connection = new MongoConnection(this);
                                    _poolSize += 1;
                                    return connection;
                                }
                                else
                                {
                                    throw new TimeoutException("Timeout waiting for a MongoConnection.");
                                }
                            }
                        }
                    }
                    finally
                    {
                        _waitQueueSize -= 1;
                    }
                }
            }
            finally
            {
                if (connectionToClose != null)
                {
                    try
                    {
                        connectionToClose.Close();
                    }
                    catch
                    {
                        // ignore exceptions
                    }
                }
            }
        }