List:Commits« Previous MessageNext Message »
From:rburnett Date:May 7 2008 3:47pm
Subject:Connector/NET commit: r1282 - in branches/5.2: . MySql.Data/Provider MySql.Data/Provider/Source
View as plain text  
Modified:
   branches/5.2/CHANGES
   branches/5.2/MySql.Data/Provider/MySql.Data.CF.csproj
   branches/5.2/MySql.Data/Provider/MySql.Data.csproj
   branches/5.2/MySql.Data/Provider/Source/MySqlPool.cs
   branches/5.2/MySql.Data/Provider/Source/MySqlPoolManager.cs
Log:
Removed some unnecessary locking from the pool manager and also reworked the pooling code
to not use a semaphore (bug #34001)


Modified: branches/5.2/CHANGES
===================================================================
--- branches/5.2/CHANGES	2008-05-07 13:44:05 UTC (rev 1281)
+++ branches/5.2/CHANGES	2008-05-07 13:47:00 UTC (rev 1282)
@@ -22,6 +22,9 @@
 - The procedure parameters schema collection has been altered to match what is coming
   with MySQL 6.0.  Some fields have been removed and others combined.  Please review
   your application for incompatibilities.
+- Removed some unnecessary locking from the pool manager and also reworked the pooling
+  code to not use a semaphore (bug #34001)
+
     
 Version 5.2.1 - 2/27/2008
 - Tons of fixes in providers.  The actually work now.  :)

Modified: branches/5.2/MySql.Data/Provider/MySql.Data.CF.csproj
===================================================================
--- branches/5.2/MySql.Data/Provider/MySql.Data.CF.csproj	2008-05-07 13:44:05 UTC (rev
1281)
+++ branches/5.2/MySql.Data/Provider/MySql.Data.CF.csproj	2008-05-07 13:47:00 UTC (rev
1282)
@@ -63,7 +63,6 @@
     <Compile Include="Source\base\DbConnectionStringBuilder.cs" />
     <Compile Include="Source\base\DbException.cs" />
     <Compile Include="Source\cf\BufferedStream.cs" />
-    <Compile Include="Source\cf\Semaphore.cs" />
     <Compile Include="Source\cf\WinCE.cs" />
     <Compile Include="Source\CharSetMap.cs" />
     <Compile Include="Source\command.cs">

Modified: branches/5.2/MySql.Data/Provider/MySql.Data.csproj
===================================================================
--- branches/5.2/MySql.Data/Provider/MySql.Data.csproj	2008-05-07 13:44:05 UTC (rev 1281)
+++ branches/5.2/MySql.Data/Provider/MySql.Data.csproj	2008-05-07 13:47:00 UTC (rev 1282)
@@ -221,7 +221,6 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Properties\Resources.Designer.cs" />
-    <Compile Include="Source\cf\Semaphore.cs" />
     <Compile Include="Source\common\Cache.cs" />
     <Compile Include="Source\common\SqlTokenizer.cs" />
     <Compile Include="Source\BulkLoader.cs" />

Modified: branches/5.2/MySql.Data/Provider/Source/MySqlPool.cs
===================================================================
--- branches/5.2/MySql.Data/Provider/Source/MySqlPool.cs	2008-05-07 13:44:05 UTC (rev
1281)
+++ branches/5.2/MySql.Data/Provider/Source/MySqlPool.cs	2008-05-07 13:47:00 UTC (rev
1282)
@@ -20,12 +20,9 @@
 
 using System;
 using System.Collections;
-using System.Threading;
 using System.Collections.Generic;
 using System.Diagnostics;
-#if CF
-using MySql.Data.Common;
-#endif
+using System.Threading;
 
 namespace MySql.Data.MySqlClient
 {
@@ -46,13 +43,18 @@
 		private uint maxSize;
         private ProcedureCache procedureCache;
         private Object lockObject;
-        private Semaphore poolGate;
         private bool beingCleared;
+        private int available;
+        private AutoResetEvent autoEvent;
 
 		public MySqlPool(MySqlConnectionStringBuilder settings)
 		{
 			minSize = settings.MinimumPoolSize;
 			maxSize = settings.MaximumPoolSize;
+
+            available = (int)maxSize;
+            autoEvent = new AutoResetEvent(false);
+
             if (minSize > maxSize)
                 minSize = maxSize;
 			this.settings = settings;
@@ -69,7 +71,6 @@
                 idlePool.Enqueue(CreateNewPooledConnection());
 
             procedureCache = new ProcedureCache((int)settings.ProcedureCacheSize);
-            poolGate = new Semaphore((int)maxSize, (int)maxSize);
 
             // we don't really need to create this but it makes the code a bit cleaner
             lockObject = new Object();
@@ -165,6 +166,8 @@
         /// </summary>
 		private Driver CreateNewPooledConnection()
 		{
+            Debug.Assert((maxSize - NumConnections) > 0, "Pool out of sync.");
+
             Driver driver = Driver.Create(settings);
             driver.Pool = this;
             return driver;
@@ -185,9 +188,8 @@
                 else
                     idlePool.Enqueue(driver);
 
-                // we now either have a connection available or have room to make
-                // one so we release one slot in our semaphore
-                poolGate.Release();
+                Interlocked.Increment(ref available);
+                autoEvent.Set();
             }
         }
 
@@ -205,7 +207,8 @@
                 if (inUsePool.Contains(driver))
                 {
                     inUsePool.Remove(driver);
-                    poolGate.Release();
+                    Interlocked.Increment(ref available);
+                    autoEvent.Set();
                 }
 
                 // if we are being cleared and we are out of connections then have
@@ -215,32 +218,45 @@
             }
         }
 
