You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by dk...@apache.org on 2011/10/10 17:49:30 UTC

svn commit: r1181036 - /cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/conn/PoolManager.java

Author: dkazimirchyk
Date: Mon Oct 10 15:49:30 2011
New Revision: 1181036

URL: http://svn.apache.org/viewvc?rev=1181036&view=rev
Log:
CAY-1513 Deadlock in PoolManager

using boolean variable to prevent any changes from outside instead of locking PoolManager instance during shutdown

Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/conn/PoolManager.java

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/conn/PoolManager.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/conn/PoolManager.java?rev=1181036&r1=1181035&r2=1181036&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/conn/PoolManager.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/conn/PoolManager.java Mon Oct 10 15:49:30 2011
@@ -59,6 +59,8 @@ public class PoolManager implements Data
     protected List<PooledConnection> usedPool;
 
     private PoolMaintenanceThread poolMaintenanceThread;
+    
+    private boolean shuttingDown;
 
     /**
      * Creates new PoolManager using org.apache.cayenne.conn.PoolDataSource for an
@@ -186,31 +188,36 @@ public class PoolManager implements Data
      */
     @BeforeScopeEnd
     public void shutdown() throws SQLException {
-        synchronized (this) {
-            // clean connections from the pool
-            ListIterator<PooledConnection> unusedIterator = unusedPool.listIterator();
-            while (unusedIterator.hasNext()) {
-                PooledConnection con = unusedIterator.next();
-                // close connection
-                con.close();
-                // remove connection from the list
-                unusedIterator.remove();
-            }
-
-            // clean used connections
-            ListIterator<PooledConnection> usedIterator = usedPool.listIterator();
-            while (usedIterator.hasNext()) {
-                PooledConnection con = usedIterator.next();
-                // stop listening for connection events
-                con.removeConnectionEventListener(this);
-                // close connection
-                con.close();
-                // remove connection from the list
-                usedIterator.remove();
-            }
-        }
-
+        
+        // disposing maintenance thread first to avoid any changes to pools
+        // during shutdown
         disposeOfMaintenanceThread();
+        
+        // using boolean variable instead of locking PoolManager instance due to
+        // possible deadlock during shutdown when one of connections locks its
+        // event listeners list trying to invoke locked PoolManager's listener methods 
+        shuttingDown = true;
+
+        ListIterator<PooledConnection> unusedIterator = unusedPool.listIterator();
+        while (unusedIterator.hasNext()) {
+            PooledConnection con = unusedIterator.next();
+            // close connection
+            con.close();
+            // remove connection from the list
+            unusedIterator.remove();
+        }
+
+        // clean used connections
+        ListIterator<PooledConnection> usedIterator = usedPool.listIterator();
+        while (usedIterator.hasNext()) {
+            PooledConnection con = usedIterator.next();
+            // stop listening for connection events
+            con.removeConnectionEventListener(this);
+            // close connection
+            con.close();
+            // remove connection from the list
+            usedIterator.remove();
+        }
     }
 
     protected void disposeOfMaintenanceThread() {
@@ -350,6 +357,10 @@ public class PoolManager implements Data
     /** Returns connection from the pool. */
     public synchronized Connection getConnection(String userName, String password)
             throws SQLException {
+        
+        if (shuttingDown) {
+            throw new SQLException("Pool manager is shutting down.");
+        }
 
         PooledConnection pooledConnection = uncheckPooledConnection(userName, password);
 
@@ -451,6 +462,11 @@ public class PoolManager implements Data
      * Returns closed connection to the pool.
      */
     public synchronized void connectionClosed(ConnectionEvent event) {
+        
+        if (shuttingDown) {
+            return;
+        }
+        
         // return connection to the pool
         PooledConnection closedConn = (PooledConnection) event.getSource();
 
@@ -476,6 +492,11 @@ public class PoolManager implements Data
      * is in invalid state.
      */
     public synchronized void connectionErrorOccurred(ConnectionEvent event) {
+        
+        if (shuttingDown) {
+            return;
+        }
+        
         // later on we should analyze the error to see if this
         // is fatal... right now just kill this PooledConnection