forked from LogBlock/LogBlock
Added ping to connection validation check.
Closing connections at server shutdown.
This commit is contained in:
@@ -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;
|
||||||
|
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user