List:Commits« Previous MessageNext Message »
From:rburnett Date:May 2 2007 8:54pm
Subject:Connector/NET commit: r701 - in branches/5.0: . Driver/Source Driver/Source/common
View as plain text  
Added:
   branches/5.0/Driver/Source/common/Cache.cs
Modified:
   branches/5.0/CHANGES
   branches/5.0/Driver/Source/Connection.cs
Log:
Bug #28167 Poor performance building connection string 

Solved this by introducing a type specific cache at the connection level.  The cache holds the last 25 connection strings to be used.  This patch was based on a patch by a user.  Thanks Maxim!

Modified: branches/5.0/CHANGES
===================================================================
--- branches/5.0/CHANGES	2007-05-02 15:29:07 UTC (rev 700)
+++ branches/5.0/CHANGES	2007-05-02 20:54:10 UTC (rev 701)
@@ -10,6 +10,7 @@
   Bug #27765 Logging does not work
   Bug #27679 MySqlCommandBuilder.DeriveParameters ignores UNSIGNED flag
   Bug #27668 FillSchema and Stored Proc with an out parameter
+  Bug #28167 Poor performance building connection string (thanks Maxim!)
    
   Other changes
   -------------

Modified: branches/5.0/Driver/Source/Connection.cs
===================================================================
--- branches/5.0/Driver/Source/Connection.cs	2007-05-02 15:29:07 UTC (rev 700)
+++ branches/5.0/Driver/Source/Connection.cs	2007-05-02 20:54:10 UTC (rev 701)
@@ -27,93 +27,96 @@
 using System.Globalization;
 using MySql.Data.Common;
 using System.Diagnostics;
