Use HikariCP for connection pooling

This commit is contained in:
Ammar Askar
2015-03-21 02:46:55 +05:00
parent 51fdff20a7
commit 448b11b35e
4 changed files with 49 additions and 421 deletions

1
.gitignore vendored
View File

@ -13,6 +13,7 @@
# maven
/target
dependency-reduced-pom.xml
# vim
.*.sw[a-p]

29
pom.xml
View File

@ -43,6 +43,7 @@
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.7.2-R0.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
@ -55,6 +56,7 @@
<groupId>com.sk89q</groupId>
<artifactId>worldedit</artifactId>
<version>6.0.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
@ -62,8 +64,13 @@
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP-java6</artifactId>
<version>2.3.4</version>
<scope>compile</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>repobo-snap</id>
@ -117,7 +124,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<version>3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
@ -143,7 +150,21 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -135,7 +135,7 @@ public class Config
if (!config.contains(e.getKey()))
config.set(e.getKey(), e.getValue());
logblock.saveConfig();
url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database") + "?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true";
url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database");
user = getStringIncludingInts(config, "mysql.user");
password = getStringIncludingInts(config, "mysql.password");
delayBetweenRuns = config.getInt("consumer.delayBetweenRuns", 2);

View File

@ -1,437 +1,43 @@
package de.diddiz.util;
import static de.diddiz.LogBlock.config.Config.mb4;
import com.zaxxer.hikari.HikariDataSource;
import de.diddiz.LogBlock.config.Config;
import java.io.Closeable;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;
import java.util.concurrent.Executor;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MySQLConnectionPool implements Closeable
{
private final static int poolSize = 10;
private final static long timeToLive = 300000;
private final Vector<JDCConnection> connections;
private final String url, user, password;
private final Lock lock = new ReentrantLock();
private final HikariDataSource ds;
public MySQLConnectionPool(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<JDCConnection>(poolSize);
ConnectionReaper reaper = new ConnectionReaper();
new Thread(reaper, "MySQL Connection Reaper Thread - LogBlock").start();
this.ds = new HikariDataSource();
ds.setJdbcUrl(url);
ds.setUsername(user);
ds.setPassword(password);
ds.addDataSourceProperty("useUnicode", "true");
ds.addDataSourceProperty("characterEncoding", "utf-8");
ds.addDataSourceProperty("rewriteBatchedStatements", "true");
ds.addDataSourceProperty("cachePrepStmts", "true");
ds.addDataSourceProperty("prepStmtCacheSize", "250");
ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
}
@Override
public void close() {
lock.lock();
final Enumeration<JDCConnection> conns = connections.elements();
while (conns.hasMoreElements()) {
final JDCConnection conn = conns.nextElement();
connections.remove(conn);
conn.terminate();
}
lock.unlock();
ds.close();
}
public Connection getConnection() throws SQLException {
lock.lock();
try {
final Enumeration<JDCConnection> conns = connections.elements();
while (conns.hasMoreElements()) {
final JDCConnection conn = conns.nextElement();
if (conn.lease()) {
if (conn.isValid())
return conn;
connections.remove(conn);
conn.terminate();
}
}
final JDCConnection 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);
if (mb4) conn.createStatement().executeQuery("SET NAMES utf8mb4");
return conn;
} finally {
lock.unlock();
Connection connection = ds.getConnection();
if (Config.mb4) {
connection.createStatement().executeQuery("SET NAMES utf8mb4");
}
return connection;
}
private void reapConnections() {
lock.lock();
final long stale = System.currentTimeMillis() - timeToLive;
final Iterator<JDCConnection> itr = connections.iterator();
while (itr.hasNext()) {
final JDCConnection conn = itr.next();
if (conn.inUse() && stale > conn.getLastUse() && !conn.isValid())
itr.remove();
}
lock.unlock();
}
private class ConnectionReaper implements Runnable
{
@Override
public void run() {
while (true) {
try {
Thread.sleep(300000);
} catch (final InterruptedException e) {
}
reapConnections();
}
}
}
private class JDCConnection implements Connection
{
private final Connection conn;
private boolean inUse;
private long timestamp;
private int networkTimeout;
private String schema;
JDCConnection(Connection conn) {
this.conn = conn;
inUse = false;
timestamp = 0;
networkTimeout = 30;
schema = "default";
}
@Override
public void clearWarnings() throws SQLException {
conn.clearWarnings();
}
@Override
public void close() {
inUse = false;
try {
if (!conn.getAutoCommit())
conn.setAutoCommit(true);
} catch (final SQLException ex) {
connections.remove(this);
terminate();
}
}
@Override
public void commit() throws SQLException {
conn.commit();
}
@Override
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
return conn.createArrayOf(typeName, elements);
}
@Override
public Blob createBlob() throws SQLException {
return conn.createBlob();
}
@Override
public Clob createClob() throws SQLException {
return conn.createClob();
}
@Override
public NClob createNClob() throws SQLException {
return conn.createNClob();
}
@Override
public SQLXML createSQLXML() throws SQLException {
return conn.createSQLXML();
}
@Override
public Statement createStatement() throws SQLException {
return conn.createStatement();
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.createStatement(resultSetType, resultSetConcurrency);
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
return conn.createStruct(typeName, attributes);
}
@Override
public boolean getAutoCommit() throws SQLException {
return conn.getAutoCommit();
}
@Override
public String getCatalog() throws SQLException {
return conn.getCatalog();
}
@Override
public Properties getClientInfo() throws SQLException {
return conn.getClientInfo();
}
@Override
public String getClientInfo(String name) throws SQLException {
return conn.getClientInfo(name);
}
@Override
public int getHoldability() throws SQLException {
return conn.getHoldability();
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
return conn.getMetaData();
}
@Override
public int getTransactionIsolation() throws SQLException {
return conn.getTransactionIsolation();
}
@Override
public Map<String, Class<?>> getTypeMap() throws SQLException {
return conn.getTypeMap();
}
@Override
public SQLWarning getWarnings() throws SQLException {
return conn.getWarnings();
}
@Override
public boolean isClosed() throws SQLException {
return conn.isClosed();
}
@Override
public boolean isReadOnly() throws SQLException {
return conn.isReadOnly();
}
@Override
public boolean isValid(int timeout) throws SQLException {
return conn.isValid(timeout);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return conn.isWrapperFor(iface);
}
@Override
public String nativeSQL(String sql) throws SQLException {
return conn.nativeSQL(sql);
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
return conn.prepareCall(sql);
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.prepareCall(sql, resultSetType, resultSetConcurrency);
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return conn.prepareStatement(sql);
}
@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
return conn.prepareStatement(sql, autoGeneratedKeys);
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
return conn.prepareStatement(sql, columnIndexes);
}
@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
return conn.prepareStatement(sql, columnNames);
}
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
conn.releaseSavepoint(savepoint);
}
@Override
public void rollback() throws SQLException {
conn.rollback();
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
conn.rollback(savepoint);
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
conn.setAutoCommit(autoCommit);
}
@Override
public void setCatalog(String catalog) throws SQLException {
conn.setCatalog(catalog);
}
@Override
public void setClientInfo(Properties properties) throws SQLClientInfoException {
conn.setClientInfo(properties);
}
@Override
public void setClientInfo(String name, String value) throws SQLClientInfoException {
conn.setClientInfo(name, value);
}
@Override
public void setHoldability(int holdability) throws SQLException {
conn.setHoldability(holdability);
}
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
conn.setReadOnly(readOnly);
}
@Override
public Savepoint setSavepoint() throws SQLException {
return conn.setSavepoint();
}
@Override
public Savepoint setSavepoint(String name) throws SQLException {
return conn.setSavepoint(name);
}
@Override
public void setTransactionIsolation(int level) throws SQLException {
conn.setTransactionIsolation(level);
}
@Override
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
conn.setTypeMap(map);
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return conn.unwrap(iface);
}
@SuppressWarnings("unused")
public int getNetworkTimeout() throws SQLException {
return networkTimeout;
}
@SuppressWarnings("unused")
public void setNetworkTimeout(Executor exec, int timeout) throws SQLException {
networkTimeout = timeout;
}
@SuppressWarnings("unused")
public void abort(Executor exec) throws SQLException {
// Not implemented really...
}
@SuppressWarnings("unused")
public String getSchema() throws SQLException {
return schema;
}
@SuppressWarnings("unused")
public void setSchema(String str) throws SQLException {
schema = str;
}
long getLastUse() {
return timestamp;
}
boolean inUse() {
return inUse;
}
boolean isValid() {
try {
return conn.isValid(1);
} catch (final SQLException ex) {
return false;
}
}
synchronized boolean lease() {
if (inUse)
return false;
inUse = true;
timestamp = System.currentTimeMillis();
return true;
}
void terminate() {
try {
conn.close();
} catch (final SQLException ex) {
}
}
}
}