From 1b1b705daa42f49daf6f0193ef036b4da82577ad Mon Sep 17 00:00:00 2001 From: Robin Kupper Date: Mon, 2 May 2011 14:55:38 +0200 Subject: [PATCH] Added ping to connection validation check. Closing connections at server shutdown. --- src/de/diddiz/LogBlock/LogBlock.java | 6 +- src/de/diddiz/util/ConnectionPool.java | 206 ++++++++++--------------- 2 files changed, 89 insertions(+), 123 deletions(-) diff --git a/src/de/diddiz/LogBlock/LogBlock.java b/src/de/diddiz/LogBlock/LogBlock.java index 8e6a102..04ce63a 100644 --- a/src/de/diddiz/LogBlock/LogBlock.java +++ b/src/de/diddiz/LogBlock/LogBlock.java @@ -74,7 +74,7 @@ public class LogBlock extends JavaPlugin return; } 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(); conn.close(); } catch (final Exception ex) { @@ -159,6 +159,8 @@ public class LogBlock extends JavaPlugin thread.run(); } } + if (pool != null) + pool.closeConnections(); log.info("LogBlock disabled."); } @@ -527,7 +529,7 @@ public class LogBlock extends JavaPlugin public Connection getConnection() { try { - return pool.connect(ConnectionPool.URL_PREFIX, null); + return pool.getConnection(); } catch (final SQLException ex) { log.log(Level.SEVERE, "[LogBlock] Error while fetching connection", ex); return null; diff --git a/src/de/diddiz/util/ConnectionPool.java b/src/de/diddiz/util/ConnectionPool.java index cd43e54..3d2c09a 100644 --- a/src/de/diddiz/util/ConnectionPool.java +++ b/src/de/diddiz/util/ConnectionPool.java @@ -20,11 +20,10 @@ import java.sql.CallableStatement; import java.sql.Clob; import java.sql.Connection; import java.sql.DatabaseMetaData; -import java.sql.Driver; import java.sql.DriverManager; -import java.sql.DriverPropertyInfo; import java.sql.NClob; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLClientInfoException; import java.sql.SQLException; import java.sql.SQLWarning; @@ -37,48 +36,80 @@ import java.util.Map; import java.util.Properties; import java.util.Vector; -public class ConnectionPool implements Driver { - public static final String URL_PREFIX = "jdbc:jdc:"; - private static final int MAJOR_VERSION = 1; - private static final int MINOR_VERSION = 0; - private final ConnectionService pool; +public class ConnectionPool { + private final Vector connections; + private final String url, user, password; + private final long timeout = 60000; + private final ConnectionReaper reaper; + private final int poolsize = 10; - public ConnectionPool(String driver, String url, String user, String password) throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException { - DriverManager.registerDriver(this); - Class.forName(driver).newInstance(); - pool = new ConnectionService(url, user, password); + public ConnectionPool(String url, String user, String password) throws ClassNotFoundException { + Class.forName("com.mysql.jdbc.Driver"); + this.url = url; + this.user = user; + this.password = password; + connections = new Vector(poolsize); + reaper = new ConnectionReaper(); + reaper.start(); } - @Override - public Connection connect(String url, Properties props) throws SQLException { - if (!url.startsWith(URL_PREFIX)) - return null; - return pool.getConnection(); + 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 { + 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 - public boolean acceptsURL(String url) { - return url.startsWith(URL_PREFIX); + private synchronized void reapConnections() { + final long stale = System.currentTimeMillis() - timeout; + final Enumeration 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 int getMajorVersion() { - return MAJOR_VERSION; + public synchronized void closeConnections() { + final Enumeration connlist = connections.elements(); + while (connlist != null && connlist.hasMoreElements()) { + final JDCConnection conn = connlist.nextElement(); + conn.terminate(); + removeConnection(conn); + } } - @Override - public int getMinorVersion() { - return MINOR_VERSION; + private synchronized void removeConnection(JDCConnection conn) { + connections.removeElement(conn); } - @Override - public DriverPropertyInfo[] getPropertyInfo(String str, Properties props) { - return new DriverPropertyInfo[0]; - } - - @Override - public boolean jdbcCompliant() { - return false; + private class ConnectionReaper extends Thread + { + @Override + public void run() { + while (true) { + try { + Thread.sleep(300000); + } catch (final InterruptedException e) {} + reapConnections(); + } + } } private class JDCConnection implements Connection @@ -93,6 +124,12 @@ public class ConnectionPool implements Driver { timestamp = 0; } + public void terminate() { + try { + conn.close(); + } catch (SQLException ex) {} + } + public synchronized boolean lease() { if (inuse) { return false; @@ -104,12 +141,24 @@ public class ConnectionPool implements Driver { } public boolean validate() { + Statement state = null; + ResultSet rs = null; try { conn.getMetaData(); - } catch (final Exception e) { - return false; + state = conn.createStatement(); + 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() { @@ -122,10 +171,6 @@ public class ConnectionPool implements Driver { @Override public void close() { - expireLease(); - } - - protected void expireLease() { inuse = false; } @@ -363,85 +408,4 @@ public class ConnectionPool implements Driver { return null; } } - - public class ConnectionService - { - private final Vector 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(poolsize); - reaper = new ConnectionReaper(this); - reaper.start(); - } - - public synchronized void reapConnections() { - final long stale = System.currentTimeMillis() - timeout; - final Enumeration 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 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(); - } - } - } }