From e75c4295de15e2e8a9825b8e21008bde08b761b0 Mon Sep 17 00:00:00 2001 From: Robin Kupper Date: Sun, 26 Jun 2011 20:30:26 +0200 Subject: [PATCH] Fixed deadlock in connection pool. --- src/de/diddiz/LogBlock/LogBlock.java | 3 +- src/de/diddiz/util/MySQLConnectionPool.java | 53 +++++++++++++-------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/de/diddiz/LogBlock/LogBlock.java b/src/de/diddiz/LogBlock/LogBlock.java index 286dfcb..0f95e9a 100644 --- a/src/de/diddiz/LogBlock/LogBlock.java +++ b/src/de/diddiz/LogBlock/LogBlock.java @@ -4,7 +4,6 @@ import static de.diddiz.util.Utils.downloadIfNotExists; import java.io.File; import java.net.URL; import java.sql.Connection; -import java.sql.SQLException; import java.util.HashMap; import java.util.Map; import java.util.Timer; @@ -181,7 +180,7 @@ public class LogBlock extends JavaPlugin public Connection getConnection() { try { return pool.getConnection(); - } catch (final SQLException ex) { + } catch (final Exception ex) { log.log(Level.SEVERE, "[LogBlock] Error while fetching connection", ex); return null; } diff --git a/src/de/diddiz/util/MySQLConnectionPool.java b/src/de/diddiz/util/MySQLConnectionPool.java index 80db572..d31d666 100644 --- a/src/de/diddiz/util/MySQLConnectionPool.java +++ b/src/de/diddiz/util/MySQLConnectionPool.java @@ -21,6 +21,10 @@ import java.util.Enumeration; import java.util.Map; import java.util.Properties; import java.util.Vector; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; public class MySQLConnectionPool implements Closeable { @@ -29,6 +33,7 @@ public class MySQLConnectionPool implements Closeable private final Vector connections; private final ConnectionReaper reaper; private final String url, user, password; + private final Lock lock = new ReentrantLock(); public MySQLConnectionPool(String url, String user, String password) throws ClassNotFoundException { Class.forName("com.mysql.jdbc.Driver"); @@ -41,41 +46,51 @@ public class MySQLConnectionPool implements Closeable } @Override - public synchronized void close() { + public void close() { + lock.lock(); final Enumeration conns = connections.elements(); while (conns.hasMoreElements()) { final JDCConnection conn = conns.nextElement(); connections.remove(conn); conn.terminate(); } + lock.unlock(); } - public synchronized Connection getConnection() throws SQLException { - JDCConnection conn; - for (int i = 0; i < connections.size(); i++) { - conn = connections.get(i); - if (conn.lease()) { - if (conn.isValid()) - return conn; - connections.remove(conn); - conn.terminate(); + public Connection getConnection() throws SQLException, InterruptedException, TimeoutException { + if (!lock.tryLock(100, TimeUnit.MILLISECONDS)) + throw new TimeoutException(); + try { + JDCConnection conn; + for (int i = 0; i < connections.size(); i++) { + conn = connections.get(i); + if (conn.lease()) { + if (conn.isValid()) + return conn; + connections.remove(conn); + conn.terminate(); + } } + conn = new JDCConnection(DriverManager.getConnection(url, user, password)); + conn.lease(); + if (!conn.isValid()) { + conn.terminate(); + throw new SQLException("Failed to validate a brand new connection"); + } + connections.add(conn); + return conn; + } finally { + lock.unlock(); } - conn = new JDCConnection(DriverManager.getConnection(url, user, password)); - conn.lease(); - if (!conn.isValid()) { - conn.terminate(); - throw new SQLException("Failed to validate a brand new connection"); - } - connections.add(conn); - return conn; } - private synchronized void reapConnections() { + private void reapConnections() { + lock.lock(); final long stale = System.currentTimeMillis() - timeToLive; for (final JDCConnection conn : connections) if (conn.inUse() && stale > conn.getLastUse() && !conn.isValid()) connections.remove(conn); + lock.unlock(); } private class ConnectionReaper extends Thread