protected override void Dispose(bool disposing) { if (!disposing) { mContext.Close(); mContext = null; } base.Dispose(disposing); }
///<summary> /// This method is responsible to handle all protocol messages sent from the backend. /// It holds all the logic to do it. /// To exchange data, it uses a Mediator object from which it reads/writes information /// to handle backend requests. /// </summary> /// internal IEnumerable <IServerResponseObject> ProcessBackendResponsesEnum( NpgsqlConnector context, bool cancelRequestCalled) { try { // Process commandTimeout behavior. if ((context.Mediator.CommandTimeout > 0) && (!CheckForContextSocketAvailability(context))) { // If timeout occurs when establishing the session with server then // throw an exception instead of trying to cancel query. This helps to prevent loop as CancelRequest will also try to stablish a connection and sends commands. if (!((this is NpgsqlStartupState || this is NpgsqlConnectedState || cancelRequestCalled))) { try { context.CancelRequest(); foreach (IServerResponseObject obj in ProcessBackendResponsesEnum(context, true)) { if (obj is IDisposable) { (obj as IDisposable).Dispose(); } } } catch { } //We should have gotten an error from CancelRequest(). Whether we did or not, what we //really have is a timeout exception, and that will be less confusing to the user than //"operation cancelled by user" or similar, so whatever the case, that is what we'll throw. // Changed message again to report about the two possible timeouts: connection or command as the establishment timeout only was confusing users when the timeout was a command timeout. } throw new NpgsqlException(resman.GetString("Exception_ConnectionOrCommandTimeout")); } return(ProcessBackendResponses_Ver_3(context)); } catch (ThreadAbortException) { try { context.CancelRequest(); context.Close(); } catch { } throw; } }
internal IEnumerable <IServerResponseObject> ProcessExistingBackendResponses(NpgsqlConnector context) { try { return(ProcessBackendResponses_Ver_3(context)); } catch (ThreadAbortException) { try { context.CancelRequest(); context.Close(); } catch { } throw; } }
private static void ClearQueue(ConnectorQueue Queue) { if (Queue == null) { return; } while (Queue.Available.Count > 0) { NpgsqlConnector connector = Queue.Available.Dequeue(); try { connector.Close(); } catch { // Maybe we should log something here to say we got an exception while closing connector? } } //Clear the busy list so that the current connections don't get re-added to the queue Queue.Busy.Clear(); }
/// <summary> /// Put a pooled connector into the pool queue. /// </summary> /// <param name="Connector">Connector to pool</param> private void UngetConnector(NpgsqlConnection Connection, NpgsqlConnector Connector) { ConnectorQueue queue; // Find the queue. // As we are handling all possible queues, we have to lock everything... lock (locker) { PooledConnectors.TryGetValue(Connection.ConnectionString, out queue); } if (queue == null) { Connector.Close(); // Release connection to postgres return; // Queue may be emptied by connection problems. See ClearPool below. } Connector.ProvideClientCertificatesCallback -= Connection.ProvideClientCertificatesCallbackDelegate; Connector.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate; Connector.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate; Connector.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate; bool inQueue = false; lock (queue) { inQueue = queue.Busy.ContainsKey(Connector); queue.Busy.Remove(Connector); } if (!Connector.IsInitialized) { if (Connector.Transaction != null) { Connector.Transaction.Cancel(); } Connector.Close(); } else { if (Connector.Transaction != null) { try { Connector.Transaction.Rollback(); } catch { Connector.Close(); } } } if (Connector.State == ConnectionState.Open) { //If thread is good if ((Thread.CurrentThread.ThreadState & (ThreadState.Aborted | ThreadState.AbortRequested)) == 0) { // Release all resources associated with this connector. try { Connector.ReleaseResources(); } catch (Exception) { //If the connector fails to release its resources then it is probably broken, so make sure we don't add it to the queue. // Usually it already won't be in the queue as it would of broken earlier inQueue = false; } if (inQueue) { lock (queue) { queue.Available.Enqueue(Connector); } } else { Connector.Close(); } } else { //Thread is being aborted, this connection is possibly broken. So kill it rather than returning it to the pool Connector.Close(); } } }
/// <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; 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.Open(); Spare.ProvideClientCertificatesCallback -= Connection.ProvideClientCertificatesCallbackDelegate; Spare.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate; Spare.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate; Spare.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate; Queue.Available.Enqueue(Spare); } } } } return(Connector); }
///<summary> /// This method is responsible to handle all protocol messages sent from the backend. /// It holds all the logic to do it. /// To exchange data, it uses a Mediator object from which it reads/writes information /// to handle backend requests. /// </summary> /// internal IEnumerable<IServerResponseObject> ProcessBackendResponsesEnum( NpgsqlConnector context, bool cancelRequestCalled) { try { // Process commandTimeout behavior. if ((context.Mediator.CommandTimeout > 0) && (!CheckForContextSocketAvailability(context, SelectMode.SelectRead))) { // If timeout occurs when establishing the session with server then // throw an exception instead of trying to cancel query. This helps to prevent loop as CancelRequest will also try to stablish a connection and sends commands. if (!((this is NpgsqlStartupState || this is NpgsqlConnectedState || cancelRequestCalled))) { try { context.CancelRequest(); foreach (IServerResponseObject obj in ProcessBackendResponsesEnum(context, true)) { if (obj is IDisposable) { (obj as IDisposable).Dispose(); } } } catch { } //We should have gotten an error from CancelRequest(). Whether we did or not, what we //really have is a timeout exception, and that will be less confusing to the user than //"operation cancelled by user" or similar, so whatever the case, that is what we'll throw. // Changed message again to report about the two possible timeouts: connection or command as the establishment timeout only was confusing users when the timeout was a command timeout. } throw new NpgsqlException(resman.GetString("Exception_ConnectionOrCommandTimeout")); } return ProcessBackendResponses_Ver_3(context); } catch (ThreadAbortException) { try { context.CancelRequest(); context.Close(); } catch { } throw; } }
internal IEnumerable<IServerResponseObject> ProcessExistingBackendResponses(NpgsqlConnector context) { try { return ProcessBackendResponses_Ver_3(context); } catch (ThreadAbortException) { try { context.CancelRequest(); context.Close(); } catch { } throw; } }
/// <summary> /// Put a pooled connector into the pool queue. /// </summary> /// <param name="Connector">Connector to pool</param> private void UngetConnector(NpgsqlConnection Connection, NpgsqlConnector Connector) { ConnectorQueue queue; // Find the queue. // As we are handling all possible queues, we have to lock everything... lock (locker) { PooledConnectors.TryGetValue(Connection.ConnectionString, out queue); } if (queue == null) { Connector.Close(); // Release connection to postgres return; // Queue may be emptied by connection problems. See ClearPool below. } Connector.ProvideClientCertificatesCallback -= Connection.ProvideClientCertificatesCallbackDelegate; Connector.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate; Connector.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate; Connector.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate; bool inQueue = false; lock (queue) { inQueue = queue.Busy.ContainsKey(Connector); queue.Busy.Remove(Connector); } if (!Connector.IsInitialized) { if (Connector.Transaction != null) { Connector.Transaction.Cancel(); } Connector.Close(); } else { if (Connector.Transaction != null) { try { Connector.Transaction.Rollback(); } catch { Connector.Close(); } } } if (Connector.State == ConnectionState.Open) { //If thread is good if ((Thread.CurrentThread.ThreadState & (ThreadState.Aborted | ThreadState.AbortRequested)) == 0) { // Release all resources associated with this connector. try { Connector.ReleaseResources(); } catch (Exception) { //If the connector fails to release its resources then it is probably broken, so make sure we don't add it to the queue. // Usually it already won't be in the queue as it would of broken earlier inQueue = false; } if (inQueue) lock (queue) { queue.Available.Enqueue(Connector); } else Connector.Close(); } else { //Thread is being aborted, this connection is possibly broken. So kill it rather than returning it to the pool Connector.Close(); } } }