3 // Permission is hereby granted, free of charge, to any person obtaining
4 // a copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to
8 // permit persons to whom the Software is furnished to do so, subject to
9 // the following conditions:
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 using System.Collections;
\r
25 using System.Threading;
\r
27 namespace IBM.Data.DB2
\r
32 /// <remarks>One connection pool per connectionstring</remarks>
\r
33 internal sealed class DB2ConnectionPool
\r
35 private ArrayList openFreeConnections; // list of pooled connections sorted by age. First connection is present at index 'connectionsUsableOffset'
\r
36 private Queue openFreeMinimalAllocated;
\r
37 private int connectionsOpen; // total number of connections open (in pool, an in use by application)
\r
38 private int connectionsInUse; // total connection in use by application
\r
39 private int connectionsUsableOffset; // Offset to the first pooled connection in 'openFreeConnections'
\r
40 private Timer timer;
\r
41 public string databaseProductName;
\r
42 public string databaseVersion;
\r
43 public int majorVersion;
\r
44 public int minorVersion;
\r
46 private DB2ConnectionSettings connectionSettings;
\r
48 public DB2ConnectionPool(DB2ConnectionSettings connectionSettings)
\r
50 this.connectionSettings = connectionSettings;
\r
51 openFreeConnections = new ArrayList();
\r
54 public DB2ConnectionSettings ConnectionSettings
\r
56 get { return connectionSettings; }
\r
59 public DB2OpenConnection GetOpenConnection(DB2Connection db2Conn)
\r
61 DB2OpenConnection connection = null;
\r
62 lock(openFreeConnections.SyncRoot)
\r
64 if((connectionSettings.ConnectionPoolSizeMax > 0) &&
\r
65 (connectionsOpen >= connectionSettings.ConnectionPoolSizeMax))
\r
67 throw new ArgumentException("Maximum connections reached for connectionstring");
\r
70 while(connectionsOpen > connectionsInUse)
\r
72 connection = (DB2OpenConnection)openFreeConnections[openFreeConnections.Count - 1];
\r
73 openFreeConnections.RemoveAt(openFreeConnections.Count - 1);
\r
75 // check if connection is dead
\r
77 short sqlRet = DB2CLIWrapper.SQLGetConnectAttr(connection.DBHandle, DB2Constants.SQL_ATTR_CONNECTION_DEAD, out isDead, 0, IntPtr.Zero);
\r
78 if(((sqlRet == DB2Constants.SQL_SUCCESS_WITH_INFO) || (sqlRet == DB2Constants.SQL_SUCCESS)) &&
\r
79 (isDead == DB2Constants.SQL_CD_FALSE))
\r
87 connection.Dispose();
\r
92 if(connectionsOpen == connectionsInUse)
\r
101 if(connection == null)
\r
103 openFreeConnections.Clear();
\r
104 connectionsUsableOffset = 0;
\r
106 connection = new DB2OpenConnection(connectionSettings, db2Conn);
\r
108 connectionsInUse++;
\r
114 private void DisposeTimedoutConnections(object state)
\r
116 lock(openFreeConnections.SyncRoot)
\r
120 TimeSpan timeToDispose = TimeSpan.Zero;
\r
121 DB2OpenConnection connection;
\r
122 while(connectionsOpen > connectionsInUse)
\r
124 connection = (DB2OpenConnection)openFreeConnections[connectionsUsableOffset];
\r
125 timeToDispose = connection.poolDisposalTime.Subtract(DateTime.Now);
\r
126 if((timeToDispose.Ticks < 0) || // time to die
\r
127 (timeToDispose > connectionSettings.ConnectionLifeTime)) // messing with system clock
\r
129 connection.Dispose();
\r
130 openFreeConnections[connectionsUsableOffset] = null;
\r
132 connectionsUsableOffset++;
\r
139 if(connectionsOpen > connectionsInUse)
\r
141 connection = (DB2OpenConnection)openFreeConnections[connectionsUsableOffset];
\r
142 timer.Change(timeToDispose, new TimeSpan(-1));
\r
150 if((connectionsUsableOffset > (openFreeConnections.Capacity / 2)) &&
\r
151 (connectionsOpen > connectionsInUse))
\r
153 openFreeConnections.RemoveRange(0, connectionsUsableOffset); // cleanup once in a while
\r
154 connectionsUsableOffset = 0;
\r
159 public void AddToFreeConnections(DB2OpenConnection connection)
\r
161 lock(openFreeConnections.SyncRoot)
\r
163 connection.poolDisposalTime = DateTime.Now.Add(connectionSettings.ConnectionLifeTime);
\r
166 timer = new Timer(new TimerCallback(DisposeTimedoutConnections), null,
\r
167 connectionSettings.ConnectionLifeTime, new TimeSpan(-1));
\r
169 connectionsInUse--;
\r
170 openFreeConnections.Add(connection);
\r
174 public void OpenConnectionFinalized()
\r
176 lock(openFreeConnections.SyncRoot)
\r
179 connectionsInUse--;
\r
184 /// Find a specific connection pool
\r
186 /// <param name="connectionString"></param>
\r
187 /// <returns></returns>
\r
188 static public DB2ConnectionPool FindConnectionPool(string connectionString)
\r
190 return (DB2ConnectionPool)DB2Environment.Instance.connectionPools[connectionString];
\r
194 /// Get a connection pool. If it doesn't exist yet, create it
\r
196 /// <param name="connectionSettings"></param>
\r
197 /// <returns></returns>
\r
198 static public DB2ConnectionPool GetConnectionPool(DB2ConnectionSettings connectionSettings)
\r
200 DB2Environment environment = DB2Environment.Instance;
\r
202 lock(environment.connectionPools.SyncRoot)
\r
204 DB2ConnectionPool pool = (DB2ConnectionPool)environment.connectionPools[connectionSettings.ConnectionString];
\r
207 pool = new DB2ConnectionPool(connectionSettings);
\r
208 environment.connectionPools.Add(connectionSettings.ConnectionString, pool);
\r