Fixed deadlock in connection pool.

This commit is contained in:
Robin Kupper
2011-06-26 20:30:26 +02:00
parent fda092e75c
commit e75c4295de
2 changed files with 35 additions and 21 deletions

View File

@@ -4,7 +4,6 @@ import static de.diddiz.util.Utils.downloadIfNotExists;
import java.io.File; import java.io.File;
import java.net.URL; import java.net.URL;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Timer; import java.util.Timer;
@@ -181,7 +180,7 @@ public class LogBlock extends JavaPlugin
public Connection getConnection() { public Connection getConnection() {
try { try {
return pool.getConnection(); return pool.getConnection();
} catch (final SQLException ex) { } catch (final Exception ex) {
log.log(Level.SEVERE, "[LogBlock] Error while fetching connection", ex); log.log(Level.SEVERE, "[LogBlock] Error while fetching connection", ex);
return null; return null;
} }

View File

@@ -21,6 +21,10 @@ import java.util.Enumeration;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Vector; 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 public class MySQLConnectionPool implements Closeable
{ {
@@ -29,6 +33,7 @@ public class MySQLConnectionPool implements Closeable
private final Vector<JDCConnection> connections; private final Vector<JDCConnection> connections;
private final ConnectionReaper reaper; private final ConnectionReaper reaper;
private final String url, user, password; private final String url, user, password;
private final Lock lock = new ReentrantLock();
public MySQLConnectionPool(String url, String user, String password) throws ClassNotFoundException { public MySQLConnectionPool(String url, String user, String password) throws ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver"); Class.forName("com.mysql.jdbc.Driver");
@@ -41,41 +46,51 @@ public class MySQLConnectionPool implements Closeable
} }
@Override @Override
public synchronized void close() { public void close() {
lock.lock();
final Enumeration<JDCConnection> conns = connections.elements(); final Enumeration<JDCConnection> conns = connections.elements();
while (conns.hasMoreElements()) { while (conns.hasMoreElements()) {
final JDCConnection conn = conns.nextElement(); final JDCConnection conn = conns.nextElement();
connections.remove(conn); connections.remove(conn);
conn.terminate(); conn.terminate();
} }
lock.unlock();
} }
public synchronized Connection getConnection() throws SQLException { public Connection getConnection() throws SQLException, InterruptedException, TimeoutException {
JDCConnection conn; if (!lock.tryLock(100, TimeUnit.MILLISECONDS))
for (int i = 0; i < connections.size(); i++) { throw new TimeoutException();
conn = connections.get(i); try {
if (conn.lease()) { JDCConnection conn;
if (conn.isValid()) for (int i = 0; i < connections.size(); i++) {
return conn; conn = connections.get(i);
connections.remove(conn); if (conn.lease()) {
conn.terminate(); 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; final long stale = System.currentTimeMillis() - timeToLive;
for (final JDCConnection conn : connections) for (final JDCConnection conn : connections)
if (conn.inUse() && stale > conn.getLastUse() && !conn.isValid()) if (conn.inUse() && stale > conn.getLastUse() && !conn.isValid())
connections.remove(conn); connections.remove(conn);
lock.unlock();
} }
private class ConnectionReaper extends Thread private class ConnectionReaper extends Thread