2004-05-01 Francisco Figueiredo Jr. <fxjrlists@yahoo.com.br>
[mono.git] / mcs / class / Npgsql / Npgsql / NpgsqlConnectorPool.cs
1 //      Copyright (C) 2002 The Npgsql Development Team
2 //      npgsql-general@gborg.postgresql.org
3 //      http://gborg.postgresql.org/project/npgsql/projdisplay.php
4 //
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.
9 //
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.
14 //
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
18 //
19 //      ConnectorPool.cs
20 // ------------------------------------------------------------------
21 //      Status
22 //              0.00.0000 - 06/17/2002 - ulrich sprick - creation
23
24 using System;
25 using System.Collections;
26 using Npgsql;
27 using System.Threading;
28
29 namespace Npgsql
30 {
31     internal class ConnectorPool
32     {
33         /// <value>Unique static instance of the connector pool
34         /// mamager.</value>
35         internal static ConnectorPool ConnectorPoolMgr = new Npgsql.ConnectorPool();
36
37         public ConnectorPool()
38         {
39             PooledConnectors = new Hashtable();
40         }
41
42
43         /// <value>Map of index to unused pooled connectors, avaliable to the
44         /// next RequestConnector() call.</value>
45         /// <remarks>This hasmap will be indexed by connection string.
46         /// This key will hold a list of the pooled connectors available to be used.</remarks>
47         internal Hashtable PooledConnectors;
48
49         /// <value>List of used, shared conncetors.</value>
50         /// <remarks>Points to the head of a double linked list</remarks>
51         private Npgsql.Connector SharedConnectors;
52
53         /// <summary>
54         /// Cuts out a connector from the the list it is in.
55         /// </summary>
56         /// <param name="Connector">The connector object to be cut out.</param>
57         /// <remarks>Shall be replaced if the lists will be based on
58         /// Collections.DictionaryBase classs </remarks>
59         internal void CutOutConnector( Npgsql.Connector Connector )
60         {
61             if ( Connector.Prev != null )
62                 Connector.Prev.Next = Connector.Next;
63             if ( Connector.Next != null )
64                 Connector.Next.Prev = Connector.Prev;
65         }
66
67         /// <summary>
68         /// Inserts a connector at the head of a shared connector list.
69         /// </summary>
70         /// <param name="Connector">The connctor to be inserted</param>
71         internal void InsertSharedConnector( Npgsql.Connector Connector )
72         {
73             if ( this.SharedConnectors == null ) // the list is empty
74             {
75                 // make the connector the only member
76                 Connector.Prev = Connector.Next = null;
77             }
78             else // the list is not empty
79             {
80                 // Make the connector the new list head
81                 Connector.Next = this.SharedConnectors;
82                 this.SharedConnectors.Prev = Connector;
83                 Connector.Prev = null;
84             }
85             // point the list to the new head
86             this.SharedConnectors = Connector;
87         }
88
89         /// <summary>
90         /// Inserts a connector at the head of a pooled connector list.
91         /// </summary>
92         /// <param name="Connector">The connctor to be inserted</param>
93         /*internal void InsertPooledConnector( Npgsql.Connector Connector )
94         {
95             if ( this.PooledConnectors == null ) // the list is empty
96             {
97                 // make the connector the only member
98                 Connector.Prev = Connector.Next = null;
99             }
100             else // the list is not empty
101             {
102                 // Make the connector the new list head
103                 Connector.Next = this.PooledConnectors;
104                 this.PooledConnectors.Prev = Connector;
105                 Connector.Prev = null;
106             }
107             // point the list to the new head
108             this.PooledConnectors = Connector;
109         }*/
110
111
112         internal Int32 GetPoolSize(String connectionString)
113         {
114             ArrayList pool = (ArrayList)PooledConnectors[connectionString];
115             if (pool == null)
116                 return 0;
117             else
118                 return pool.Count;
119
120
121         }
122
123         /// <summary>
124         /// Searches the shared and pooled connector lists for a
125         /// matching connector object or creates a new one.
126         /// </summary>
127         /// <param name="ConnectString">used to connect to the
128         /// database server</param>
129         /// <param name="Shared">Allows multiple connections
130         /// on a single connector. </param>
131         /// <returns>A pooled connector object.</returns>
132         internal Npgsql.Connector RequestConnector (String connectionString,
133                 Int32 maxPoolSize,
134                 Int32 timeout,
135                 Boolean shared )
136         {
137             Connector connector;
138             ArrayList connectorPool = null;
139
140             if ( shared )
141             {
142                 // if a shared connector is requested then the
143                 // Shared Connector List is searched first
144
145                 /*for ( Connector = Npgsql.ConnectorPool.ConnectorPoolMgr.SharedConnectors;
146                         Connector != null; Connector = Connector.Next )
147                 {
148                     if ( Connector.ConnectString == connectionString )
149                     {   // Bingo!
150                         // Return the shared connector to caller
151                         Connector.mShareCount++;
152                         return Connector;
153                     }
154                 }*/
155
156                 return null;
157             }
158             else
159             {
160                 // if a shared connector could not be found or a
161                 // nonshared connector is requested, then the pooled
162                 // (unused) connectors are beeing searched.
163
164
165                 connectorPool = (ArrayList)PooledConnectors[connectionString];
166
167                 if (connectorPool == null)
168                 {
169                     connectorPool = new ArrayList();
170                     PooledConnectors[connectionString] = connectorPool;
171                 }
172
173
174                 // Now look for an available connector.
175
176                 Connector freeConnector = FindFreeConnector(connectorPool);
177                 if (freeConnector != null)
178                     return freeConnector;
179
180                 // No suitable connector could be found, so create new one
181                 // if there is room available.
182
183                 if (connectorPool.Count < maxPoolSize)
184                 {
185                     connector = new Npgsql.Connector(connectionString, shared);
186
187                     connectorPool.Add(connector);
188
189
190                     // and then returned to the caller
191                     return connector;
192                 }
193                 else
194                 {
195                     // keep checking in the pool until some connector is available or
196                     // a timeout occurs.
197                     Int32 timeoutMilliseconds = timeout * 1000;
198
199                     while (timeoutMilliseconds > 0)
200                     {
201                         Connector freeConnector2 = FindFreeConnector(connectorPool);
202                         if (freeConnector2 != null)
203                             return freeConnector2;
204                         else
205                             Thread.Sleep((timeoutMilliseconds > 900) ? 900 : timeoutMilliseconds);
206                         timeoutMilliseconds -= 900;
207                     }
208
209                     throw new Exception("Timeout while getting a connection from pool.");
210
211                 }
212
213             }
214
215         }
216
217         private Connector FindFreeConnector(ArrayList connectorPool)
218         {
219             foreach (Connector c in connectorPool)
220             {
221                 if (!c.InUse)
222                     return c;
223             }
224
225             return null;
226         }
227     }
228 }