/// <summary> /// Opens a database connection with the property settings specified by the /// <see cref="Npgsql.NpgsqlConnection.ConnectionString">ConnectionString</see>. /// </summary> public override void Open() { // If we're postponing a close (see doc on this variable), the connection is already // open and can be silently reused if (_postponingClose) { return; } CheckConnectionClosed(); NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Open"); // Check if there is any missing argument. if (!settings.ContainsKey(Keywords.Host)) { throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), NpgsqlConnectionStringBuilder.GetKeyName(Keywords.Host)); } if (!settings.ContainsKey(Keywords.UserName) && !settings.ContainsKey(Keywords.IntegratedSecurity)) { throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), NpgsqlConnectionStringBuilder.GetKeyName(Keywords.UserName)); } // Get a Connector, either from the pool or creating one ourselves. if (Pooling) { connector = NpgsqlConnectorPool.ConnectorPoolMgr.RequestConnector(this); } else { connector = new NpgsqlConnector(this); connector.RemoteCertificateValidationCallback += RemoteCertificateValidationCallback; // connector.ProvideClientCertificatesCallback += ProvideClientCertificatesCallbackDelegate; // connector.CertificateSelectionCallback += CertificateSelectionCallbackDelegate; // connector.CertificateValidationCallback += CertificateValidationCallbackDelegate; // connector.PrivateKeySelectionCallback += PrivateKeySelectionCallbackDelegate; // connector.ValidateRemoteCertificateCallback += ValidateRemoteCertificateCallbackDelegate; connector.Open(); } connector.Notice += NoticeDelegate; connector.Notification += NotificationDelegate; if (SyncNotification) { connector.AddNotificationThread(); } if (Enlist) { Promotable.Enlist(Transaction.Current); } this.OnStateChange(new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open)); }
/// <summary> /// Opens a database connection with the property settings specified by the /// <see cref="NpgsqlConnection.ConnectionString">ConnectionString</see>. /// </summary> public override void Open() { // If we're postponing a close (see doc on this variable), the connection is already // open and can be silently reused if (_postponingClose) { return; } CheckConnectionClosed(); _log.Debug("Opening connnection"); // Check if there is any missing argument. if (!_settings.ContainsKey(Keywords.Host)) { throw new ArgumentException(L10N.MissingConnStrArg, Keywords.Host.ToString()); } if (!_settings.ContainsKey(Keywords.UserName) && !_settings.ContainsKey(Keywords.IntegratedSecurity)) { throw new ArgumentException(L10N.MissingConnStrArg, Keywords.UserName.ToString()); } // Get a Connector, either from the pool or creating one ourselves. if (Pooling) { Connector = NpgsqlConnectorPool.ConnectorPoolMgr.RequestConnector(this); } else { Connector = new NpgsqlConnector(this); Connector.ProvideClientCertificatesCallback += ProvideClientCertificatesCallbackDelegate; Connector.CertificateSelectionCallback += CertificateSelectionCallbackDelegate; Connector.CertificateValidationCallback += CertificateValidationCallbackDelegate; Connector.PrivateKeySelectionCallback += PrivateKeySelectionCallbackDelegate; Connector.ValidateRemoteCertificateCallback += ValidateRemoteCertificateCallbackDelegate; Connector.Open(); } Connector.Notice += NoticeDelegate; Connector.Notification += NotificationDelegate; if (SyncNotification) { // Disable async notifications for now //Connector.AddNotificationThread(); } if (Enlist) { Promotable.Enlist(Transaction.Current); } OnStateChange(new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open)); }
/// <summary> /// Attempts to ensure, on a best-effort basis, that there are enough connections to meet MinPoolSize. /// This method never throws an exception. /// </summary> void EnsureMinPoolSize(NpgsqlConnection conn) { int missing; lock (this) { missing = _min - (Busy + Idle.Count); if (missing <= 0) { return; } Busy += missing; } for (; missing > 0; missing--) { try { #if NETSTANDARD1_3 var connector = new NpgsqlConnector(conn.Clone()) #else var connector = new NpgsqlConnector((NpgsqlConnection)((ICloneable)conn).Clone()) #endif { ClearCounter = _clearCounter }; // TODO: Think about the timeout here... connector.Open(new NpgsqlTimeout(TimeSpan.Zero), false, CancellationToken.None).Wait(); connector.Reset(); Counters.NumberOfPooledConnections.Increment(); lock (this) { Idle.Push(connector); EnsurePruningTimerState(); Busy--; } } catch (Exception e) { lock (this) Busy -= missing; Log.Warn("Connection error while attempting to ensure MinPoolSize", e); return; } } }
/// <summary> /// Attempts to ensure, on a best-effort basis, that there are enough connections to meet MinPoolSize. /// This method never throws an exception. /// </summary> void EnsureMinPoolSize(NpgsqlConnection conn) { int missing; lock (this) { missing = Min - (Busy + Idle.Count); if (missing <= 0) { return; } Busy += missing; } for (; missing > 0; missing--) { try { #if NET451 || NET45 var connector = new NpgsqlConnector((NpgsqlConnection)((ICloneable)conn).Clone()) #else var connector = new NpgsqlConnector(conn.Clone()) #endif { ClearCounter = _clearCounter }; connector.Open(); connector.Reset(); lock (this) { Idle.Push(connector); EnsurePruningTimerState(); Busy--; } } catch (Exception e) { lock (this) Busy -= missing; Log.Warn("Connection error while attempting to ensure MinPoolSize", e); return; } } }
/// <summary> /// Find an available pooled connector in the pool, or create a new one if none found. /// </summary> private NpgsqlConnector GetPooledConnector(NpgsqlConnection Connection) { ConnectorQueue Queue = null; NpgsqlConnector Connector = null; // We only need to lock all pools when trying to get one pool or create one. lock (locker) { // Try to find a queue. if (!PooledConnectors.TryGetValue(Connection.ConnectionString, out Queue)) { Queue = new ConnectorQueue(); Queue.ConnectionLifeTime = Connection.ConnectionLifeTime; Queue.MinPoolSize = Connection.MinPoolSize; PooledConnectors[Connection.ConnectionString] = Queue; } } // Now we can simply lock on the pool itself. lock (Queue) { if (Queue.Available.Count > 0) { // Found a queue with connectors. Grab the top one. // Check if the connector is still valid. Connector = Queue.Available.Dequeue(); Queue.Busy.Add(Connector, null); } } if (Connector != null) { return(Connector); } lock (Queue) { if (Queue.Available.Count + Queue.Busy.Count < Connection.MaxPoolSize) { Connector = new NpgsqlConnector(Connection); Queue.Busy.Add(Connector, null); } } if (Connector != null) { Connector.ProvideClientCertificatesCallback = Connection.ProvideClientCertificatesCallback; Connector.UserCertificateValidationCallback = Connection.UserCertificateValidationCallback; try { Connector.Open(); } catch { Contract.Assert(Connector.IsBroken); lock (Queue) { Queue.Busy.Remove(Connector); } throw; } // Meet the MinPoolSize requirement if needed. if (Connection.MinPoolSize > 1) { lock (Queue) { while (Queue.Available.Count + Queue.Busy.Count < Connection.MinPoolSize) { NpgsqlConnector spare = new NpgsqlConnector(Connection) { ProvideClientCertificatesCallback = Connection.ProvideClientCertificatesCallback, UserCertificateValidationCallback = Connection.UserCertificateValidationCallback }; spare.Open(); spare.ProvideClientCertificatesCallback = null; spare.UserCertificateValidationCallback = null; spare.Connection = null; Queue.Available.Enqueue(spare); } } } } return(Connector); }
internal async ValueTask <NpgsqlConnector> AllocateLong(NpgsqlConnection conn, NpgsqlTimeout timeout, bool async, CancellationToken cancellationToken) { Debug.Assert(Monitor.IsEntered(this)); NpgsqlConnector connector; Debug.Assert(Busy <= _max); if (Busy == _max) { // TODO: Async cancellation var tcs = new TaskCompletionSource <NpgsqlConnector>(); _waiting.Enqueue(new WaitingOpenAttempt { TaskCompletionSource = tcs, IsAsync = async }); Monitor.Exit(this); try { if (async) { if (timeout.IsSet) { var timeLeft = timeout.TimeLeft; if (timeLeft <= TimeSpan.Zero || tcs.Task != await Task.WhenAny(tcs.Task, Task.Delay(timeLeft))) { throw new NpgsqlException($"The connection pool has been exhausted, either raise MaxPoolSize (currently {_max}) or Timeout (currently {Settings.Timeout} seconds)"); } } else { await tcs.Task; } } else { if (timeout.IsSet) { var timeLeft = timeout.TimeLeft; if (timeLeft <= TimeSpan.Zero || !tcs.Task.Wait(timeLeft)) { throw new NpgsqlException($"The connection pool has been exhausted, either raise MaxPoolSize (currently {_max}) or Timeout (currently {Settings.Timeout} seconds)"); } } else { tcs.Task.Wait(); } } } catch { // We're here if the timeout expired or the cancellation token was triggered // Re-lock and check in case the task was set to completed after coming out of the Wait lock (this) { if (!tcs.Task.IsCompleted) { tcs.SetCanceled(); throw; } } } connector = tcs.Task.Result; connector.Connection = conn; return(connector); } // No idle connectors are available, and we're under the pool's maximum capacity. IncrementBusy(); Monitor.Exit(this); try { connector = new NpgsqlConnector(conn) { ClearCounter = _clearCounter }; await connector.Open(timeout, async, cancellationToken); Counters.NumberOfPooledConnections.Increment(); EnsureMinPoolSize(conn); return(connector); } catch { lock (this) DecrementBusy(); throw; } }
/// <summary> /// Opens a database connection with the property settings specified by the /// <see cref="Npgsql.NpgsqlConnection.ConnectionString">ConnectionString</see>. /// </summary> public override void Open() { // If we're postponing a close (see doc on this variable), the connection is already // open and can be silently reused if (_postponingClose) return; CheckConnectionClosed(); NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Open"); // Check if there is any missing argument. if (!settings.ContainsKey(Keywords.Host)) { throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), NpgsqlConnectionStringBuilder.GetKeyName(Keywords.Host)); } if (!settings.ContainsKey(Keywords.UserName) && !settings.ContainsKey(Keywords.IntegratedSecurity)) { throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), NpgsqlConnectionStringBuilder.GetKeyName(Keywords.UserName)); } // Get a Connector, either from the pool or creating one ourselves. if (Pooling) { connector = NpgsqlConnectorPool.ConnectorPoolMgr.RequestConnector(this); } else { connector = new NpgsqlConnector(this); connector.ProvideClientCertificatesCallback += ProvideClientCertificatesCallbackDelegate; connector.CertificateSelectionCallback += CertificateSelectionCallbackDelegate; connector.CertificateValidationCallback += CertificateValidationCallbackDelegate; connector.PrivateKeySelectionCallback += PrivateKeySelectionCallbackDelegate; connector.ValidateRemoteCertificateCallback += ValidateRemoteCertificateCallbackDelegate; connector.Open(); } connector.Notice += NoticeDelegate; connector.Notification += NotificationDelegate; if (SyncNotification) { connector.AddNotificationThread(); } if (Enlist) { Promotable.Enlist(Transaction.Current); } this.OnStateChange (new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open)); }
/// <summary> /// Find an available pooled connector in the non-shared pool, or create /// a new one if none found. /// </summary> private NpgsqlConnector GetPooledConnector(NpgsqlConnection Connection) { ConnectorQueue Queue; NpgsqlConnector Connector = null; // We only need to lock all pools when trying to get one pool or create one. lock (locker) { // Try to find a queue. if (!PooledConnectors.TryGetValue(Connection.ConnectionString, out Queue)) { Queue = new ConnectorQueue(); Queue.ConnectionLifeTime = Connection.ConnectionLifeTime; Queue.MinPoolSize = Connection.MinPoolSize; PooledConnectors[Connection.ConnectionString] = Queue; } } // Now we can simply lock on the pool itself. lock (Queue) { if (Queue.Available.Count > 0) { // Found a queue with connectors. Grab the top one. // Check if the connector is still valid. Connector = Queue.Available.Dequeue(); Queue.Busy.Add(Connector, null); } } if (Connector != null) { if (!Connector.IsValid()) { lock (Queue) { Queue.Busy.Remove(Connector); } Connector.Close(); return GetPooledConnector(Connection); //Try again } return Connector; } lock (Queue) { if (Queue.Available.Count + Queue.Busy.Count < Connection.MaxPoolSize) { Connector = new NpgsqlConnector(Connection); Queue.Busy.Add(Connector, null); } } if (Connector != null) { Connector.ProvideClientCertificatesCallback += Connection.ProvideClientCertificatesCallbackDelegate; Connector.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate; Connector.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate; Connector.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate; Connector.ValidateRemoteCertificateCallback += Connection.ValidateRemoteCertificateCallbackDelegate; try { Connector.Open(); } catch { lock (Queue) { Queue.Busy.Remove(Connector); } Connector.Close(); throw; } // Meet the MinPoolSize requirement if needed. if (Connection.MinPoolSize > 1) { lock (Queue) { while (Queue.Available.Count + Queue.Busy.Count < Connection.MinPoolSize) { NpgsqlConnector Spare = new NpgsqlConnector(Connection); Spare.ProvideClientCertificatesCallback += Connection.ProvideClientCertificatesCallbackDelegate; Spare.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate; Spare.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate; Spare.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate; Spare.ValidateRemoteCertificateCallback += Connection.ValidateRemoteCertificateCallbackDelegate; Spare.Open(); Spare.ProvideClientCertificatesCallback -= Connection.ProvideClientCertificatesCallbackDelegate; Spare.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate; Spare.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate; Spare.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate; Spare.ValidateRemoteCertificateCallback -= Connection.ValidateRemoteCertificateCallbackDelegate; Queue.Available.Enqueue(Spare); } } } } return Connector; }
/// <summary> /// Find an available pooled connector in the non-shared pool, or create /// a new one if none found. /// </summary> private NpgsqlConnector GetPooledConnector(NpgsqlConnection Connection) { ConnectorQueue Queue; NpgsqlConnector Connector = null; // Try to find a queue. Queue = (ConnectorQueue)PooledConnectors[Connection.ConnectionString.ToString()]; if (Queue == null) { Queue = new ConnectorQueue(); Queue.ConnectionLifeTime = Connection.ConnectionLifeTime; Queue.MinPoolSize = Connection.MinPoolSize; PooledConnectors[Connection.ConnectionString.ToString()] = Queue; } // Fix queue use count. Use count may be dropped below zero if Queue was cleared and there were connections open. if (Queue.UseCount < 0) { Queue.UseCount = 0; } if (Queue.Count > 0) { // Found a queue with connectors. Grab the top one. // Check if the connector is still valid. Connector = (NpgsqlConnector)Queue.Dequeue(); Queue.UseCount++; } else if (Queue.Count + Queue.UseCount < Connection.MaxPoolSize) { Connector = CreateConnector(Connection); Connector.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate; Connector.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate; Connector.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate; try { Connector.Open(); } catch { try { Connector.Close(); } catch {} throw; } Queue.UseCount++; } // Meet the MinPoolSize requirement if needed. if (Connection.MinPoolSize > 0) { while (Queue.Count + Queue.UseCount < Connection.MinPoolSize) { NpgsqlConnector Spare = CreateConnector(Connection); Spare.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate; Spare.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate; Spare.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate; Spare.Open(); Spare.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate; Spare.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate; Spare.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate; Queue.Enqueue(Spare); } } return(Connector); }
internal NpgsqlConnector Allocate(NpgsqlConnection conn, NpgsqlTimeout timeout) { NpgsqlConnector connector; Monitor.Enter(this); while (Idle.Count > 0) { connector = Idle.Pop(); // An idle connector could be broken because of a keepalive if (connector.IsBroken) { continue; } connector.Connection = conn; Busy++; EnsurePruningTimerState(); Monitor.Exit(this); return(connector); } Contract.Assert(Busy <= _max); if (Busy == _max) { // TODO: Async cancellation var tcs = new TaskCompletionSource <NpgsqlConnector>(); EnqueueWaitingOpenAttempt(tcs); Monitor.Exit(this); try { WaitForTask(tcs.Task, timeout.TimeLeft); } catch { // We're here if the timeout expired or the cancellation token was triggered // Re-lock and check in case the task was set to completed after coming out of the Wait lock (this) { if (!tcs.Task.IsCompleted) { tcs.SetCanceled(); throw; } } } connector = tcs.Task.Result; connector.Connection = conn; return(connector); } // No idle connectors are available, and we're under the pool's maximum capacity. Busy++; Monitor.Exit(this); try { connector = new NpgsqlConnector(conn) { ClearCounter = _clearCounter }; connector.Open(timeout); EnsureMinPoolSize(conn); return(connector); } catch { lock (this) Busy--; throw; } }
/// <summary> /// Find an available pooled connector in the non-shared pool, or create /// a new one if none found. /// </summary> private NpgsqlConnector GetPooledConnector(NpgsqlConnection Connection) { ConnectorQueue Queue; NpgsqlConnector Connector = null; // We only need to lock all pools when trying to get one pool or create one. lock (locker) { // Try to find a queue. if (!PooledConnectors.TryGetValue(Connection.ConnectionString, out Queue)) { Queue = new ConnectorQueue(); Queue.ConnectionLifeTime = Connection.ConnectionLifeTime; Queue.MinPoolSize = Connection.MinPoolSize; PooledConnectors[Connection.ConnectionString] = Queue; } } // Now we can simply lock on the pool itself. lock (Queue) { if (Queue.Available.Count > 0) { // Found a queue with connectors. Grab the top one. // Check if the connector is still valid. Connector = Queue.Available.Dequeue(); Queue.Busy.Add(Connector, null); } } if (Connector != null) { if (!Connector.IsValid()) { lock (Queue) { Queue.Busy.Remove(Connector); } Connector.Close(); return(GetPooledConnector(Connection)); //Try again } return(Connector); } lock (Queue) { if (Queue.Available.Count + Queue.Busy.Count < Connection.MaxPoolSize) { Connector = new NpgsqlConnector(Connection); Queue.Busy.Add(Connector, null); } } if (Connector != null) { Connector.ProvideClientCertificatesCallback += Connection.ProvideClientCertificatesCallbackDelegate; Connector.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate; Connector.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate; Connector.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate; Connector.ValidateRemoteCertificateCallback += Connection.ValidateRemoteCertificateCallbackDelegate; try { Connector.Open(); } catch { lock (Queue) { Queue.Busy.Remove(Connector); } Connector.Close(); throw; } // Meet the MinPoolSize requirement if needed. if (Connection.MinPoolSize > 1) { lock (Queue) { while (Queue.Available.Count + Queue.Busy.Count < Connection.MinPoolSize) { NpgsqlConnector Spare = new NpgsqlConnector(Connection); Spare.ProvideClientCertificatesCallback += Connection.ProvideClientCertificatesCallbackDelegate; Spare.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate; Spare.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate; Spare.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate; Spare.ValidateRemoteCertificateCallback += Connection.ValidateRemoteCertificateCallbackDelegate; Spare.Open(); Spare.ProvideClientCertificatesCallback -= Connection.ProvideClientCertificatesCallbackDelegate; Spare.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate; Spare.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate; Spare.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate; Spare.ValidateRemoteCertificateCallback -= Connection.ValidateRemoteCertificateCallbackDelegate; Queue.Available.Enqueue(Spare); } } } } return(Connector); }
/// <summary> /// Find an available pooled connector in the pool, or create a new one if none found. /// </summary> private NpgsqlConnector GetPooledConnector(NpgsqlConnection Connection) { ConnectorQueue Queue = null; NpgsqlConnector Connector = null; // We only need to lock all pools when trying to get one pool or create one. lock (locker) { // Try to find a queue. if (!PooledConnectors.TryGetValue(Connection.ConnectionString, out Queue)) { Queue = new ConnectorQueue(); Queue.ConnectionLifeTime = Connection.ConnectionLifeTime; Queue.MinPoolSize = Connection.MinPoolSize; PooledConnectors[Connection.ConnectionString] = Queue; } } // Now we can simply lock on the pool itself. lock (Queue) { if (Queue.Available.Count > 0) { // Found a queue with connectors. Grab the top one. // Check if the connector is still valid. Connector = Queue.Available.Dequeue(); Queue.Busy.Add(Connector, null); } } if (Connector != null) return Connector; lock (Queue) { if (Queue.Available.Count + Queue.Busy.Count < Connection.MaxPoolSize) { Connector = new NpgsqlConnector(Connection); Queue.Busy.Add(Connector, null); } } if (Connector != null) { Connector.ProvideClientCertificatesCallback = Connection.ProvideClientCertificatesCallback; Connector.UserCertificateValidationCallback = Connection.UserCertificateValidationCallback; try { Connector.Open(); } catch { Contract.Assert(Connector.IsBroken); lock (Queue) { Queue.Busy.Remove(Connector); } throw; } // Meet the MinPoolSize requirement if needed. if (Connection.MinPoolSize > 1) { try { lock (Queue) { while (Queue.Available.Count + Queue.Busy.Count < Connection.MinPoolSize) { NpgsqlConnector spare = new NpgsqlConnector(Connection) { ProvideClientCertificatesCallback = Connection.ProvideClientCertificatesCallback, UserCertificateValidationCallback = Connection.UserCertificateValidationCallback }; spare.Open(); spare.ProvideClientCertificatesCallback = null; spare.UserCertificateValidationCallback = null; spare.Connection = null; Queue.Available.Enqueue(spare); } } } catch (Exception e) { Log.Warn("Exception while trying to open spare connectors to meet MinPoolSize", e); } } } return Connector; }
/// <summary> /// Find an available pooled connector in the non-shared pool, or create /// a new one if none found. /// </summary> private NpgsqlConnector GetPooledConnector(NpgsqlConnection Connection) { ConnectorQueue Queue; NpgsqlConnector Connector = null; // Try to find a queue. if (!PooledConnectors.TryGetValue(Connection.ConnectionString, out Queue)) { Queue = new ConnectorQueue(); Queue.ConnectionLifeTime = Connection.ConnectionLifeTime; Queue.MinPoolSize = Connection.MinPoolSize; PooledConnectors[Connection.ConnectionString] = Queue; } // Fix queue use count. Use count may be dropped below zero if Queue was cleared and there were connections open. if (Queue.UseCount < 0) { Queue.UseCount = 0; } if (Queue.Count > 0) { // Found a queue with connectors. Grab the top one. // Check if the connector is still valid. Connector = Queue.Dequeue(); /*try * { * Connector.TestConnector(); * Connector.RequireReadyForQuery = true; * } * catch //This connector is broken! * { * try * { * Connector.Close(); * } * catch * { * try * { * Connector.Stream.Close(); * } * catch * { * } * } * return GetPooledConnector(Connection); //Try again * }*/ if (!Connector.IsValid()) { try { Connector.Close(); } catch { try { Connector.Stream.Close(); } catch { } } return(GetPooledConnector(Connection)); //Try again } Queue.UseCount++; } else if (Queue.Count + Queue.UseCount < Connection.MaxPoolSize) { Connector = CreateConnector(Connection); Connector.ProvideClientCertificatesCallback += Connection.ProvideClientCertificatesCallbackDelegate; Connector.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate; Connector.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate; Connector.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate; try { Connector.Open(); } catch { try { Connector.Close(); } catch { } throw; } Queue.UseCount++; } // Meet the MinPoolSize requirement if needed. if (Connection.MinPoolSize > 0) { while (Queue.Count + Queue.UseCount < Connection.MinPoolSize) { NpgsqlConnector Spare = CreateConnector(Connection); Spare.ProvideClientCertificatesCallback += Connection.ProvideClientCertificatesCallbackDelegate; Spare.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate; Spare.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate; Spare.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate; Spare.Open(); Spare.ProvideClientCertificatesCallback -= Connection.ProvideClientCertificatesCallbackDelegate; Spare.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate; Spare.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate; Spare.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate; Queue.Enqueue(Spare); } } return(Connector); }
/// <summary> /// Find an available pooled connector in the non-shared pool, or create /// a new one if none found. /// </summary> private NpgsqlConnector GetPooledConnector(NpgsqlConnection Connection) { ConnectorQueue Queue; NpgsqlConnector Connector = null; // Try to find a queue. if (!PooledConnectors.TryGetValue(Connection.ConnectionString, out Queue)) { Queue = new ConnectorQueue(); Queue.ConnectionLifeTime = Connection.ConnectionLifeTime; Queue.MinPoolSize = Connection.MinPoolSize; PooledConnectors[Connection.ConnectionString] = Queue; } if (Queue.Available.Count > 0) { // Found a queue with connectors. Grab the top one. // Check if the connector is still valid. Connector = Queue.Available.Dequeue(); if (!Connector.IsValid()) { Connector.Close(); return(GetPooledConnector(Connection)); //Try again } Queue.Busy.Add(Connector, null); } else if (Queue.Available.Count + Queue.Busy.Count < Connection.MaxPoolSize) { Connector = CreateConnector(Connection); Connector.ProvideClientCertificatesCallback += Connection.ProvideClientCertificatesCallbackDelegate; Connector.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate; Connector.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate; Connector.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate; try { Connector.Open(); } catch { Connector.Close(); throw; } Queue.Busy.Add(Connector, null); } // Meet the MinPoolSize requirement if needed. if (Connection.MinPoolSize > 0) { while (Queue.Available.Count + Queue.Busy.Count < Connection.MinPoolSize) { NpgsqlConnector Spare = CreateConnector(Connection); Spare.ProvideClientCertificatesCallback += Connection.ProvideClientCertificatesCallbackDelegate; Spare.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate; Spare.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate; Spare.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate; Spare.Open(); Spare.ProvideClientCertificatesCallback -= Connection.ProvideClientCertificatesCallbackDelegate; Spare.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate; Spare.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate; Spare.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate; Queue.Available.Enqueue(Spare); } } return(Connector); }
/// <summary> /// Opens a database connection with the property settings specified by the /// <see cref="NpgsqlConnection.ConnectionString">ConnectionString</see>. /// </summary> public override void Open() { if (string.IsNullOrWhiteSpace(Host)) { throw new ArgumentException("Host can't be null"); } if (string.IsNullOrWhiteSpace(Database)) { throw new ArgumentException("Database can't be null"); } if (string.IsNullOrWhiteSpace(UserName) && !IntegratedSecurity) { throw new ArgumentException("Either Username must be specified or IntegratedSecurity must be on"); } Contract.EndContractBlock(); // If we're postponing a close (see doc on this variable), the connection is already // open and can be silently reused if (_postponingClose) { return; } CheckConnectionClosed(); Log.Debug("Opening connnection"); WasBroken = false; try { // Get a Connector, either from the pool or creating one ourselves. if (Pooling) { Connector = NpgsqlConnectorPool.ConnectorPoolMgr.RequestConnector(this); } else { Connector = new NpgsqlConnector(this) { ProvideClientCertificatesCallback = ProvideClientCertificatesCallback, UserCertificateValidationCallback = UserCertificateValidationCallback }; Connector.Open(); } Connector.Notice += NoticeDelegate; Connector.Notification += NotificationDelegate; #if !DNXCORE50 if (Enlist) { Promotable.Enlist(Transaction.Current); } #endif } catch { Connector = null; throw; } OpenCounter++; OnStateChange(new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open)); }
/// <summary> /// Opens a database connection with the property settings specified by the /// <see cref="NpgsqlConnection.ConnectionString">ConnectionString</see>. /// </summary> public override void Open() { // If we're postponing a close (see doc on this variable), the connection is already // open and can be silently reused if (_postponingClose) return; CheckConnectionClosed(); _log.Debug("Opening connnection"); // Check if there is any missing argument. if (!_settings.ContainsKey(Keywords.Host)) { throw new ArgumentException(L10N.MissingConnStrArg, Keywords.Host.ToString()); } if (!_settings.ContainsKey(Keywords.UserName) && !_settings.ContainsKey(Keywords.IntegratedSecurity)) { throw new ArgumentException(L10N.MissingConnStrArg, Keywords.UserName.ToString()); } // Get a Connector, either from the pool or creating one ourselves. if (Pooling) { Connector = NpgsqlConnectorPool.ConnectorPoolMgr.RequestConnector(this); } else { Connector = new NpgsqlConnector(this); Connector.ProvideClientCertificatesCallback += ProvideClientCertificatesCallbackDelegate; Connector.CertificateSelectionCallback += CertificateSelectionCallbackDelegate; Connector.CertificateValidationCallback += CertificateValidationCallbackDelegate; Connector.PrivateKeySelectionCallback += PrivateKeySelectionCallbackDelegate; Connector.ValidateRemoteCertificateCallback += ValidateRemoteCertificateCallbackDelegate; Connector.Open(); } Connector.Notice += NoticeDelegate; Connector.Notification += NotificationDelegate; if (SyncNotification) { Connector.AddNotificationThread(); } if (Enlist) { Promotable.Enlist(Transaction.Current); } OnStateChange(new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open)); }