+        private Driver TryToGetDriver()
+        {
+            int count = Interlocked.Decrement(ref available);
+            if (count < 0)
+            {
+                Interlocked.Increment(ref available);
+                return null;
+            }
+            try
+            {
+                Driver driver = GetPooledConnection();
+                return driver;
+            }
+            catch (Exception ex)
+            {
+                if (settings.Logging)
+                    Logger.LogException(ex);
+                Interlocked.Increment(ref available);
+                throw;
+            }
+        }
+
 		public Driver GetConnection() 
 		{
-			int ticks = (int)settings.ConnectionTimeout * 1000;
+			int fullTimeOut = (int)settings.ConnectionTimeout * 1000;
+            int timeOut = fullTimeOut;
 
-            // wait till we are allowed in
-            bool allowed = poolGate.WaitOne(ticks, false);
-            if (! allowed)
-                throw new MySqlException(Resources.TimeoutGettingConnection);
+            DateTime start = DateTime.Now;
 
-            // if we get here, then it means that we either have an idle connection
-            // or room to make a new connection
-            lock (lockObject)
+            while (timeOut > 0)
             {
-                try
-                {
-                    Driver d = GetPooledConnection();
-                    return d;
-                }
-                catch (Exception ex)
-                {
-                    if (settings.Logging)
-                        Logger.LogException(ex);
-                    poolGate.Release();
-                    throw;
-                }
+                Driver driver = TryToGetDriver();
+                if (driver != null) return driver;
+
+                // We have no tickets right now, lets wait for one.
+                if (!autoEvent.WaitOne(timeOut, false)) break;
+                timeOut = fullTimeOut -
(int)DateTime.Now.Subtract(start).TotalMilliseconds;
             }
+            throw new MySqlException(Resources.TimeoutGettingConnection);
 		}
 
         /// <summary>

Modified: branches/5.2/MySql.Data/Provider/Source/MySqlPoolManager.cs
===================================================================
--- branches/5.2/MySql.Data/Provider/Source/MySqlPoolManager.cs	2008-05-07 13:44:05 UTC
(rev 1281)
+++ branches/5.2/MySql.Data/Provider/Source/MySqlPoolManager.cs	2008-05-07 13:47:00 UTC
(rev 1282)
@@ -66,10 +66,7 @@
 			MySqlPool pool = driver.Pool;
 			if (pool == null) return;
 
-            lock (pools.SyncRoot)
-            {
-                pool.RemoveConnection(driver);
-            }
+            pool.RemoveConnection(driver);
         }
 
         public static void ReleaseConnection(Driver driver)
@@ -77,10 +74,7 @@
 			MySqlPool pool = driver.Pool;
 			if (pool == null) return;
 			
-			lock (pools.SyncRoot)
-            {
-                pool.ReleaseConnection(driver);
-            }
+            pool.ReleaseConnection(driver);
         }
 
         public static void ClearPool(MySqlConnectionStringBuilder settings)

Thread
Connector/NET commit: r1282 - in branches/5.2: . MySql.Data/Provider MySql.Data/Provider/Sourcerburnett7 May