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