// Copyright (C) 2002 The Npgsql Development Team // npgsql-general@gborg.postgresql.org // http://gborg.postgresql.org/project/npgsql/projdisplay.php // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // ConnectorPool.cs // ------------------------------------------------------------------ // Status // 0.00.0000 - 06/17/2002 - ulrich sprick - creation using System; using System.Collections; using Npgsql; using System.Threading; namespace Npgsql { internal class ConnectorPool { /// Unique static instance of the connector pool /// mamager. internal static ConnectorPool ConnectorPoolMgr = new Npgsql.ConnectorPool(); public ConnectorPool() { PooledConnectors = new Hashtable(); } /// Map of index to unused pooled connectors, avaliable to the /// next RequestConnector() call. /// This hasmap will be indexed by connection string. /// This key will hold a list of the pooled connectors available to be used. internal Hashtable PooledConnectors; /// List of used, shared conncetors. /// Points to the head of a double linked list private Npgsql.Connector SharedConnectors; /// /// Cuts out a connector from the the list it is in. /// /// The connector object to be cut out. /// Shall be replaced if the lists will be based on /// Collections.DictionaryBase classs internal void CutOutConnector( Npgsql.Connector Connector ) { if ( Connector.Prev != null ) Connector.Prev.Next = Connector.Next; if ( Connector.Next != null ) Connector.Next.Prev = Connector.Prev; } /// /// Inserts a connector at the head of a shared connector list. /// /// The connctor to be inserted internal void InsertSharedConnector( Npgsql.Connector Connector ) { if ( this.SharedConnectors == null ) // the list is empty { // make the connector the only member Connector.Prev = Connector.Next = null; } else // the list is not empty { // Make the connector the new list head Connector.Next = this.SharedConnectors; this.SharedConnectors.Prev = Connector; Connector.Prev = null; } // point the list to the new head this.SharedConnectors = Connector; } /// /// Inserts a connector at the head of a pooled connector list. /// /// The connctor to be inserted /*internal void InsertPooledConnector( Npgsql.Connector Connector ) { if ( this.PooledConnectors == null ) // the list is empty { // make the connector the only member Connector.Prev = Connector.Next = null; } else // the list is not empty { // Make the connector the new list head Connector.Next = this.PooledConnectors; this.PooledConnectors.Prev = Connector; Connector.Prev = null; } // point the list to the new head this.PooledConnectors = Connector; }*/ internal Int32 GetPoolSize(String connectionString) { ArrayList pool = (ArrayList)PooledConnectors[connectionString]; if (pool == null) return 0; else return pool.Count; } /// /// Searches the shared and pooled connector lists for a /// matching connector object or creates a new one. /// /// used to connect to the /// database server /// Allows multiple connections /// on a single connector. /// A pooled connector object. internal Npgsql.Connector RequestConnector (String connectionString, Int32 maxPoolSize, Int32 timeout, Boolean shared ) { Connector connector; ArrayList connectorPool = null; if ( shared ) { // if a shared connector is requested then the // Shared Connector List is searched first /*for ( Connector = Npgsql.ConnectorPool.ConnectorPoolMgr.SharedConnectors; Connector != null; Connector = Connector.Next ) { if ( Connector.ConnectString == connectionString ) { // Bingo! // Return the shared connector to caller Connector.mShareCount++; return Connector; } }*/ return null; } else { // if a shared connector could not be found or a // nonshared connector is requested, then the pooled // (unused) connectors are beeing searched. connectorPool = (ArrayList)PooledConnectors[connectionString]; if (connectorPool == null) { connectorPool = new ArrayList(); PooledConnectors[connectionString] = connectorPool; } // Now look for an available connector. Connector freeConnector = FindFreeConnector(connectorPool); if (freeConnector != null) return freeConnector; // No suitable connector could be found, so create new one // if there is room available. if (connectorPool.Count < maxPoolSize) { connector = new Npgsql.Connector(connectionString, shared); connectorPool.Add(connector); // and then returned to the caller return connector; } else { // keep checking in the pool until some connector is available or // a timeout occurs. Int32 timeoutMilliseconds = timeout * 1000; while (timeoutMilliseconds > 0) { Connector freeConnector2 = FindFreeConnector(connectorPool); if (freeConnector2 != null) return freeConnector2; else Thread.Sleep((timeoutMilliseconds > 900) ? 900 : timeoutMilliseconds); timeoutMilliseconds -= 900; } throw new NpgsqlException("Timeout while getting a connection from pool."); } } } private Connector FindFreeConnector(ArrayList connectorPool) { foreach (Connector c in connectorPool) { if (!c.InUse) return c; } return null; } } }