1 // Copyright (C) 2002 The Npgsql Development Team
2 // npgsql-general@gborg.postgresql.org
3 // http://gborg.postgresql.org/project/npgsql/projdisplay.php
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // ------------------------------------------------------------------
22 // 0.00.0000 - 06/17/2002 - ulrich sprick - creation
23 // - 05/??/2004 - Glen Parker<glenebob@nwlink.com> rewritten using
27 using System.Collections;
29 using System.Threading;
33 internal class ConnectorPool
36 /// A queue with an extra Int32 for keeping track of busy connections.
38 private class ConnectorQueue : System.Collections.Queue
41 /// The number of pooled Connectors that belong to this queue but
42 /// are currently in use.
44 public Int32 UseCount = 0;
47 /// <value>Unique static instance of the connector pool
49 internal static ConnectorPool ConnectorPoolMgr = new Npgsql.ConnectorPool();
51 public ConnectorPool()
53 PooledConnectors = new Hashtable();
57 /// <value>Map of index to unused pooled connectors, avaliable to the
58 /// next RequestConnector() call.</value>
59 /// <remarks>This hashmap will be indexed by connection string.
60 /// This key will hold a list of queues of pooled connectors available to be used.</remarks>
61 private Hashtable PooledConnectors;
63 /// <value>Map of shared connectors, avaliable to the
64 /// next RequestConnector() call.</value>
65 /// <remarks>This hashmap will be indexed by connection string.
66 /// This key will hold a list of shared connectors available to be used.</remarks>
68 //private Hashtable SharedConnectors;
71 /// Searches the shared and pooled connector lists for a
72 /// matching connector object or creates a new one.
74 /// <param name="Connection">The NpgsqlConnection that is requesting
75 /// the connector. Its ConnectionString will be used to search the
76 /// pool for available connectors.</param>
77 /// <returns>A connector object.</returns>
78 internal Npgsql.Connector RequestConnector (NpgsqlConnection Connection)
80 if (Connection.Pooling) {
81 return RequestPooledConnector(Connection);
83 return GetNonPooledConnector(Connection);
88 /// Find a pooled connector. Handle locking and timeout here.
90 private Npgsql.Connector RequestPooledConnector (NpgsqlConnection Connection)
93 Int32 timeoutMilliseconds = Connection.Timeout * 1000;
97 Connector = RequestPooledConnectorInternal(Connection);
100 while (Connector == null && timeoutMilliseconds > 0)
102 Int32 ST = timeoutMilliseconds > 1000 ? 1000 : timeoutMilliseconds;
105 timeoutMilliseconds -= ST;
109 Connector = RequestPooledConnectorInternal(Connection);
113 if (Connector == null) {
114 throw new Exception("Timeout while getting a connection from pool.");
121 /// Find a pooled connector. Handle shared/non-shared here.
123 private Npgsql.Connector RequestPooledConnectorInternal (NpgsqlConnection Connection)
125 Connector Connector = null;
126 Boolean Shared = false;
128 // If sharing were implemented, I suppose Shared would be set based
129 // on some property on the Connection.
132 Connector = GetPooledConnector(Connection);
134 // Connection sharing? What's that?
135 throw new NotImplementedException("Internal: Shared pooling not implemented");
142 /// Releases a connector, possibly back to the pool for future use.
145 /// Pooled connectors will be put back into the pool if there is room.
146 /// Shared connectors should just have their use count decremented
147 /// since they always stay in the shared pool.
149 /// <param name="Connector">The connector to release.</param>
150 /// <param name="ForceClose">Force the connector to close, even if it is pooled.</param>
151 public void ReleaseConnector (Connector Connector, bool ForceClose)
153 if (Connector.Connection.Pooling) {
154 ReleasePooledConnector(Connector, ForceClose);
156 UngetNonPooledConnector(Connector);
161 /// Release a pooled connector. Handle locking here.
163 private void ReleasePooledConnector (Connector Connector, bool ForceClose)
167 ReleasePooledConnectorInternal(Connector, ForceClose);
172 /// Release a pooled connector. Handle shared/non-shared here.
174 private void ReleasePooledConnectorInternal (Connector Connector, bool ForceClose)
176 if (! Connector.Shared) {
177 UngetPooledConnector(Connector, ForceClose);
179 // Connection sharing? What's that?
180 throw new NotImplementedException("Internal: Shared pooling not implemented");
185 /// Create a connector without any pooling functionality.
187 private Npgsql.Connector GetNonPooledConnector(NpgsqlConnection Connection)
191 Connector = new Connector(false);
192 Connector.Connection = Connection;
198 /// Find an available pooled connector in the non-shared pool, or create
199 /// a new one if none found.
201 private Npgsql.Connector GetPooledConnector(NpgsqlConnection Connection)
203 ConnectorQueue Queue;
204 Connector Connector = null;
206 // Try to find a queue.
207 Queue = (ConnectorQueue)PooledConnectors[Connection.ConnectionString];
210 Queue = new ConnectorQueue();
211 PooledConnectors[Connection.ConnectionString] = Queue;
214 if (Queue.Count > 0) {
215 // Found a queue with connectors. Grab the top one.
216 Connector = (Connector)Queue.Dequeue();
218 Connector.Connection = Connection;
219 } else if (Queue.Count + Queue.UseCount < Connection.MaxPoolSize) {
220 Connector = new Connector(false);
222 Connector.Connection = Connection;
230 /// Find an available shared connector in the shared pool, or create
231 /// a new one if none found.
233 private Npgsql.Connector GetSharedConnector(NpgsqlConnection Connection)
241 /// Close the connector.
243 /// <param name="Connector">Connector to release</param>
244 private void UngetNonPooledConnector(Connector Connector)
250 /// Put a pooled connector into the pool queue. Create the queue if needed.
252 /// <param name="Connector">Connector to pool</param>
253 private void UngetPooledConnector(Connector Connector, bool ForceClose)
255 ConnectorQueue Queue;
258 Queue = (ConnectorQueue)PooledConnectors[Connector.Connection.ConnectionString];
261 throw new InvalidOperationException("Internal: No connector queue found for existing connector.");
267 Connector.Connection = null;
268 Queue.Enqueue(Connector);
275 /// Stop sharing a shared connector.
277 /// <param name="Connector">Connector to unshare</param>
278 private void UngetSharedConnector(Connector Connector)