Added ping to connection validation check.

Closing connections at server shutdown.
This commit is contained in:
Robin Kupper
2011-05-02 14:55:38 +02:00
parent 70d8f55f5d
commit 1b1b705daa
2 changed files with 89 additions and 123 deletions

View File

@@ -74,7 +74,7 @@ public class LogBlock extends JavaPlugin
return; return;
} }
try { try {
pool = new ConnectionPool("com.mysql.jdbc.Driver", config.url, config.user, config.password); pool = new ConnectionPool(config.url, config.user, config.password);
final Connection conn = getConnection(); final Connection conn = getConnection();
conn.close(); conn.close();
} catch (final Exception ex) { } catch (final Exception ex) {
@@ -159,6 +159,8 @@ public class LogBlock extends JavaPlugin
thread.run(); thread.run();
} }
} }
if (pool != null)
pool.closeConnections();
log.info("LogBlock disabled."); log.info("LogBlock disabled.");
} }
@@ -527,7 +529,7 @@ public class LogBlock extends JavaPlugin
public Connection getConnection() { public Connection getConnection() {
try { try {
return pool.connect(ConnectionPool.URL_PREFIX, null); return pool.getConnection();
} catch (final SQLException ex) { } catch (final SQLException 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

@@ -20,11 +20,10 @@ import java.sql.CallableStatement;
import java.sql.Clob; import java.sql.Clob;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DatabaseMetaData; import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.NClob; import java.sql.NClob;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLClientInfoException; import java.sql.SQLClientInfoException;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.SQLWarning; import java.sql.SQLWarning;
@@ -37,48 +36,80 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Vector; import java.util.Vector;
public class ConnectionPool implements Driver { public class ConnectionPool {
public static final String URL_PREFIX = "jdbc:jdc:"; private final Vector<JDCConnection> connections;
private static final int MAJOR_VERSION = 1; private final String url, user, password;
private static final int MINOR_VERSION = 0; private final long timeout = 60000;
private final ConnectionService pool; private final ConnectionReaper reaper;
private final int poolsize = 10;
public ConnectionPool(String driver, String url, String user, String password) throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException { public ConnectionPool(String url, String user, String password) throws ClassNotFoundException {
DriverManager.registerDriver(this); Class.forName("com.mysql.jdbc.Driver");
Class.forName(driver).newInstance(); this.url = url;
pool = new ConnectionService(url, user, password); this.user = user;
this.password = password;
connections = new Vector<JDCConnection>(poolsize);
reaper = new ConnectionReaper();
reaper.start();
} }
@Override public synchronized Connection getConnection() throws SQLException {
public Connection connect(String url, Properties props) throws SQLException { JDCConnection c;
if (!url.startsWith(URL_PREFIX)) for (int i = 0; i < connections.size(); i++) {
return null; c = connections.elementAt(i);
return pool.getConnection(); if (c.lease()) {
if (c.validate())
return c;
else {
c.terminate();
removeConnection(c);
}
}
}
c = new JDCConnection(DriverManager.getConnection(url, user, password));
c.lease();
if (!c.validate()) {
c.terminate();
throw new SQLException("Failed to validate a brand new connection");
}
connections.addElement(c);
return c;
} }
@Override private synchronized void reapConnections() {
public boolean acceptsURL(String url) { final long stale = System.currentTimeMillis() - timeout;
return url.startsWith(URL_PREFIX); final Enumeration<JDCConnection> connlist = connections.elements();
while (connlist != null && connlist.hasMoreElements()) {
final JDCConnection conn = connlist.nextElement();
if (conn.inUse() && stale > conn.getLastUse() && !conn.validate())
removeConnection(conn);
}
} }
@Override public synchronized void closeConnections() {
public int getMajorVersion() { final Enumeration<JDCConnection> connlist = connections.elements();
return MAJOR_VERSION; while (connlist != null && connlist.hasMoreElements()) {
final JDCConnection conn = connlist.nextElement();
conn.terminate();
removeConnection(conn);
}
} }
@Override private synchronized void removeConnection(JDCConnection conn) {
public int getMinorVersion() { connections.removeElement(conn);
return MINOR_VERSION;
} }
@Override private class ConnectionReaper extends Thread
public DriverPropertyInfo[] getPropertyInfo(String str, Properties props) { {
return new DriverPropertyInfo[0]; @Override
} public void run() {
while (true) {
@Override try {
public boolean jdbcCompliant() { Thread.sleep(300000);
return false; } catch (final InterruptedException e) {}
reapConnections();
}
}
} }
private class JDCConnection implements Connection private class JDCConnection implements Connection
@@ -93,6 +124,12 @@ public class ConnectionPool implements Driver {
timestamp = 0; timestamp = 0;
} }
public void terminate() {
try {
conn.close();
} catch (SQLException ex) {}
}
public synchronized boolean lease() { public synchronized boolean lease() {
if (inuse) { if (inuse) {
return false; return false;
@@ -104,12 +141,24 @@ public class ConnectionPool implements Driver {
} }
public boolean validate() { public boolean validate() {
Statement state = null;
ResultSet rs = null;
try { try {
conn.getMetaData(); conn.getMetaData();
} catch (final Exception e) { state = conn.createStatement();
return false; rs = state.executeQuery("/* ping */");
if (rs.next() && rs.getInt(1) == 1)
return true;
} catch (final SQLException ex) {
} finally {
try {
if (rs != null)
rs.close();
if (state != null)
state.close();
} catch (final SQLException ex) {}
} }
return true; return false;
} }
public boolean inUse() { public boolean inUse() {
@@ -122,10 +171,6 @@ public class ConnectionPool implements Driver {
@Override @Override
public void close() { public void close() {
expireLease();
}
protected void expireLease() {
inuse = false; inuse = false;
} }
@@ -363,85 +408,4 @@ public class ConnectionPool implements Driver {
return null; return null;
} }
} }
public class ConnectionService
{
private final Vector<JDCConnection> connections;
private final String url, user, password;
final private long timeout = 60000;
private final ConnectionReaper reaper;
final private int poolsize = 10;
public ConnectionService(String url, String user, String password) {
this.url = url;
this.user = user;
this.password = password;
connections = new Vector<JDCConnection>(poolsize);
reaper = new ConnectionReaper(this);
reaper.start();
}
public synchronized void reapConnections() {
final long stale = System.currentTimeMillis() - timeout;
final Enumeration<JDCConnection> connlist = connections.elements();
while (connlist != null && connlist.hasMoreElements()) {
final JDCConnection conn = connlist.nextElement();
if (conn.inUse() && stale > conn.getLastUse() && !conn.validate())
removeConnection(conn);
}
}
public synchronized void closeConnections() {
final Enumeration<JDCConnection> connlist = connections.elements();
while (connlist != null && connlist.hasMoreElements()) {
final JDCConnection conn = connlist.nextElement();
removeConnection(conn);
}
}
private synchronized void removeConnection(JDCConnection conn) {
connections.removeElement(conn);
}
public synchronized Connection getConnection() throws SQLException {
JDCConnection c;
for (int i = 0; i < connections.size(); i++) {
c = connections.elementAt(i);
if (c.lease()) {
if (c.validate())
return c;
else
removeConnection(c);
}
}
c = new JDCConnection(DriverManager.getConnection(url, user, password));
c.lease();
connections.addElement(c);
return c;
}
public synchronized void returnConnection(JDCConnection conn) {
conn.expireLease();
}
}
class ConnectionReaper extends Thread
{
private final ConnectionService pool;
private final long delay = 300000;
ConnectionReaper(ConnectionService pool) {
this.pool = pool;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(delay);
} catch (final InterruptedException e) {}
pool.reapConnections();
}
}
}
} }