You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@manifoldcf.apache.org by kw...@apache.org on 2013/02/04 20:43:48 UTC

svn commit: r1442313 - in /manifoldcf/trunk: framework/core/src/main/java/org/apache/manifoldcf/core/database/ framework/core/src/main/java/org/apache/manifoldcf/core/jdbcpool/ framework/core/src/main/java/org/apache/manifoldcf/core/system/ site/src/do...

Author: kwright
Date: Mon Feb  4 19:43:48 2013
New Revision: 1442313

URL: http://svn.apache.org/viewvc?rev=1442313&view=rev
Log:
Change the logic so that connection tracking can be enabled by parameter.

Modified:
    manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/database/ConnectionFactory.java
    manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/jdbcpool/ConnectionPool.java
    manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/jdbcpool/ConnectionPoolManager.java
    manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/system/ManifoldCF.java
    manifoldcf/trunk/site/src/documentation/content/xdocs/en_US/how-to-build-and-deploy.xml
    manifoldcf/trunk/site/src/documentation/content/xdocs/ja_JP/how-to-build-and-deploy.xml

Modified: manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/database/ConnectionFactory.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/database/ConnectionFactory.java?rev=1442313&r1=1442312&r2=1442313&view=diff
==============================================================================
--- manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/database/ConnectionFactory.java (original)
+++ manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/database/ConnectionFactory.java Mon Feb  4 19:43:48 2013
@@ -179,6 +179,7 @@ public class ConnectionFactory
     }
 
     public ConnectionPoolManager createPoolManager()
