- * The public methods of this class are thread-safe. - * - *
- * Home page: www.
- * source-code.biz/miniconnectionpoolmanager
- * If
- * If a connection is not valid, the method tries to get another connection
- * until one is valid (or a timeout occurs).
- *
- *
- * Pooled connections may become invalid when e.g. the database server is
- * restarted.
- *
- *
- * This method is slower than {@link #getConnection()} because the JDBC
- * driver has to send an extra command to the database server to test the
- * connection.
- *
- *
- * This method requires Java 1.6 or newer.
- *
- * @throws TimeoutException
- * when no valid connection becomes available within
- *
- * This is the number of
- * This is the number of internally kept recycled connections, for which
- *
- * Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland
- * Multi-licensed: EPL / LGPL / MPL.
- */
-public class MiniConnectionPoolManager {
-
- private ConnectionPoolDataSource dataSource;
- private int maxConnections;
- private long timeoutMs;
- private PrintWriter logWriter;
- private Semaphore semaphore;
- private PoolConnectionEventListener poolConnectionEventListener;
-
- // The following variables must only be accessed within synchronized blocks.
- // @GuardedBy("this") could by used in the future.
- private LinkedListtimeout seconds.
- */
- public static class TimeoutException extends RuntimeException {
-
- private static final long serialVersionUID = 1;
-
- public TimeoutException() {
- super("Timeout while waiting for a free database connection.");
- }
-
- public TimeoutException(String msg) {
- super(msg);
- }
- }
-
- /**
- * Constructs a MiniConnectionPoolManager object with a timeout of 60
- * seconds.
- *
- * @param dataSource
- * the data source for the connections.
- * @param maxConnections
- * the maximum number of connections.
- */
- public MiniConnectionPoolManager(ConnectionPoolDataSource dataSource,
- int maxConnections) {
- this(dataSource, maxConnections, 60);
- }
-
- /**
- * Constructs a MiniConnectionPoolManager object.
- *
- * @param dataSource
- * the data source for the connections.
- * @param maxConnections
- * the maximum number of connections.
- * @param timeout
- * the maximum time in seconds to wait for a free connection.
- */
- public MiniConnectionPoolManager(ConnectionPoolDataSource dataSource,
- int maxConnections, int timeout) {
- this.dataSource = dataSource;
- this.maxConnections = maxConnections;
- this.timeoutMs = timeout * 1000L;
- try {
- logWriter = dataSource.getLogWriter();
- } catch (SQLException e) {
- }
- if (maxConnections < 1) {
- throw new IllegalArgumentException("Invalid maxConnections value.");
- }
- semaphore = new Semaphore(maxConnections, true);
- recycledConnections = new LinkedListmaxConnections connections are already in use, the method
- * waits until a connection becomes available or timeout
- * seconds elapsed. When the application is finished using the connection,
- * it must close it in order to return it to the pool.
- *
- * @return a new Connection object.
- * @throws TimeoutException
- * when no connection becomes available within
- * timeout seconds.
- */
- public Connection getConnection() throws SQLException {
- return getConnection2(timeoutMs);
- }
-
- private Connection getConnection2(long timeoutMs) throws SQLException {
- // This routine is unsynchronized, because semaphore.tryAcquire() may
- // block.
- synchronized (this) {
- if (isDisposed) {
- throw new IllegalStateException("Connection pool has been disposed.");
- }
- }
- try {
- if (!semaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
- throw new TimeoutException();
- }
- } catch (InterruptedException e) {
- throw new RuntimeException("Interrupted while waiting for a database connection.", e);
- }
- boolean ok = false;
- try {
- Connection conn = getConnection3();
- ok = true;
- return conn;
- } finally {
- if (!ok) {
- semaphore.release();
- }
- }
- }
-
- private synchronized Connection getConnection3() throws SQLException {
- if (isDisposed) {
- throw new IllegalStateException("Connection pool has been disposed.");
- }
- PooledConnection pconn;
- if (!recycledConnections.isEmpty()) {
- pconn = recycledConnections.remove();
- } else {
- pconn = dataSource.getPooledConnection();
- pconn.addConnectionEventListener(poolConnectionEventListener);
- }
- Connection conn;
- try {
- // The JDBC driver may call
- // ConnectionEventListener.connectionErrorOccurred()
- // from within PooledConnection.getConnection(). To detect this
- // within
- // disposeConnection(), we temporarily set connectionInTransition.
- connectionInTransition = pconn;
- activeConnections++;
- conn = pconn.getConnection();
- } finally {
- connectionInTransition = null;
- }
- assertInnerState();
- return conn;
- }
-
- /**
- * Retrieves a connection from the connection pool and ensures that it is
- * valid by calling {@link Connection#isValid(int)}.
- *
- * timeout seconds.
- */
- public Connection getValidConnection() {
- long time = System.currentTimeMillis();
- long timeoutTime = time + timeoutMs;
- int triesWithoutDelay = getInactiveConnections() + 1;
- while (true) {
- Connection conn = getValidConnection2(time, timeoutTime);
- if (conn != null) {
- return conn;
- }
- triesWithoutDelay--;
- if (triesWithoutDelay <= 0) {
- triesWithoutDelay = 0;
- try {
- Thread.sleep(250);
- } catch (InterruptedException e) {
- throw new RuntimeException("Interrupted while waiting for a valid database connection.", e);
- }
- }
- time = System.currentTimeMillis();
- if (time >= timeoutTime) {
- throw new TimeoutException("Timeout while waiting for a valid database connection.");
- }
- }
- }
-
- private Connection getValidConnection2(long time, long timeoutTime) {
- long rtime = Math.max(1, timeoutTime - time);
- Connection conn;
- try {
- conn = getConnection2(rtime);
- } catch (SQLException e) {
- return null;
- }
- rtime = timeoutTime - System.currentTimeMillis();
- int rtimeSecs = Math.max(1, (int) ((rtime + 999) / 1000));
- try {
- if (conn.isValid(rtimeSecs)) {
- return conn;
- }
- } catch (SQLException e) {
- }
- // This Exception should never occur. If it nevertheless occurs, it's
- // because of an error in the
- // JDBC driver which we ignore and assume that the connection is not
- // valid.
- // When isValid() returns false, the JDBC driver should have already
- // called connectionErrorOccurred()
- // and the PooledConnection has been removed from the pool, i.e. the
- // PooledConnection will
- // not be added to recycledConnections when Connection.close() is
- // called.
- // But to be sure that this works even with a faulty JDBC driver, we
- // call purgeConnection().
- purgeConnection(conn);
- return null;
- }
-
- // Purges the PooledConnection associated with the passed Connection from
- // the connection pool.
- private synchronized void purgeConnection(Connection conn) {
- try {
- doPurgeConnection = true;
- // (A potential problem of this program logic is that setting the
- // doPurgeConnection flag
- // has an effect only if the JDBC driver calls connectionClosed()
- // synchronously within
- // Connection.close().)
- conn.close();
- } catch (SQLException e) {
- }
- // ignore exception from close()
- finally {
- doPurgeConnection = false;
- }
- }
-
- private synchronized void recycleConnection(PooledConnection pconn) {
- if (isDisposed || doPurgeConnection) {
- disposeConnection(pconn);
- return;
- }
- if (activeConnections <= 0) {
- throw new AssertionError("AuthMeDatabaseError");
- }
- activeConnections--;
- semaphore.release();
- recycledConnections.add(pconn);
- assertInnerState();
- }
-
- private synchronized void disposeConnection(PooledConnection pconn) {
- pconn.removeConnectionEventListener(poolConnectionEventListener);
- if (!recycledConnections.remove(pconn) && pconn != connectionInTransition) {
- // If the PooledConnection is not in the recycledConnections list
- // and is not currently within a PooledConnection.getConnection()
- // call,
- // we assume that the connection was active.
- if (activeConnections <= 0) {
- throw new AssertionError("AuthMeDatabaseError");
- }
- activeConnections--;
- semaphore.release();
- }
- closeConnectionAndIgnoreException(pconn);
- assertInnerState();
- }
-
- private void closeConnectionAndIgnoreException(PooledConnection pconn) {
- try {
- pconn.close();
- } catch (SQLException e) {
- log("Error while closing database connection: " + e.toString());
- }
- }
-
- private void log(String msg) {
- String s = "MiniConnectionPoolManager: " + msg;
- try {
- if (logWriter == null) {
- System.err.println(s);
- } else {
- logWriter.println(s);
- }
- } catch (Exception e) {
- }
- }
-
- private synchronized void assertInnerState() {
- if (activeConnections < 0) {
- throw new AssertionError("AuthMeDatabaseError");
- }
- if (activeConnections + recycledConnections.size() > maxConnections) {
- throw new AssertionError("AuthMeDatabaseError");
- }
- if (activeConnections + semaphore.availablePermits() > maxConnections) {
- throw new AssertionError("AuthMeDatabaseError");
- }
- }
-
- private class PoolConnectionEventListener implements
- ConnectionEventListener {
-
- public void connectionClosed(ConnectionEvent event) {
- PooledConnection pconn = (PooledConnection) event.getSource();
- recycleConnection(pconn);
- }
-
- public void connectionErrorOccurred(ConnectionEvent event) {
- PooledConnection pconn = (PooledConnection) event.getSource();
- disposeConnection(pconn);
- }
- }
-
- /**
- * Returns the number of active (open) connections of this pool.
- *
- * Connection objects that have been
- * issued by {@link #getConnection()}, for which
- * Connection.close() has not yet been called.
- *
- * @return the number of active connections.
- **/
- public synchronized int getActiveConnections() {
- return activeConnections;
- }
-
- /**
- * Returns the number of inactive (unused) connections in this pool.
- *
- * Connection.close() has been called and which have not yet
- * been reused.
- *
- * @return the number of inactive connections.
- **/
- public synchronized int getInactiveConnections() {
- return recycledConnections.size();
- }
-
-} // end class MiniConnectionPoolManager
diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java
index 4f4f96b5..b637259e 100644
--- a/src/main/java/fr/xephi/authme/datasource/MySQL.java
+++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java
@@ -8,13 +8,14 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.TimeoutException;
-import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
-import fr.xephi.authme.datasource.MiniConnectionPoolManager.TimeoutException;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.settings.Settings;
@@ -40,7 +41,7 @@ public class MySQL implements DataSource {
private String columnID;
private String columnLogged;
private List