2 // Mono.Data.TdsClient.TdsConnectionPool.cs
5 // Lluis Sanchez Gual (lluis@ximian.com)
6 // Christian Hergert (christian.hergert@gmail.com)
7 // Gonzalo Paniagua Javier (gonzalo@novell.com)
9 // Copyright (C) 2004 Novell, Inc.
10 // Copyright (C) 2009 Novell, Inc.
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System
.Collections
;
36 using System
.Threading
;
38 namespace Mono
.Data
.Tds
.Protocol
40 public class TdsConnectionPoolManager
42 Hashtable pools
= Hashtable
.Synchronized (new Hashtable ());
45 public TdsConnectionPoolManager (TdsVersion version
)
47 this.version
= version
;
50 public TdsConnectionPool
GetConnectionPool (string connectionString
, TdsConnectionInfo info
)
52 TdsConnectionPool pool
= (TdsConnectionPool
) pools
[connectionString
];
54 pools
[connectionString
] = new TdsConnectionPool (this, info
);
55 pool
= (TdsConnectionPool
) pools
[connectionString
];
60 public TdsConnectionPool
GetConnectionPool (string connectionString
)
62 return (TdsConnectionPool
) pools
[connectionString
];
65 public virtual Tds
CreateConnection (TdsConnectionInfo info
)
67 //Console.WriteLine ("CreateConnection: TdsVersion:{0}", version);
70 case TdsVersion
.tds42
:
71 return new Tds42 (info
.DataSource
, info
.Port
, info
.PacketSize
, info
.Timeout
);
72 case TdsVersion
.tds50
:
73 return new Tds50 (info
.DataSource
, info
.Port
, info
.PacketSize
, info
.Timeout
);
74 case TdsVersion
.tds70
:
75 return new Tds70 (info
.DataSource
, info
.Port
, info
.PacketSize
, info
.Timeout
);
76 case TdsVersion
.tds80
:
77 return new Tds80 (info
.DataSource
, info
.Port
, info
.PacketSize
, info
.Timeout
);
79 throw new NotSupportedException ();
82 public IDictionary
GetConnectionPool ()
88 public class TdsConnectionInfo
90 public TdsConnectionInfo (string dataSource
, int port
, int packetSize
, int timeout
, int minSize
, int maxSize
)
92 DataSource
= dataSource
;
94 PacketSize
= packetSize
;
96 PoolMinSize
= minSize
;
97 PoolMaxSize
= maxSize
;
100 public string DataSource
;
102 public int PacketSize
;
104 public int PoolMinSize
;
105 public int PoolMaxSize
;
107 public override string ToString ()
109 StringBuilder sb
= new StringBuilder ();
110 sb
.AppendFormat ("DataSouce: {0}\n", DataSource
);
111 sb
.AppendFormat ("Port: {0}\n", Port
);
112 sb
.AppendFormat ("PacketSize: {0}\n", PacketSize
);
113 sb
.AppendFormat ("Timeout: {0}\n", Timeout
);
114 sb
.AppendFormat ("PoolMinSize: {0}\n", PoolMinSize
);
115 sb
.AppendFormat ("PoolMaxSize: {0}", PoolMaxSize
);
116 return sb
.ToString ();
120 public class TdsConnectionPool
122 TdsConnectionInfo info
;
124 TdsConnectionPoolManager manager
;
128 public TdsConnectionPool (TdsConnectionPoolManager manager
, TdsConnectionInfo info
)
131 this.manager
= manager
;
132 conns
= new ArrayList (info
.PoolMaxSize
);
133 available
= new Queue (info
.PoolMaxSize
);
137 void InitializePool ()
139 /* conns.Count might not be 0 when we are resetting the connection pool */
140 for (int i
= conns
.Count
; i
< info
.PoolMinSize
; i
++) {
142 Tds t
= manager
.CreateConnection (info
);
144 available
.Enqueue (t
);
146 // Ignore. GetConnection will throw again.
151 public bool Pooling
{
152 get { return !no_pooling; }
153 set { no_pooling = !value; }
159 public Tds
GetConnection ()
162 return manager
.CreateConnection (info
);
166 int retries
= info
.PoolMaxSize
* 2;
168 while (result
== null) {
171 if (available
.Count
> 0) {
172 result
= (Tds
) available
.Dequeue ();
173 break; // .. and do the reset out of the loop
175 Monitor
.Enter (conns
);
177 if (conns
.Count
>= info
.PoolMaxSize
- in_progress
) {
178 Monitor
.Exit (conns
);
179 bool got_lock
= Monitor
.Wait (available
, info
.Timeout
* 1000);
181 throw new InvalidOperationException (
182 "Timeout expired. The timeout period elapsed before a " +
183 "connection could be obtained. A possible explanation " +
184 "is that all the connections in the pool are in use, " +
185 "and the maximum pool size is reached.");
186 } else if (available
.Count
> 0) {
187 result
= (Tds
) available
.Dequeue ();
188 break; // .. and do the reset out of the loop
196 Monitor
.Exit (conns
); // Exiting if not owned is ok < 2.x
201 result
= manager
.CreateConnection (info
);
212 bool remove_cnc
= true;
213 Exception exc
= null;
215 remove_cnc
= (!result
.IsConnected
|| !result
.Reset ());
216 } catch (Exception e
) {
222 conns
.Remove (result
);
223 result
.Disconnect ();
232 public void ReleaseConnection (Tds connection
)
234 if (connection
== null)
237 connection
.Disconnect ();
241 if (connection
.poolStatus
== 2) {
243 conns
.Remove (connection
);
244 connection
.Disconnect ();
248 if (connection
!= null) // connection is still open
249 available
.Enqueue (connection
);
250 // We pulse even if we don't queue, because null means that there's a slot
251 // available in 'conns'
252 Monitor
.Pulse (available
);
257 public void ResetConnectionPool ()
263 for (i
= conns
.Count
- 1; i
>= 0; i
--) {
264 tds
= (Tds
) conns
[i
];
265 tds
.poolStatus
= 2; // 2 -> disconnect me upon release
267 for (i
= available
.Count
- 1; i
>= 0; i
--) {
268 tds
= (Tds
) available
.Dequeue ();
275 Monitor
.PulseAll (available
);
279 #endregion // Methods