Add in Linux special case for performance optimization around locking.
authorfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Fri, 24 Jul 2009 15:24:52 +0000 (15:24 +0000)
committerfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Fri, 24 Jul 2009 15:24:52 +0000 (15:24 +0000)
Set default queue to be the fair one
Remove unused code

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@797528 13f79535-47bb-0310-9956-ffa450edef68

modules/jdbc-pool/doc/jdbc-pool.xml
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/FairBlockingQueue.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java

index 800d896..45821c6 100644 (file)
     <attribute name="fairQueue" required="false">
       <p>(boolean) Set to true if you wish that calls to getConnection should be treated
          fairly in a true FIFO fashion. This uses the <code>org.apache.tomcat.jdbc.pool.FairBlockingQueue</code> 
-         implementation for the list of the idle connections. The default value is <code>false</code>.
+         implementation for the list of the idle connections. The default value is <code>true</code>.
          This flag is required when you want to use asynchronous connection retrieval.<br/>
-         During performance tests, the fairQueue does very well on a multi core Solaris system,
-         but performs terribly on a Linux Fedora 11 system. On Linux we recommend setting this to false. 
+         Setting this flag ensures that threads receive connections in the order they arrive.<br/>
+         During performance tests, there is a very large difference in how locks
+         and lock waiting is implemented. When <code>fairQueue=true></code>
+         there is a decision making process based on what operating system the system is running.
+         If the system is running on Linux (property <code>os.name=Linux</code>.
+         To disable this Linux specific behavior and still use the fair queue, simply add the property
+         <code>org.apache.tomcat.jdbc.pool.FairBlockingQueue.ignoreOS=true</code> to your system properties
+         before the connection pool classes are loaded.
       </p>
     </attribute>
 
index 9250dac..948034e 100644 (file)
@@ -148,6 +148,9 @@ public class ConnectionPool {
         if (idle instanceof FairBlockingQueue) {
             Future<PooledConnection> pcf = ((FairBlockingQueue<PooledConnection>)idle).pollAsync();
             return new ConnectionFuture(pcf);
+        } else if (idle instanceof MultiLockFairBlockingQueue) {
+                Future<PooledConnection> pcf = ((MultiLockFairBlockingQueue<PooledConnection>)idle).pollAsync();
+                return new ConnectionFuture(pcf);
         } else {
             throw new SQLException("Connection pool is misconfigured, doesn't support async retrieval. Set the 'fair' property to 'true'");
         }
@@ -306,21 +309,6 @@ public class ConnectionPool {
     }
 
     /**
-     * If the connection pool gets garbage collected, lets make sure we clean up
-     * and close all the connections.
-     * {@inheritDoc}
-     */
-    @Override
-    protected void finalize() throws Throwable {
-//        Runnable closer = new Runnable() {
-//            public void run() {
-//                close(true);
-//            }
-//        };
-//        this.cancellator.execute(closer);
-    }
-
-    /**
      * Closes the pool and all disconnects all idle connections
      * Active connections will be closed upon the {@link java.sql.Connection#close close} method is called
      * on the underlying connection instead of being returned to the pool
@@ -381,6 +369,7 @@ public class ConnectionPool {
         //make space for 10 extra in case we flow over a bit
         if (properties.isFairQueue()) {
             idle = new FairBlockingQueue<PooledConnection>();
+            //idle = new MultiLockFairBlockingQueue<PooledConnection>();
         } else {
             idle = new ArrayBlockingQueue<PooledConnection>(properties.getMaxActive(),properties.isFairQueue());
         }
index 12d94d5..3c1934c 100644 (file)
@@ -155,17 +155,6 @@ public class DataSourceProxy implements PoolConfiguration {
         }
     }
 
-    protected void finalize() throws Throwable {
-//        //terminate the pool?
-//        ThreadPoolExecutor closer = new ThreadPoolExecutor(0,1,1000,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
-//        final Runnable r = new Runnable() {
-//            public void run(){ 
-//                close(true);                
-//            }
-//        };
-//        closer.execute(r);
-    }
-
     public int getPoolSize() throws SQLException{
         final ConnectionPool p = pool;
         if (p == null) return 0;
index 74a3ca2..992e80a 100644 (file)
@@ -43,6 +43,20 @@ import java.util.concurrent.locks.ReentrantLock;
 public class FairBlockingQueue<E> implements BlockingQueue<E> {
     
     /**
+     * This little sucker is used to reorder the way to do 
+     * {@link java.util.concurrent.locks.Lock#lock()},
+     * {@link java.util.concurrent.locks.Lock#unlock()}
+     * and 
+     * {@link java.util.concurrent.CountDownLatch#countDown()}
+     * during the {@link #poll(long, TimeUnit)} operation.
+     * On Linux, it performs much better if we count down while we hold the global
+     * lock, on Solaris its the other way around.
+     * Until we have tested other platforms we only check for Linux.
+     */
+    final static boolean isLinux = "Linux".equals(System.getProperty("os.name")) &&
+                                   (!Boolean.getBoolean(FairBlockingQueue.class.getName()+".ignoreOS"));
+    
+    /**
      * Phase one entry lock in order to give out 
      * per-thread-locks for the waiting phase we have 
      * a phase one lock during the contention period.
@@ -86,6 +100,7 @@ public class FairBlockingQueue<E> implements BlockingQueue<E> {
                 c = waiters.poll();
                 //give the object to the thread instead of adding it to the pool
                 c.setItem(e);
+                if (isLinux && c!=null) c.countDown();
             } else {
                 //we always add first, so that the most recently used object will be given out
                 items.addFirst(e);
@@ -94,7 +109,7 @@ public class FairBlockingQueue<E> implements BlockingQueue<E> {
             lock.unlock();
         }
         //if we exchanged an object with another thread, wake it up.
-        if (c!=null) c.countDown();
+        if (!isLinux && c!=null) c.countDown();
         //we have an unbounded queue, so always return true
         return true;
     }
@@ -261,6 +276,7 @@ public class FairBlockingQueue<E> implements BlockingQueue<E> {
      * {@inheritDoc}
      * @throws UnsupportedOperation - this operation is not supported
      */
+    
     public int drainTo(Collection<? super E> c) {
         return drainTo(c,Integer.MAX_VALUE);
     }
index 9673562..667ae62 100644 (file)
@@ -65,7 +65,7 @@ public interface PoolConfiguration {
      * Set to true if you wish that calls to getConnection 
      * should be treated fairly in a true FIFO fashion. 
      * This uses the {@link FairBlockingQueue} implementation for the list of the idle connections. 
-     * The default value is false. 
+     * The default value is true. 
      * This flag is required when you want to use asynchronous connection retrieval.
      * @param fairQueue
      */
index a43461e..73ef6ef 100644 (file)
@@ -68,7 +68,7 @@ public class PoolProperties implements PoolConfiguration {
     protected String initSQL;
     protected boolean testOnConnect =false;
     protected String jdbcInterceptors=null;
-    protected boolean fairQueue = false;
+    protected boolean fairQueue = true;
     protected boolean useEquals = false;
     protected int abandonWhenPercentageFull = 0;
     protected long maxAge = 0;