+using System.Collections.Generic;
 
 namespace MySql.Data.MySqlClient
 {
-	/// <include file='docs/MySqlConnection.xml' path='docs/ClassSummary/*'/>
+    /// <include file='docs/MySqlConnection.xml' path='docs/ClassSummary/*'/>
 #if !PocketPC
-	[System.Drawing.ToolboxBitmap(typeof(MySqlConnection), "MySqlClient.resources.connection.bmp")]
-	[System.ComponentModel.DesignerCategory("Code")]
-	[ToolboxItem(true)]
+    [System.Drawing.ToolboxBitmap(typeof(MySqlConnection), "MySqlClient.resources.connection.bmp")]
+    [System.ComponentModel.DesignerCategory("Code")]
+    [ToolboxItem(true)]
 #endif
-	public sealed class MySqlConnection : DbConnection, ICloneable
-	{
-		internal ConnectionState connectionState;
-		internal Driver driver;
-		private MySqlDataReader dataReader;
-		private MySqlConnectionStringBuilder settings;
-		private UsageAdvisor advisor;
-		private bool hasBeenOpen;
-		private SchemaProvider schemaProvider;
-		private ProcedureCache procedureCache;
-		private PerformanceMonitor perfMonitor;
-		private MySqlPromotableTransaction currentTransaction;
+    public sealed class MySqlConnection : DbConnection, ICloneable
+    {
+        internal ConnectionState connectionState;
+        internal Driver driver;
+        private MySqlDataReader dataReader;
+        private MySqlConnectionStringBuilder settings;
+        private UsageAdvisor advisor;
+        private bool hasBeenOpen;
+        private SchemaProvider schemaProvider;
+        private ProcedureCache procedureCache;
+        private PerformanceMonitor perfMonitor;
+        private MySqlPromotableTransaction currentTransaction;
         private bool isExecutingBuggyQuery;
 
-		/// <include file='docs/MySqlConnection.xml' path='docs/InfoMessage/*'/>
-		public event MySqlInfoMessageEventHandler InfoMessage;
+        /// <include file='docs/MySqlConnection.xml' path='docs/InfoMessage/*'/>
+        public event MySqlInfoMessageEventHandler InfoMessage;
 
+        private static Cache connectionStringCache = new Cache(0, 25);
+
 #if MONO2
         /// <include file='docs/MySqlConnection.xml' path='docs/StateChange/*'/>
         public event StateChangeEventHandler StateChange;
 #endif
 
-		/// <include file='docs/MySqlConnection.xml' path='docs/DefaultCtor/*'/>
-		public MySqlConnection()
-		{
-			//TODO: add event data to StateChange docs
-			settings = new MySqlConnectionStringBuilder();
-			advisor = new UsageAdvisor(this);
-		}
+        /// <include file='docs/MySqlConnection.xml' path='docs/DefaultCtor/*'/>
+        public MySqlConnection()
+        {
+            //TODO: add event data to StateChange docs
+            settings = new MySqlConnectionStringBuilder();
+            advisor = new UsageAdvisor(this);
+        }
 
-		/// <include file='docs/MySqlConnection.xml' path='docs/Ctor1/*'/>
-		public MySqlConnection(string connectionString)
-			: this()
-		{
-			ConnectionString = connectionString;
-		}
+        /// <include file='docs/MySqlConnection.xml' path='docs/Ctor1/*'/>
+        public MySqlConnection(string connectionString)
+            : this()
+        {
+            ConnectionString = connectionString;
+        }
 
-		#region Interal Methods & Properties
+        #region Interal Methods & Properties
 
-		internal MySqlPromotableTransaction CurrentTransaction
-		{
-			get { return currentTransaction; }
-			set { currentTransaction = value; }
-		}
+        internal MySqlPromotableTransaction CurrentTransaction
+        {
+            get { return currentTransaction; }
+            set { currentTransaction = value; }
+        }
 
-		internal ProcedureCache ProcedureCache
-		{
-			get { return procedureCache; }
-		}
+        internal ProcedureCache ProcedureCache
+        {
+            get { return procedureCache; }
+        }
 
-		internal MySqlConnectionStringBuilder Settings
-		{
-			get { return settings; }
-		}
+        internal MySqlConnectionStringBuilder Settings
+        {
+            get { return settings; }
+        }
 
-		internal MySqlDataReader Reader
-		{
-			get { return dataReader; }
-			set { dataReader = value; }
-		}
+        internal MySqlDataReader Reader
+        {
+            get { return dataReader; }
+            set { dataReader = value; }
+        }
 
-		internal char ParameterMarker
-		{
-			get { if (settings.UseOldSyntax) return '@'; return '?'; }
-		}
+        internal char ParameterMarker
+        {
+            get { if (settings.UseOldSyntax) return '@'; return '?'; }
+        }
 
-		internal void OnInfoMessage(MySqlInfoMessageEventArgs args)
-		{
-			if (InfoMessage != null)
-			{
-				InfoMessage(this, args);
-			}
-		}
+        internal void OnInfoMessage(MySqlInfoMessageEventArgs args)
+        {
+            if (InfoMessage != null)
+            {
+                InfoMessage(this, args);
+            }
+        }
 
-		internal PerformanceMonitor PerfMonitor
-		{
-			get { return perfMonitor; }
-		}
+        internal PerformanceMonitor PerfMonitor
+        {
+            get { return perfMonitor; }
+        }
 
         internal bool IsExecutingBuggyQuery
         {
@@ -123,359 +126,361 @@
 
         #endregion
 
-		#region Properties
+        #region Properties
 
 #if !PocketPC
-		[Browsable(false)]
+        [Browsable(false)]
 #endif
-		internal UsageAdvisor UsageAdvisor
-		{
-			get { return advisor; }
-		}
+        internal UsageAdvisor UsageAdvisor
+        {
+            get { return advisor; }
+        }
 
-		/// <summary>
-		/// Returns the id of the server thread this connection is executing on
-		/// </summary>
+        /// <summary>
+        /// Returns the id of the server thread this connection is executing on
+        /// </summary>
 #if !PocketPC
-		[Browsable(false)]
+        [Browsable(false)]
 #endif
-		public int ServerThread
-		{
-			get { return driver.ThreadID; }
-		}
+        public int ServerThread
+        {
+            get { return driver.ThreadID; }
+        }
 
-		/// <summary>
-		/// Gets the name of the MySQL server to which to connect.
-		/// </summary>
+        /// <summary>
+        /// Gets the name of the MySQL server to which to connect.
+        /// </summary>
 #if !PocketPC
-		[Browsable(true)]
+        [Browsable(true)]
 #endif
-		public override string DataSource
-		{
-			get { return settings.Server; }
-		}
+        public override string DataSource
+        {
+            get { return settings.Server; }
+        }
 
-		/// <include file='docs/MySqlConnection.xml' path='docs/ConnectionTimeout/*'/>
+        /// <include file='docs/MySqlConnection.xml' path='docs/ConnectionTimeout/*'/>
 #if !PocketPC
-		[Browsable(true)]
+        [Browsable(true)]
 #endif
-		public override int ConnectionTimeout
-		{
-			get { return (int)settings.ConnectionTimeout; }
-		}
+        public override int ConnectionTimeout
+        {
+            get { return (int)settings.ConnectionTimeout; }
+        }
 
-		/// <include file='docs/MySqlConnection.xml' path='docs/Database/*'/>
+        /// <include file='docs/MySqlConnection.xml' path='docs/Database/*'/>
 #if !PocketPC
-		[Browsable(true)]
+        [Browsable(true)]
 #endif
-		public override string Database
-		{
-			get { return settings.Database; }
-		}
+        public override string Database
+        {
+            get { return settings.Database; }
+        }
 
-		/// <summary>
-		/// Indicates if this connection should use compression when communicating with the server.
-		/// </summary>
+        /// <summary>
+        /// Indicates if this connection should use compression when communicating with the server.
+        /// </summary>
 #if !PocketPC
-		[Browsable(false)]
+        [Browsable(false)]
 #endif
-		public bool UseCompression
-		{
-			get { return settings.UseCompression; }
-		}
+        public bool UseCompression
+        {
+            get { return settings.UseCompression; }
+        }
 
-		/// <include file='docs/MySqlConnection.xml' path='docs/State/*'/>
+        /// <include file='docs/MySqlConnection.xml' path='docs/State/*'/>
 #if !PocketPC
-		[Browsable(false)]
+        [Browsable(false)]
 #endif
-		public override ConnectionState State
-		{
-			get { return connectionState; }
-		}
+        public override ConnectionState State
+        {
+            get { return connectionState; }
+        }
 
-		/// <include file='docs/MySqlConnection.xml' path='docs/ServerVersion/*'/>
+        /// <include file='docs/MySqlConnection.xml' path='docs/ServerVersion/*'/>
 #if !PocketPC
-		[Browsable(false)]
+        [Browsable(false)]
 #endif
-		public override string ServerVersion
-		{
-			get { return driver.Version.ToString(); }
-		}
+        public override string ServerVersion
+        {
+            get { return driver.Version.ToString(); }
+        }
 
-		internal Encoding Encoding
-		{
-			get
-			{
-				if (driver == null)
-					return System.Text.Encoding.Default;
-				else
-					return driver.Encoding;
-			}
-		}
+        internal Encoding Encoding
+        {
+            get
+            {
+                if (driver == null)
+                    return System.Text.Encoding.Default;
+                else
+                    return driver.Encoding;
+            }
+        }
 
 
-		/// <include file='docs/MySqlConnection.xml' path='docs/ConnectionString/*'/>
+        /// <include file='docs/MySqlConnection.xml' path='docs/ConnectionString/*'/>
 #if !PocketPC
-		[Editor("MySql.Data.MySqlClient.Design.ConnectionStringTypeEditor,MySqlClient.Design", typeof(System.Drawing.Design.UITypeEditor))]
-		[Browsable(true)]
-		[Category("Data")]
-		[Description("Information used to connect to a DataSource, such as 'Server=xxx;UserId=yyy;Password=zzz;Database=dbdb'.")]
+        [Editor("MySql.Data.MySqlClient.Design.ConnectionStringTypeEditor,MySqlClient.Design", typeof(System.Drawing.Design.UITypeEditor))]
+        [Browsable(true)]
+        [Category("Data")]
+        [Description("Information used to connect to a DataSource, such as 'Server=xxx;UserId=yyy;Password=zzz;Database=dbdb'.")]
 #endif
-		public override string ConnectionString
-		{
-			get
-			{
-				// Always return exactly what the user set.
-				// Security-sensitive information may be removed.
-				return settings.GetConnectionString(!hasBeenOpen || settings.PersistSecurityInfo);
-			}
-			set
-			{
-				if (this.State != ConnectionState.Closed)
-					throw new MySqlException("Not allowed to change the 'ConnectionString' property while the connection (state=" + State + ").");
+        public override string ConnectionString
+        {
+            get
+            {
+                // Always return exactly what the user set.
+                // Security-sensitive information may be removed.
+                return settings.GetConnectionString(!hasBeenOpen || settings.PersistSecurityInfo);
+            }
+            set
+            {
+                if (this.State != ConnectionState.Closed)
+                    throw new MySqlException("Not allowed to change the 'ConnectionString' property while the connection (state=" + State + ").");
 
-				try
-				{
-					MySqlConnectionStringBuilder newSettings =
-						 new MySqlConnectionStringBuilder(value);
-					settings = newSettings;
-					if (driver != null)
-						driver.Settings = newSettings;
-					//TODO: what happens if we are in a pool
-				}
-				catch (Exception)
-				{
-					throw;
-				}
-			}
-		}
+                MySqlConnectionStringBuilder newSettings = 
+                    (MySqlConnectionStringBuilder)connectionStringCache[value];
 
-		#endregion
+                if (null == newSettings) //!globalConnectionStringCache.TryGetValue(value, out newSettings))
+                {
+                    lock (connectionStringCache)
+                    {
+                        newSettings = new MySqlConnectionStringBuilder(value);
+                        connectionStringCache.Add(value, newSettings);
+                    }
+                }
 
-		#region Transactions
+                settings = newSettings;
+                if (driver != null)
+                    driver.Settings = newSettings;
+            }
+        }
 
+        #endregion
+
+        #region Transactions
+
 #if !MONO
-		/// <summary>
-		/// Enlists in the specified transaction. 
-		/// </summary>
-		/// <param name="transaction">
-		/// A reference to an existing <see cref="System.Transactions.Transaction"/> in which to enlist.
-		/// </param>
-		public override void EnlistTransaction(System.Transactions.Transaction transaction)
-		{
-			if (currentTransaction != null)
-			{
-				if (currentTransaction.BaseTransaction == transaction)
-					return;
+        /// <summary>
+        /// Enlists in the specified transaction. 
+        /// </summary>
+        /// <param name="transaction">
+        /// A reference to an existing <see cref="System.Transactions.Transaction"/> in which to enlist.
+        /// </param>
+        public override void EnlistTransaction(System.Transactions.Transaction transaction)
+        {
+            if (currentTransaction != null)
+            {
+                if (currentTransaction.BaseTransaction == transaction)
+                    return;
 
-				throw new MySqlException("Already enlisted");
-			}
+                throw new MySqlException("Already enlisted");
+            }
 
-			currentTransaction = new MySqlPromotableTransaction(this, transaction);
-			transaction.EnlistPromotableSinglePhase(currentTransaction);
-		}
+            currentTransaction = new MySqlPromotableTransaction(this, transaction);
+            transaction.EnlistPromotableSinglePhase(currentTransaction);
+        }
 #endif
 
-		/// <include file='docs/MySqlConnection.xml' path='docs/BeginTransaction/*'/>
-		public new MySqlTransaction BeginTransaction()
-		{
-			return this.BeginTransaction(IsolationLevel.RepeatableRead);
-		}
+        /// <include file='docs/MySqlConnection.xml' path='docs/BeginTransaction/*'/>
+        public new MySqlTransaction BeginTransaction()
+        {
+            return this.BeginTransaction(IsolationLevel.RepeatableRead);
+        }
 
-		/// <include file='docs/MySqlConnection.xml' path='docs/BeginTransaction1/*'/>
-		public new MySqlTransaction BeginTransaction(IsolationLevel iso)
-		{
+        /// <include file='docs/MySqlConnection.xml' path='docs/BeginTransaction1/*'/>
+        public new MySqlTransaction BeginTransaction(IsolationLevel iso)
+        {
             // First check to see if we are in a current transaction
             if ((driver.ServerStatus & ServerStatusFlags.InTransaction) != 0)
                 throw new InvalidOperationException(Resources.NoNestedTransactions);
 
-			//TODO: check note in help
-			if (State != ConnectionState.Open)
-				throw new InvalidOperationException(Resources.ConnectionNotOpen);
+            //TODO: check note in help
+            if (State != ConnectionState.Open)
+                throw new InvalidOperationException(Resources.ConnectionNotOpen);
 
-			MySqlTransaction t = new MySqlTransaction(this, iso);
+            MySqlTransaction t = new MySqlTransaction(this, iso);
 
-			MySqlCommand cmd = new MySqlCommand("", this);
+            MySqlCommand cmd = new MySqlCommand("", this);
 
-			cmd.CommandText = "SET SESSION TRANSACTION ISOLATION LEVEL ";
-			switch (iso)
-			{
-				case IsolationLevel.ReadCommitted:
-					cmd.CommandText += "READ COMMITTED"; break;
-				case IsolationLevel.ReadUncommitted:
-					cmd.CommandText += "READ UNCOMMITTED"; break;
-				case IsolationLevel.RepeatableRead:
-					cmd.CommandText += "REPEATABLE READ"; break;
-				case IsolationLevel.Serializable:
-					cmd.CommandText += "SERIALIZABLE"; break;
-				case IsolationLevel.Chaos:
-					throw new NotSupportedException(Resources.ChaosNotSupported);
-			}
+            cmd.CommandText = "SET SESSION TRANSACTION ISOLATION LEVEL ";
+            switch (iso)
+            {
+                case IsolationLevel.ReadCommitted:
+                    cmd.CommandText += "READ COMMITTED"; break;
+                case IsolationLevel.ReadUncommitted:
+                    cmd.CommandText += "READ UNCOMMITTED"; break;
+                case IsolationLevel.RepeatableRead:
+                    cmd.CommandText += "REPEATABLE READ"; break;
+                case IsolationLevel.Serializable:
+                    cmd.CommandText += "SERIALIZABLE"; break;
+                case IsolationLevel.Chaos:
+                    throw new NotSupportedException(Resources.ChaosNotSupported);
+            }
 
-			cmd.ExecuteNonQuery();
+            cmd.ExecuteNonQuery();
 
-			cmd.CommandText = "BEGIN";
-			cmd.ExecuteNonQuery();
+            cmd.CommandText = "BEGIN";
+            cmd.ExecuteNonQuery();
 
-			return t;
-		}
+            return t;
+        }
 
-		#endregion
+        #endregion
 
-		/// <include file='docs/MySqlConnection.xml' path='docs/ChangeDatabase/*'/>
-		public override void ChangeDatabase(string database)
-		{
-			if (database == null || database.Trim().Length == 0)
-				throw new ArgumentException(Resources.ParameterIsInvalid, "database");
+        /// <include file='docs/MySqlConnection.xml' path='docs/ChangeDatabase/*'/>
+        public override void ChangeDatabase(string database)
+        {
+            if (database == null || database.Trim().Length == 0)
+                throw new ArgumentException(Resources.ParameterIsInvalid, "database");
 
-			if (State != ConnectionState.Open)
-				throw new InvalidOperationException(Resources.ConnectionNotOpen);
+            if (State != ConnectionState.Open)
+                throw new InvalidOperationException(Resources.ConnectionNotOpen);
 
-			driver.SetDatabase(database);
-			settings.Database = database;
-		}
+            driver.SetDatabase(database);
+            settings.Database = database;
+        }
 
-		internal void SetState(ConnectionState newConnectionState)
-		{
-			if (newConnectionState == this.connectionState)
-				return;
-			ConnectionState oldConnectionState = this.connectionState;
-			this.connectionState = newConnectionState;
-			this.OnStateChange(new StateChangeEventArgs(oldConnectionState, this.connectionState));
-		}
+        internal void SetState(ConnectionState newConnectionState)
+        {
+            if (newConnectionState == this.connectionState)
+                return;
+            ConnectionState oldConnectionState = this.connectionState;
+            this.connectionState = newConnectionState;
+            this.OnStateChange(new StateChangeEventArgs(oldConnectionState, this.connectionState));
+        }
 
-		/// <summary>
-		/// Ping
-		/// </summary>
-		/// <returns></returns>
-		public bool Ping()
-		{
-			bool result = driver.Ping();
-			if (!result)
-				SetState(ConnectionState.Closed);
-			return result;
-		}
+        /// <summary>
+        /// Ping
+        /// </summary>
+        /// <returns></returns>
+        public bool Ping()
+        {
+            bool result = driver.Ping();
+            if (!result)
+                SetState(ConnectionState.Closed);
+            return result;
+        }
 
-		/// <include file='docs/MySqlConnection.xml' path='docs/Open/*'/>
-		public override void Open()
-		{
-			if (State == ConnectionState.Open)
-				throw new InvalidOperationException(Resources.ConnectionAlreadyOpen);
+        /// <include file='docs/MySqlConnection.xml' path='docs/Open/*'/>
+        public override void Open()
+        {
+            if (State == ConnectionState.Open)
+                throw new InvalidOperationException(Resources.ConnectionAlreadyOpen);
 
-			SetState(ConnectionState.Connecting);
+            SetState(ConnectionState.Connecting);
 
-			try
-			{
-				if (settings.Pooling)
-				{
-					MySqlPool pool = MySqlPoolManager.GetPool(settings);
-					driver = pool.GetConnection();
-					procedureCache = pool.ProcedureCache;
-				}
-				else
-				{
-					driver = Driver.Create(settings);
-					procedureCache = new ProcedureCache(settings.ProcedureCacheSize);
-				}
-			}
-			catch (Exception)
-			{
-				SetState(ConnectionState.Closed);
-				throw;
-			}
+            try
+            {
+                if (settings.Pooling)
+                {
+                    MySqlPool pool = MySqlPoolManager.GetPool(settings);
+                    driver = pool.GetConnection();
+                    procedureCache = pool.ProcedureCache;
+                }
+                else
+                {
+                    driver = Driver.Create(settings);
+                    procedureCache = new ProcedureCache(settings.ProcedureCacheSize);
+                }
+            }
+            catch (Exception)
+            {
+                SetState(ConnectionState.Closed);
+                throw;
+            }
 
-			// if the user is using old syntax, let them know
-			if (driver.Settings.UseOldSyntax)
-				Logger.LogWarning("You are using old syntax that will be removed in future versions");
+            // if the user is using old syntax, let them know
+            if (driver.Settings.UseOldSyntax)
+                Logger.LogWarning("You are using old syntax that will be removed in future versions");
 
-			SetState(ConnectionState.Open);
-			driver.Configure(this);
-			if (settings.Database != null && settings.Database != String.Empty)
-				ChangeDatabase(settings.Database);
+            SetState(ConnectionState.Open);
+            driver.Configure(this);
+            if (settings.Database != null && settings.Database != String.Empty)
+                ChangeDatabase(settings.Database);
 
-			// setup our schema provider
-			if (driver.Version.isAtLeast(5, 0, 0))
-				schemaProvider = new ISSchemaProvider(this);
-			else
-				schemaProvider = new SchemaProvider(this);
-			perfMonitor = new PerformanceMonitor(this);
+            // setup our schema provider
+            if (driver.Version.isAtLeast(5, 0, 0))
+                schemaProvider = new ISSchemaProvider(this);
+            else
+                schemaProvider = new SchemaProvider(this);
+            perfMonitor = new PerformanceMonitor(this);
 
-			// if we are opening up inside a current transaction, then autoenlist
-			// TODO: control this with a connection string option
+            // if we are opening up inside a current transaction, then autoenlist
+            // TODO: control this with a connection string option
 #if !MONO
-			if (System.Transactions.Transaction.Current != null)
-				EnlistTransaction(System.Transactions.Transaction.Current);
+            if (System.Transactions.Transaction.Current != null)
+                EnlistTransaction(System.Transactions.Transaction.Current);
 #endif
 
-			hasBeenOpen = true;
-		}
+            hasBeenOpen = true;
+        }
 
-		/// <include file='docs/MySqlConnection.xml' path='docs/CreateCommand/*'/>
-		public new MySqlCommand CreateCommand()
-		{
-			// Return a new instance of a command object.
-			MySqlCommand c = new MySqlCommand();
-			c.Connection = this;
-			return c;
-		}
+        /// <include file='docs/MySqlConnection.xml' path='docs/CreateCommand/*'/>
+        public new MySqlCommand CreateCommand()
+        {
+            // Return a new instance of a command object.
+            MySqlCommand c = new MySqlCommand();
+            c.Connection = this;
+            return c;
+        }
 
-		#region ICloneable
-		/// <summary>
-		/// Creates a new MySqlConnection object with the exact same ConnectionString value
-		/// </summary>
-		/// <returns>A cloned MySqlConnection object</returns>
-		object ICloneable.Clone()
-		{
-			MySqlConnection clone = new MySqlConnection();
-			clone.ConnectionString = settings.GetConnectionString(true);
-			return clone;
-		}
-		#endregion
+        #region ICloneable
+        /// <summary>
+        /// Creates a new MySqlConnection object with the exact same ConnectionString value
+        /// </summary>
+        /// <returns>A cloned MySqlConnection object</returns>
+        object ICloneable.Clone()
+        {
+            MySqlConnection clone = new MySqlConnection();
+            clone.ConnectionString = settings.GetConnectionString(true);
+            return clone;
+        }
+        #endregion
 
-		#region IDisposeable
+        #region IDisposeable
 
-		protected override void Dispose(bool disposing)
-		{
-			if (disposing && State == ConnectionState.Open)
-				Close();
-			base.Dispose(disposing);
-		}
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && State == ConnectionState.Open)
+                Close();
+            base.Dispose(disposing);
+        }
 
-		#endregion
+        #endregion
 
-		protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
-		{
-			if (isolationLevel == IsolationLevel.Unspecified)
-				return BeginTransaction();
-			return BeginTransaction(isolationLevel);
-		}
+        protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
+        {
+            if (isolationLevel == IsolationLevel.Unspecified)
+                return BeginTransaction();
+            return BeginTransaction(isolationLevel);
+        }
 
-		protected override DbCommand CreateDbCommand()
-		{
-			return CreateCommand();
-		}
+        protected override DbCommand CreateDbCommand()
+        {
+            return CreateCommand();
+        }
 
-		internal void Abort()
-		{
-			try
-			{
-				if (settings.Pooling)
-					MySqlPoolManager.ReleaseConnection(driver);
-				else
-					driver.Close();
-			}
-			catch (Exception) { }
-			SetState(ConnectionState.Closed);
-		}
+        internal void Abort()
+        {
+            try
+            {
+                if (settings.Pooling)
+                    MySqlPoolManager.ReleaseConnection(driver);
+                else
+                    driver.Close();
+            }
+            catch (Exception) { }
+            SetState(ConnectionState.Closed);
+        }
 
-		/// <include file='docs/MySqlConnection.xml' path='docs/Close/*'/>
-		public override void Close()
-		{
-			//TODO: rollback any pending transaction
-			if (State == ConnectionState.Closed) return;
+        /// <include file='docs/MySqlConnection.xml' path='docs/Close/*'/>
+        public override void Close()
+        {
+            //TODO: rollback any pending transaction
+            if (State == ConnectionState.Closed) return;
 
-			if (dataReader != null)
-				dataReader.Close();
+            if (dataReader != null)
+                dataReader.Close();
 
             if ((driver.ServerStatus & ServerStatusFlags.InTransaction) != 0)
             {
@@ -483,13 +488,13 @@
                 t.Rollback();
             }
 
-			if (settings.Pooling)
-				MySqlPoolManager.ReleaseConnection(driver);
-			else
-				driver.Close();
+            if (settings.Pooling)
+                MySqlPoolManager.ReleaseConnection(driver);
+            else
+                driver.Close();
 
-			SetState(ConnectionState.Closed);
-		}
+            SetState(ConnectionState.Closed);
+        }
 
 #if MONO2
 
@@ -501,50 +506,50 @@
 
 #endif
 
-		#region GetSchema Support
+        #region GetSchema Support
 
-		/// <summary>
-		/// Returns schema information for the data source of this <see cref="DbConnection"/>. 
-		/// </summary>
-		/// <returns>A <see cref="DataTable"/> that contains schema information. </returns>
-		public override DataTable GetSchema()
-		{
-			return GetSchema(null);
-		}
+        /// <summary>
+        /// Returns schema information for the data source of this <see cref="DbConnection"/>. 
+        /// </summary>
+        /// <returns>A <see cref="DataTable"/> that contains schema information. </returns>
+        public override DataTable GetSchema()
+        {
+            return GetSchema(null);
+        }
 
-		/// <summary>
-		/// Returns schema information for the data source of this 
-		/// <see cref="DbConnection"/> using the specified string for the schema name. 
-		/// </summary>
-		/// <param name="collectionName">Specifies the name of the schema to return. </param>
-		/// <returns>A <see cref="DataTable"/> that contains schema information. </returns>
-		public override DataTable GetSchema(string collectionName)
-		{
-			if (collectionName == null)
-				collectionName = SchemaProvider.MetaCollection;
+        /// <summary>
+        /// Returns schema information for the data source of this 
+        /// <see cref="DbConnection"/> using the specified string for the schema name. 
+        /// </summary>
+        /// <param name="collectionName">Specifies the name of the schema to return. </param>
+        /// <returns>A <see cref="DataTable"/> that contains schema information. </returns>
+        public override DataTable GetSchema(string collectionName)
+        {
+            if (collectionName == null)
+                collectionName = SchemaProvider.MetaCollection;
 
-			return GetSchema(collectionName, null);
-		}
+            return GetSchema(collectionName, null);
+        }
 
-		/// <summary>
-		/// Returns schema information for the data source of this <see cref="DbConnection"/>
-		/// using the specified string for the schema name and the specified string array 
-		/// for the restriction values. 
-		/// </summary>
-		/// <param name="collectionName">Specifies the name of the schema to return.</param>
-		/// <param name="restrictionValues">Specifies a set of restriction values for the requested schema.</param>
-		/// <returns>A <see cref="DataTable"/> that contains schema information.</returns>
-		public override DataTable GetSchema(string collectionName, string[] restrictionValues)
-		{
-/*            string msg = String.Format("collection = {0}", collectionName);
-            foreach (string s in restrictionValues)
-            {
-                msg += String.Format(" res={0}", s);
-            }
-            MessageBox.Show(msg);
-  */
-			if (collectionName == null)
-				collectionName = SchemaProvider.MetaCollection;
+        /// <summary>
+        /// Returns schema information for the data source of this <see cref="DbConnection"/>
+        /// using the specified string for the schema name and the specified string array 
+        /// for the restriction values. 
+        /// </summary>
+        /// <param name="collectionName">Specifies the name of the schema to return.</param>
+        /// <param name="restrictionValues">Specifies a set of restriction values for the requested schema.</param>
+        /// <returns>A <see cref="DataTable"/> that contains schema information.</returns>
+        public override DataTable GetSchema(string collectionName, string[] restrictionValues)
+        {
+            /*            string msg = String.Format("collection = {0}", collectionName);
+                        foreach (string s in restrictionValues)
+                        {
+                            msg += String.Format(" res={0}", s);
+                        }
+                        MessageBox.Show(msg);
+              */
+            if (collectionName == null)
+                collectionName = SchemaProvider.MetaCollection;
 
             string[] restrictions = null;
             if (restrictionValues != null)
@@ -564,28 +569,28 @@
                 }
             }
 
-			DataTable dt = schemaProvider.GetSchema(collectionName, restrictions);
+            DataTable dt = schemaProvider.GetSchema(collectionName, restrictions);
             return dt;
-		}
+        }
 
