From: Date: May 2 2007 10:54pm Subject: Connector/NET commit: r701 - in branches/5.0: . Driver/Source Driver/Source/common List-Archive: http://lists.mysql.com/commits/25944 X-Bug: 28167 Message-Id: <200705022054.l42KsBPk026117@bk-internal.mysql.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 { - /// + /// #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; - /// - public event MySqlInfoMessageEventHandler InfoMessage; + /// + public event MySqlInfoMessageEventHandler InfoMessage; + private static Cache connectionStringCache = new Cache(0, 25); + #if MONO2 /// public event StateChangeEventHandler StateChange; #endif - /// - public MySqlConnection() - { - //TODO: add event data to StateChange docs - settings = new MySqlConnectionStringBuilder(); - advisor = new UsageAdvisor(this); - } + /// + public MySqlConnection() + { + //TODO: add event data to StateChange docs + settings = new MySqlConnectionStringBuilder(); + advisor = new UsageAdvisor(this); + } - /// - public MySqlConnection(string connectionString) - : this() - { - ConnectionString = connectionString; - } + /// + 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; } + } - /// - /// Returns the id of the server thread this connection is executing on - /// + /// + /// Returns the id of the server thread this connection is executing on + /// #if !PocketPC - [Browsable(false)] + [Browsable(false)] #endif - public int ServerThread - { - get { return driver.ThreadID; } - } + public int ServerThread + { + get { return driver.ThreadID; } + } - /// - /// Gets the name of the MySQL server to which to connect. - /// + /// + /// Gets the name of the MySQL server to which to connect. + /// #if !PocketPC - [Browsable(true)] + [Browsable(true)] #endif - public override string DataSource - { - get { return settings.Server; } - } + public override string DataSource + { + get { return settings.Server; } + } - /// + /// #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; } + } - /// + /// #if !PocketPC - [Browsable(true)] + [Browsable(true)] #endif - public override string Database - { - get { return settings.Database; } - } + public override string Database + { + get { return settings.Database; } + } - /// - /// Indicates if this connection should use compression when communicating with the server. - /// + /// + /// Indicates if this connection should use compression when communicating with the server. + /// #if !PocketPC - [Browsable(false)] + [Browsable(false)] #endif - public bool UseCompression - { - get { return settings.UseCompression; } - } + public bool UseCompression + { + get { return settings.UseCompression; } + } - /// + /// #if !PocketPC - [Browsable(false)] + [Browsable(false)] #endif - public override ConnectionState State - { - get { return connectionState; } - } + public override ConnectionState State + { + get { return connectionState; } + } - /// + /// #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; + } + } - /// + /// #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 - /// - /// Enlists in the specified transaction. - /// - /// - /// A reference to an existing in which to enlist. - /// - public override void EnlistTransaction(System.Transactions.Transaction transaction) - { - if (currentTransaction != null) - { - if (currentTransaction.BaseTransaction == transaction) - return; + /// + /// Enlists in the specified transaction. + /// + /// + /// A reference to an existing in which to enlist. + /// + 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 - /// - public new MySqlTransaction BeginTransaction() - { - return this.BeginTransaction(IsolationLevel.RepeatableRead); - } + /// + public new MySqlTransaction BeginTransaction() + { + return this.BeginTransaction(IsolationLevel.RepeatableRead); + } - /// - public new MySqlTransaction BeginTransaction(IsolationLevel iso) - { + /// + 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 - /// - public override void ChangeDatabase(string database) - { - if (database == null || database.Trim().Length == 0) - throw new ArgumentException(Resources.ParameterIsInvalid, "database"); + /// + 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)); + } - /// - /// Ping - /// - /// - public bool Ping() - { - bool result = driver.Ping(); - if (!result) - SetState(ConnectionState.Closed); - return result; - } + /// + /// Ping + /// + /// + public bool Ping() + { + bool result = driver.Ping(); + if (!result) + SetState(ConnectionState.Closed); + return result; + } - /// - public override void Open() - { - if (State == ConnectionState.Open) - throw new InvalidOperationException(Resources.ConnectionAlreadyOpen); + /// + 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; + } - /// - public new MySqlCommand CreateCommand() - { - // Return a new instance of a command object. - MySqlCommand c = new MySqlCommand(); - c.Connection = this; - return c; - } + /// + public new MySqlCommand CreateCommand() + { + // Return a new instance of a command object. + MySqlCommand c = new MySqlCommand(); + c.Connection = this; + return c; + } - #region ICloneable - /// - /// Creates a new MySqlConnection object with the exact same ConnectionString value - /// - /// A cloned MySqlConnection object - object ICloneable.Clone() - { - MySqlConnection clone = new MySqlConnection(); - clone.ConnectionString = settings.GetConnectionString(true); - return clone; - } - #endregion + #region ICloneable + /// + /// Creates a new MySqlConnection object with the exact same ConnectionString value + /// + /// A cloned MySqlConnection object + 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); + } - /// - public override void Close() - { - //TODO: rollback any pending transaction - if (State == ConnectionState.Closed) return; + /// + 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 - /// - /// Returns schema information for the data source of this . - /// - /// A that contains schema information. - public override DataTable GetSchema() - { - return GetSchema(null); - } + /// + /// Returns schema information for the data source of this . + /// + /// A that contains schema information. + public override DataTable GetSchema() + { + return GetSchema(null); + } - /// - /// Returns schema information for the data source of this - /// using the specified string for the schema name. - /// - /// Specifies the name of the schema to return. - /// A that contains schema information. - public override DataTable GetSchema(string collectionName) - { - if (collectionName == null) - collectionName = SchemaProvider.MetaCollection; + /// + /// Returns schema information for the data source of this + /// using the specified string for the schema name. + /// + /// Specifies the name of the schema to return. + /// A that contains schema information. + public override DataTable GetSchema(string collectionName) + { + if (collectionName == null) + collectionName = SchemaProvider.MetaCollection; - return GetSchema(collectionName, null); - } + return GetSchema(collectionName, null); + } - /// - /// Returns schema information for the data source of this - /// using the specified string for the schema name and the specified string array - /// for the restriction values. - /// - /// Specifies the name of the schema to return. - /// Specifies a set of restriction values for the requested schema. - /// A that contains schema information. - 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; + /// + /// Returns schema information for the data source of this + /// using the specified string for the schema name and the specified string array + /// for the restriction values. + /// + /// Specifies the name of the schema to return. + /// Specifies a set of restriction values for the requested schema. + /// A that contains schema information. + 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 - } + } - /// - /// Represents the method that will handle the event of a - /// . - /// - public delegate void MySqlInfoMessageEventHandler(object sender, MySqlInfoMessageEventArgs args); + /// + /// Represents the method that will handle the event of a + /// . + /// + public delegate void MySqlInfoMessageEventHandler(object sender, MySqlInfoMessageEventArgs args); - /// - /// Provides data for the InfoMessage event. This class cannot be inherited. - /// - public class MySqlInfoMessageEventArgs : EventArgs - { - /// - /// - /// - public MySqlError[] errors; - } + /// + /// Provides data for the InfoMessage event. This class cannot be inherited. + /// + public class MySqlInfoMessageEventArgs : EventArgs + { + /// + /// + /// + 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