// 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 } } } }
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 } } } }