-		#endregion
+        #endregion
 
-	}
+    }
 
-	/// <summary>
-	/// Represents the method that will handle the <see cref="MySqlConnection.InfoMessage"/> event of a 
-	/// <see cref="MySqlConnection"/>.
-	/// </summary>
-	public delegate void MySqlInfoMessageEventHandler(object sender, MySqlInfoMessageEventArgs args);
+    /// <summary>
+    /// Represents the method that will handle the <see cref="MySqlConnection.InfoMessage"/> event of a 
+    /// <see cref="MySqlConnection"/>.
+    /// </summary>
+    public delegate void MySqlInfoMessageEventHandler(object sender, MySqlInfoMessageEventArgs args);
 
-	/// <summary>
-	/// Provides data for the InfoMessage event. This class cannot be inherited.
-	/// </summary>
-	public class MySqlInfoMessageEventArgs : EventArgs
-	{
-		/// <summary>
-		/// 
-		/// </summary>
-		public MySqlError[] errors;
-	}
+    /// <summary>
+    /// Provides data for the InfoMessage event. This class cannot be inherited.
+    /// </summary>
+    public class MySqlInfoMessageEventArgs : EventArgs
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        public MySqlError[] errors;
+    }
 }

Added: branches/5.0/Driver/Source/common/Cache.cs
===================================================================
--- branches/5.0/Driver/Source/common/Cache.cs	2007-05-02 15:29:07 UTC (rev 700)
+++ branches/5.0/Driver/Source/common/Cache.cs	2007-05-02 20:54:10 UTC (rev 701)
@@ -0,0 +1,57 @@
+// Copyright (C) 2004-2007 MySQL AB
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation
+//
+// There are special exceptions to the terms and conditions of the GPL 
+// as it is applied to this software. View the full text of the 
+// exception in file EXCEPTIONS in the directory of this software 
+// distribution.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+
+using System.Collections.Specialized;
+
+namespace MySql.Data.Common
+{
+    internal class Cache : NameObjectCollectionBase
+    {
+        private int capacity;
+
+        public Cache(int initialCapacity, int capacity) : base(initialCapacity)
+        {
+            this.capacity = capacity;
+        }
+
+        public object this[string key]
+        {
+            get { return BaseGet(key); }
+            set { InternalAdd(key, value); }
+        }
+
+        public void Add(string key, object value)
+        {
+            InternalAdd(key, value);
+        }
+
+        private void InternalAdd(string key, object value)
+        {
+            if (base.Count == capacity)
+                RemoveOldestItem();
+            BaseAdd(key, value);
+        }
+
+        private void RemoveOldestItem()
+        {
+            BaseRemoveAt(0);
+        }
+    }
+}
\ No newline at end of file

Thread
Connector/NET commit: r701 - in branches/5.0: . Driver/Source Driver/Source/commonrburnett2 May