You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2011/11/13 15:18:06 UTC

svn commit: r1201430 - in /cayenne/main/branches/STABLE-3.0: docs/doc/src/main/resources/RELEASE-NOTES.txt framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/conn/PoolManager.java

Author: aadamchik
Date: Sun Nov 13 14:18:06 2011
New Revision: 1201430

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

porting from trunk

Modified:
    cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/conn/PoolManager.java

Modified: cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt?rev=1201430&r1=1201429&r2=1201430&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt (original)
+++ cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt Sun Nov 13 14:18:06 2011
@@ -20,6 +20,7 @@ CAY-1605 Switch Cayenne to use unified M
 Bug Fixes Since 3.0.2:
 
 CAY-1469 Modeler: dbRelationships renaming problem
+CAY-1513 Deadlock in PoolManager
 CAY-1514 ClassCastException when EJQLQuery parameters is null.
 CAY-1577 SQL queries for LIKE expressions with escape character generated with syntax errors
 CAY-1581 Not-Escaping <> during serialization to *.map.xml

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/conn/PoolManager.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/conn/PoolManager.java?rev=1201430&r1=1201429&r2=1201430&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/conn/PoolManager.java (original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/conn/PoolManager.java Sun Nov 13 14:18:06 2011
@@ -58,6 +58,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
@@ -169,37 +171,43 @@ public class PoolManager implements Data
     }
 
     /** Closes all existing connections, removes them from the pool. */
-    public void dispose() 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();
-            }
-        }
-
+    public synchronized void dispose() throws SQLException {
+        
+        // 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() {
         if (poolMaintenanceThread != null) {
             this.poolMaintenanceThread.dispose();
+			this.poolMaintenanceThread = null;
         }
     }
 
@@ -333,6 +341,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);
 
@@ -434,6 +446,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();
 
@@ -459,6 +476,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
 
@@ -506,14 +528,14 @@ public class PoolManager implements Data
                     // ignore...
                 }
 
-                if (shouldDie) {
-                    break;
-                }
-
                 synchronized (pool) {
                     // TODO: implement a smarter algorithm for pool management...
                     // right now it will simply close one connection if the count is
                     // above median and there are any idle connections.
+                    
+                    if (shouldDie) {
+                        break;
+                    }
 
                     int unused = pool.getCurrentlyUnused();
                     int used = pool.getCurrentlyInUse();