**** Merged r40732-r40872 from MCS ****
[mono.git] / mcs / class / Mono.Data.Tds / Mono.Data.Tds.Protocol / TdsConnectionPool.cs
1 //
2 // Mono.Data.TdsClient.TdsConnectionPool.cs
3 //
4 // Author:
5 //   Lluis Sanchez Gual (lluis@ximian.com)
6 //
7 // Copyright (C) 2004 Novell, Inc.
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using Mono.Data.Tds.Protocol;
32 using System;
33 using System.Collections;
34 using System.Threading;
35
36 namespace Mono.Data.Tds.Protocol 
37 {
38         public class TdsConnectionPoolManager
39         {
40                 Hashtable pools = new Hashtable ();
41                 TdsVersion version;
42                 
43                 public TdsConnectionPoolManager (TdsVersion version)
44                 {
45                         this.version = version;
46                 }
47                 
48                 public TdsConnectionPool GetConnectionPool (string connectionString, TdsConnectionInfo info)
49                 {
50                         lock (pools)
51                         {
52                                 TdsConnectionPool pool = (TdsConnectionPool) pools [connectionString];
53                                 if (pool == null) {
54                                         pool = new TdsConnectionPool (this, info);
55                                         pools [connectionString] = pool;
56                                 }
57                                 return pool;
58                         }
59                 }
60                 
61                 public virtual ITds CreateConnection (TdsConnectionInfo info)
62                 {
63                         switch (version)
64                         {
65                                 case TdsVersion.tds42:
66                                         return new Tds42 (info.DataSource, info.Port, info.PacketSize, info.Timeout);
67                                 case TdsVersion.tds50:
68                                         return new Tds50 (info.DataSource, info.Port, info.PacketSize, info.Timeout);
69                                 case TdsVersion.tds70:
70                                         return new Tds70 (info.DataSource, info.Port, info.PacketSize, info.Timeout);
71                                 case TdsVersion.tds80:
72                                         return new Tds80 (info.DataSource, info.Port, info.PacketSize, info.Timeout);
73                         }
74                         throw new NotSupportedException ();
75                 }
76         }
77         
78         public class TdsConnectionInfo
79         {
80                 public TdsConnectionInfo (string dataSource, int port, int packetSize, int timeout, int minSize, int maxSize)
81                 {
82                         DataSource = dataSource;
83                         Port = port;
84                         PacketSize = packetSize;
85                         Timeout = timeout;
86                         PoolMinSize = minSize;
87                         PoolMaxSize = maxSize;
88                 }
89                 
90                 public string DataSource;
91                 public int Port;
92                 public int PacketSize;
93                 public int Timeout;
94                 public int PoolMinSize;
95                 public int PoolMaxSize;
96         }
97         
98         public class TdsConnectionPool
99         {
100                 ArrayList list = new ArrayList ();
101                 TdsConnectionInfo info;
102                 bool initialized;
103                 int activeConnections = 0;
104                 TdsConnectionPoolManager manager;
105
106                 public TdsConnectionPool (TdsConnectionPoolManager manager, TdsConnectionInfo info)
107                 {
108                         this.info = info;
109                         this.manager = manager;
110                 }
111
112                 #region Methods
113
114                 public ITds GetConnection ()
115                 {
116                         ITds connection = null;
117                                 
118                         lock (list)
119                         {
120                                 if (!initialized) 
121                                 {
122                                         for (int n=0; n<info.PoolMinSize; n++)
123                                                 list.Add (CreateConnection ());
124                                         initialized = true;
125                                 }
126                                 
127                                 do {
128                                         if (list.Count > 0) 
129                                         {
130                                                 // There are available connections
131                                                 connection = (ITds) list [list.Count - 1];
132                                                 list.RemoveAt (list.Count - 1);
133                                                 if (!connection.Reset ()) {
134                                                         try {
135                                                                 connection.Disconnect ();
136                                                         } catch {}
137                                                         connection = null;
138                                                         continue;
139                                                 }
140                                         }
141
142                                         if (connection == null && activeConnections < info.PoolMaxSize)
143                                         {
144                                                 // No connections available, but the connection limit
145                                                 // has not been reached yet, so a new one can be created
146                                                 connection = CreateConnection();
147                                         }
148
149                                         // No available connections in the pool
150                                         // Wait for somewone to release one.
151                                         if (connection == null)
152                                         {
153                                                 Monitor.Wait (list);
154                                         }
155                                 } 
156                                 while (connection == null);
157                         }
158
159                         return connection;
160                 }
161
162                 public void ReleaseConnection (ITds tds)
163                 {
164                         lock (list)
165                         {
166                                 list.Add (tds);
167                                 Monitor.Pulse (list);
168                         }
169                 }
170                 
171                 ITds CreateConnection ()
172                 {
173                         activeConnections++;
174                         return manager.CreateConnection (info);
175                 }
176                 
177                 #endregion // Methods
178         }
179 }