forked from LogBlock/LogBlock
Fixed deadlock in connection pool.
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user