+      throws ManifoldCFException
     {
       synchronized (poolExistenceLock)
       {

Modified: manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/jdbcpool/ConnectionPool.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/jdbcpool/ConnectionPool.java?rev=1442313&r1=1442312&r2=1442313&view=diff
==============================================================================
--- manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/jdbcpool/ConnectionPool.java (original)
+++ manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/jdbcpool/ConnectionPool.java Mon Feb  4 19:43:48 2013
@@ -30,22 +30,22 @@ public class ConnectionPool
 {
   public static final String _rcsid = "@(#)$Id$";
 
-  protected String dbURL;
-  protected String userName;
-  protected String password;
+  protected final String dbURL;
+  protected final String userName;
+  protected final String password;
   protected volatile int freePointer;
   protected volatile int activeConnections;
   protected volatile boolean closed;
-  protected Connection[] freeConnections;
-  protected long[] connectionCleanupTimeouts;
-  protected long expiration;
+  protected final Connection[] freeConnections;
+  protected final long[] connectionCleanupTimeouts;
+  protected final long expiration;
   
-  protected final static boolean debug = true;
+  protected final boolean debug;
   
-  protected List<WrappedConnection> outstandingConnections = new ArrayList<WrappedConnection>();
+  protected final Set<WrappedConnection> outstandingConnections = new HashSet<WrappedConnection>();
   
   /** Constructor */
-  public ConnectionPool(String dbURL, String userName, String password, int maxConnections, long expiration)
+  public ConnectionPool(String dbURL, String userName, String password, int maxConnections, long expiration, boolean debug)
   {
     this.dbURL = dbURL;
     this.userName = userName;
@@ -56,6 +56,7 @@ public class ConnectionPool
     this.activeConnections = 0;
     this.closed = false;
     this.expiration = expiration;
+    this.debug = debug;
   }
   
   /** Obtain a connection from the pool.
@@ -71,6 +72,7 @@ public class ConnectionPool
       instantiationException = new Exception("Possibly leaked db connection");
     else
       instantiationException = null;
+    Connection rval = null;
     while (true)
     {
       synchronized (this)
@@ -79,12 +81,9 @@ public class ConnectionPool
         {
           if (closed)
             throw new InterruptedException("Pool already closed");
-          Connection rval = freeConnections[--freePointer];
+          rval = freeConnections[--freePointer];
           freeConnections[freePointer] = null;
-          WrappedConnection rval3 = new WrappedConnection(this,rval,instantiationException);
-          if (debug)
-            outstandingConnections.add(rval3);
-          return rval3;
+          break;
         }
         if (activeConnections == freeConnections.length)
         {
@@ -92,9 +91,9 @@ public class ConnectionPool
           if (debug)
           {
             Logging.db.warn("Out of db connections, list of outstanding ones follows.");
-            for (int i = 0; i < outstandingConnections.size(); i++)
+            for (WrappedConnection c : outstandingConnections)
             {
-              Logging.db.warn("Found a possibly leaked db connection",outstandingConnections.get(i).getInstantiationException());
+              Logging.db.warn("Found a possibly leaked db connection",c.getInstantiationException());
             }
           }
           // Wait until kicked; we hope something will free up...
@@ -106,30 +105,58 @@ public class ConnectionPool
         break;
       }
     }
-    
-    // Create a new connection.  If we fail at this we need to restore the number of active connections, so catch any failures
-    Connection rval2 = null;
+
+    boolean returnedValue = true;
     try
     {
-      if (userName != null)
-        rval2 = DriverManager.getConnection(dbURL, userName, password);
-      else
-        rval2 = DriverManager.getConnection(dbURL);
+      if (rval == null)
+      {
+        if (userName != null)
+          rval = DriverManager.getConnection(dbURL, userName, password);
+        else
+          rval = DriverManager.getConnection(dbURL);
+      }
+
+      WrappedConnection wc = new WrappedConnection(this,rval,instantiationException);
+      if (debug)
+      {
+        synchronized (outstandingConnections)
+        {
+          outstandingConnections.add(wc);
+        }
+      }
+      return wc;
     }
-    finally
+    catch (Error e)
     {
-      if (rval2 == null)
-        activeConnections--;
+      returnedValue = false;
+      throw e;
     }
-    WrappedConnection rval4 = new WrappedConnection(this,rval2,instantiationException);
-    if (debug)
+    catch (RuntimeException e)
     {
-      synchronized (this)
+      returnedValue = false;
+      throw e;
+    }
+    catch (SQLException e)
+    {
+      returnedValue = false;
+      throw e;
+    }
+    finally
+    {
+      if (!returnedValue)
       {
-        outstandingConnections.add(rval4);
+        // We didn't finish.  Restore the pool to the correct form.
+        // Note: We should always be able to just return any current connection to the pool.  This is
+        // safe because we reserved a slot when we decided to create the connection (if that's what
+        // we did), or we just used a connection that was already allocated.  Either way, we can put
+        // it into the pool.
+        if (rval != null)
+        {
+          release(rval);
+        }
       }
     }
-    return rval4;
   }
   
   /** Close down the pool.
@@ -187,14 +214,30 @@ public class ConnectionPool
     }
   }
   
-  public synchronized void releaseConnection(WrappedConnection connection)
+  public void releaseConnection(WrappedConnection connection)
   {
-    freeConnections[freePointer] = connection.getConnection();
-    connectionCleanupTimeouts[freePointer] = System.currentTimeMillis() + expiration;
-    freePointer++;
+
     if (debug)
-      outstandingConnections.remove(connection);
-    notifyAll();
+    {
+      synchronized (outstandingConnections)
+      {
+        outstandingConnections.remove(connection);
+      }
+    }
+
+    release(connection.getConnection());
+  }
+  
+  protected void release(Connection c)
+  {
+    synchronized (this)
+    {
+      freeConnections[freePointer] = c;
+      connectionCleanupTimeouts[freePointer] = System.currentTimeMillis() + expiration;
+      freePointer++;
+      notifyAll();
+    }
+    
   }
   
 }

Modified: manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/jdbcpool/ConnectionPoolManager.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/jdbcpool/ConnectionPoolManager.java?rev=1442313&r1=1442312&r2=1442313&view=diff
==============================================================================
--- manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/jdbcpool/ConnectionPoolManager.java (original)
+++ manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/jdbcpool/ConnectionPoolManager.java Mon Feb  4 19:43:48 2013
@@ -23,18 +23,24 @@ import javax.sql.*;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import org.apache.manifoldcf.core.interfaces.ManifoldCFException;
+import org.apache.manifoldcf.core.system.ManifoldCF;
+
 /** An instance of this class manages a number of (independent) connection pools.
 */
 public class ConnectionPoolManager
 {
   public static final String _rcsid = "@(#)$Id$";
 
-  protected Map<String,ConnectionPool> poolMap;
-  protected ConnectionCloserThread connectionCloserThread;
+  protected final Map<String,ConnectionPool> poolMap;
+  protected final ConnectionCloserThread connectionCloserThread;
   protected volatile AtomicBoolean shuttingDown = new AtomicBoolean(false);
-
+  protected final boolean debug;
+  
   public ConnectionPoolManager(int count)
+    throws ManifoldCFException
   {
+    debug = ManifoldCF.getBooleanProperty(ManifoldCF.databaseConnectionTrackingProperty, false);
     poolMap = new HashMap<String,ConnectionPool>(count);
     connectionCloserThread = new ConnectionCloserThread();
     connectionCloserThread.start();
@@ -54,7 +60,7 @@ public class ConnectionPoolManager
     throws ClassNotFoundException, InstantiationException, IllegalAccessException
   {
     Class.forName(driverClassName).newInstance();
-    ConnectionPool cp = new ConnectionPool(dbURL,userName,password,maxSize,expiration);
+    ConnectionPool cp = new ConnectionPool(dbURL,userName,password,maxSize,expiration,debug);
     poolMap.put(poolKey,cp);
     return cp;
   }

Modified: manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/system/ManifoldCF.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/system/ManifoldCF.java?rev=1442313&r1=1442312&r2=1442313&view=diff
==============================================================================
--- manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/system/ManifoldCF.java (original)
+++ manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/system/ManifoldCF.java Mon Feb  4 19:43:48 2013
@@ -109,6 +109,8 @@ public class ManifoldCF
   public static final String databaseHandleMaxcountProperty = "org.apache.manifoldcf.database.maxhandles";
   /** Database handle timeout property */
   public static final String databaseHandleTimeoutProperty = "org.apache.manifoldcf.database.handletimeout";
+  /** Connection tracking debug property */
+  public static final String databaseConnectionTrackingProperty = "org.apache.manifoldcf.database.connectiontracking";
 
   // Database performance monitoring properties
   /** Elapsed time a query can take before a warning is output to the log, in seconds */

Modified: manifoldcf/trunk/site/src/documentation/content/xdocs/en_US/how-to-build-and-deploy.xml
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/site/src/documentation/content/xdocs/en_US/how-to-build-and-deploy.xml?rev=1442313&r1=1442312&r2=1442313&view=diff
==============================================================================
--- manifoldcf/trunk/site/src/documentation/content/xdocs/en_US/how-to-build-and-deploy.xml (original)
+++ manifoldcf/trunk/site/src/documentation/content/xdocs/en_US/how-to-build-and-deploy.xml Mon Feb  4 19:43:48 2013
@@ -801,6 +801,7 @@ cd example
             <tr><td>org.apache.manifoldcf.synchdirectory</td><td>Yes, if file-based synchronization class is used</td><td>Specifies the path of a synchronization directory.  All ManifoldCF process owners <strong>must</strong> have read/write privileges to this directory.</td></tr>
             <tr><td>org.apache.manifoldcf.database.maxhandles</td><td>No</td><td>Specifies the maximum number of database connection handles that will by pooled.  Recommended value is 200.</td></tr>
             <tr><td>org.apache.manifoldcf.database.handletimeout</td><td>No</td><td>Specifies the maximum time a handle is to live before it is presumed dead.  Recommend a value of 604800, which is the maximum allowable.</td></tr>
+            <tr><td>org.apache.manifoldcf.database.connectiontracking</td><td>No</td><td>True or false.  When "true", will track all allocated database connection handles, and will dump an allocation stack trace when the pool is exhausted.  Useful for diagnosing connection leaks.</td></tr>
             <tr><td>org.apache.manifoldcf.logconfigfile</td><td>No</td><td>Specifies location of logging configuration file.</td></tr>
             <tr><td>org.apache.manifoldcf.database.name</td><td>No</td><td>Describes database name for ManifoldCF; defaults to "dbname" if not specified.</td></tr>
             <tr><td>org.apache.manifoldcf.database.username</td><td>No</td><td>Describes database user name for ManifoldCF; defaults to "manifoldcf" if not specified.</td></tr>

Modified: manifoldcf/trunk/site/src/documentation/content/xdocs/ja_JP/how-to-build-and-deploy.xml
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/site/src/documentation/content/xdocs/ja_JP/how-to-build-and-deploy.xml?rev=1442313&r1=1442312&r2=1442313&view=diff
==============================================================================
--- manifoldcf/trunk/site/src/documentation/content/xdocs/ja_JP/how-to-build-and-deploy.xml (original)
+++ manifoldcf/trunk/site/src/documentation/content/xdocs/ja_JP/how-to-build-and-deploy.xml Mon Feb  4 19:43:48 2013
@@ -801,6 +801,7 @@ cd example
             <tr><td>org.apache.manifoldcf.synchdirectory</td><td>Yes, if file-based synchronization class is used</td><td>Specifies the path of a synchronization directory.  All ManifoldCF process owners <strong>must</strong> have read/write privileges to this directory.</td></tr>
             <tr><td>org.apache.manifoldcf.database.maxhandles</td><td>No</td><td>Specifies the maximum number of database connection handles that will by pooled.  Recommended value is 200.</td></tr>
             <tr><td>org.apache.manifoldcf.database.handletimeout</td><td>No</td><td>Specifies the maximum time a handle is to live before it is presumed dead.  Recommend a value of 604800, which is the maximum allowable.</td></tr>
+            <tr><td>org.apache.manifoldcf.database.connectiontracking</td><td>No</td><td>True or false.  When "true", will track all allocated database connection handles, and will dump an allocation stack trace when the pool is exhausted.  Useful for diagnosing connection leaks.</td></tr>
             <tr><td>org.apache.manifoldcf.logconfigfile</td><td>No</td><td>Specifies location of logging configuration file.</td></tr>
             <tr><td>org.apache.manifoldcf.database.name</td><td>No</td><td>Describes database name for ManifoldCF; defaults to "dbname" if not specified.</td></tr>
             <tr><td>org.apache.manifoldcf.database.username</td><td>No</td><td>Describes database user name for ManifoldCF; defaults to "manifoldcf" if not specified.</td></tr>