X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FMono.Data.Tds%2FMono.Data.Tds.Protocol%2FTdsConnectionPool.cs;h=7ec2fe0e9e27586fefa3a9613f558027fcf36a7a;hb=e4d8f21cf6f6629ea80d4db5cc5086e24047491a;hp=25bf2e2d789d9348f7a9056432bc57f7443e3967;hpb=53497da09c4928635f4d4c4776c8c7e48c6098c3;p=mono.git diff --git a/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsConnectionPool.cs b/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsConnectionPool.cs index 25bf2e2d789..7ec2fe0e9e2 100644 --- a/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsConnectionPool.cs +++ b/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsConnectionPool.cs @@ -3,9 +3,11 @@ // // Author: // Lluis Sanchez Gual (lluis@ximian.com) +// Christian Hergert (christian.hergert@gmail.com) +// Gonzalo Paniagua Javier (gonzalo@novell.com) // // Copyright (C) 2004 Novell, Inc. -// +// Copyright (C) 2009 Novell, Inc. // // Permission is hereby granted, free of charge, to any person obtaining @@ -28,16 +30,16 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -using Mono.Data.Tds.Protocol; using System; using System.Collections; +using System.Text; using System.Threading; namespace Mono.Data.Tds.Protocol { public class TdsConnectionPoolManager { - Hashtable pools = new Hashtable (); + Hashtable pools = Hashtable.Synchronized (new Hashtable ()); TdsVersion version; public TdsConnectionPoolManager (TdsVersion version) @@ -47,19 +49,22 @@ namespace Mono.Data.Tds.Protocol public TdsConnectionPool GetConnectionPool (string connectionString, TdsConnectionInfo info) { - lock (pools) - { - TdsConnectionPool pool = (TdsConnectionPool) pools [connectionString]; - if (pool == null) { - pool = new TdsConnectionPool (this, info); - pools [connectionString] = pool; - } - return pool; + TdsConnectionPool pool = (TdsConnectionPool) pools [connectionString]; + if (pool == null) { + pools [connectionString] = new TdsConnectionPool (this, info); + pool = (TdsConnectionPool) pools [connectionString]; } + return pool; } - - public virtual ITds CreateConnection (TdsConnectionInfo info) + + public TdsConnectionPool GetConnectionPool (string connectionString) { + return (TdsConnectionPool) pools [connectionString]; + } + + public virtual Tds CreateConnection (TdsConnectionInfo info) + { + //Console.WriteLine ("CreateConnection: TdsVersion:{0}", version); switch (version) { case TdsVersion.tds42: @@ -67,17 +72,28 @@ namespace Mono.Data.Tds.Protocol case TdsVersion.tds50: return new Tds50 (info.DataSource, info.Port, info.PacketSize, info.Timeout); case TdsVersion.tds70: - return new Tds70 (info.DataSource, info.Port, info.PacketSize, info.Timeout); + return new Tds70 (info.DataSource, info.Port, info.PacketSize, info.Timeout, info.LifeTime); case TdsVersion.tds80: - return new Tds80 (info.DataSource, info.Port, info.PacketSize, info.Timeout); + return new Tds80 (info.DataSource, info.Port, info.PacketSize, info.Timeout, info.LifeTime); } throw new NotSupportedException (); } + + public IDictionary GetConnectionPool () + { + return pools; + } } public class TdsConnectionInfo { + [Obsolete ("Use the constructor that receives a lifetime parameter")] public TdsConnectionInfo (string dataSource, int port, int packetSize, int timeout, int minSize, int maxSize) + : this (dataSource, port, packetSize, timeout, minSize, maxSize, 0) + { + } + + public TdsConnectionInfo (string dataSource, int port, int packetSize, int timeout, int minSize, int maxSize, int lifeTime) { DataSource = dataSource; Port = port; @@ -85,95 +101,191 @@ namespace Mono.Data.Tds.Protocol Timeout = timeout; PoolMinSize = minSize; PoolMaxSize = maxSize; + LifeTime = lifeTime; } public string DataSource; public int Port; public int PacketSize; public int Timeout; + public int LifeTime; public int PoolMinSize; public int PoolMaxSize; + + public override string ToString () + { + StringBuilder sb = new StringBuilder (); + sb.AppendFormat ("DataSouce: {0}\n", DataSource); + sb.AppendFormat ("Port: {0}\n", Port); + sb.AppendFormat ("PacketSize: {0}\n", PacketSize); + sb.AppendFormat ("Timeout: {0}\n", Timeout); + sb.AppendFormat ("PoolMinSize: {0}\n", PoolMinSize); + sb.AppendFormat ("PoolMaxSize: {0}", PoolMaxSize); + return sb.ToString (); + } } - + public class TdsConnectionPool { - ArrayList list = new ArrayList (); TdsConnectionInfo info; - bool initialized; - int activeConnections = 0; + bool no_pooling; TdsConnectionPoolManager manager; - + Queue available; + ArrayList conns; + public TdsConnectionPool (TdsConnectionPoolManager manager, TdsConnectionInfo info) { this.info = info; this.manager = manager; + conns = new ArrayList (info.PoolMaxSize); + available = new Queue (info.PoolMaxSize); + InitializePool (); + } + + void InitializePool () + { + /* conns.Count might not be 0 when we are resetting the connection pool */ + for (int i = conns.Count; i < info.PoolMinSize; i++) { + try { + Tds t = manager.CreateConnection (info); + conns.Add (t); + available.Enqueue (t); + } catch { + // Ignore. GetConnection will throw again. + } + } + } + + public bool Pooling { + get { return !no_pooling; } + set { no_pooling = !value; } } #region Methods - public ITds GetConnection () + int in_progress; + public Tds GetConnection () { - ITds connection = null; - - lock (list) - { - if (!initialized) - { - for (int n=0; n 0) - { - // There are available connections - connection = (ITds) list [list.Count - 1]; - list.RemoveAt (list.Count - 1); - if (!connection.Reset ()) { - try { - connection.Disconnect (); - } catch {} - connection = null; + if (no_pooling) + return manager.CreateConnection (info); + + Tds result = null; + bool create_new; + int retries = info.PoolMaxSize * 2; +retry: + while (result == null) { + create_new = false; + lock (available) { + if (available.Count > 0) { + result = (Tds) available.Dequeue (); + break; // .. and do the reset out of the loop + } + Monitor.Enter (conns); + try { + if (conns.Count >= info.PoolMaxSize - in_progress) { + Monitor.Exit (conns); + bool got_lock = Monitor.Wait (available, info.Timeout * 1000); + if (!got_lock) { + throw new InvalidOperationException ( + "Timeout expired. The timeout period elapsed before a " + + "connection could be obtained. A possible explanation " + + "is that all the connections in the pool are in use, " + + "and the maximum pool size is reached."); + } else if (available.Count > 0) { + result = (Tds) available.Dequeue (); + break; // .. and do the reset out of the loop + } continue; + } else { + create_new = true; + in_progress++; } + } finally { + Monitor.Exit (conns); // Exiting if not owned is ok < 2.x } - - if (connection == null && activeConnections < info.PoolMaxSize) - { - // No connections available, but the connection limit - // has not been reached yet, so a new one can be created - connection = CreateConnection(); - } - - // No available connections in the pool - // Wait for somewone to release one. - if (connection == null) - { - Monitor.Wait (list); + } + if (create_new) { + try { + result = manager.CreateConnection (info); + lock (conns) + conns.Add (result); + return result; + } finally { + lock (available) + in_progress--; } - } - while (connection == null); + } } - return connection; + bool remove_cnc = true; + Exception exc = null; + try { + remove_cnc = (!result.IsConnected || !result.Reset ()); + } catch (Exception e) { + remove_cnc = true; + exc = e; + } + if (remove_cnc) { + lock (conns) + conns.Remove (result); + result.Disconnect (); + retries--; + if (retries == 0) + throw exc; + result = null; + goto retry; + } + return result; } - public void ReleaseConnection (ITds tds) + public void ReleaseConnection (Tds connection) { - lock (list) - { - list.Add (tds); - Monitor.Pulse (list); + if (connection == null) + return; + if (no_pooling) { + connection.Disconnect (); + return; + } + + if (connection.poolStatus == 2 || connection.Expired) { + lock (conns) + conns.Remove (connection); + connection.Disconnect (); + connection = null; + } + lock (available) { + if (connection != null) // connection is still open + available.Enqueue (connection); + // We pulse even if we don't queue, because null means that there's a slot + // available in 'conns' + Monitor.Pulse (available); } } - - ITds CreateConnection () + +#if NET_2_0 + public void ResetConnectionPool () { - activeConnections++; - return manager.CreateConnection (info); + lock (available) { + lock (conns) { + Tds tds; + int i; + for (i = conns.Count - 1; i >= 0; i--) { + tds = (Tds) conns [i]; + tds.poolStatus = 2; // 2 -> disconnect me upon release + } + for (i = available.Count - 1; i >= 0; i--) { + tds = (Tds) available.Dequeue (); + tds.Disconnect (); + conns.Remove (tds); + } + available.Clear (); + InitializePool (); + } + Monitor.PulseAll (available); + } } - +#endif #endregion // Methods } } +