com.wizarius.orm.database.DBConnectionPool Maven / Gradle / Ivy
The newest version!
package com.wizarius.orm.database;
import org.apache.log4j.Logger;
import com.wizarius.orm.database.exceptions.DBException;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author Shyshkin Vladyslav on 14.03.17.
*/
@SuppressWarnings("unchecked")
public class DBConnectionPool {
private static final Logger log = Logger.getLogger(DBConnectionPool.class.getName());
private final ConnectionDriver connectionDriver;
private final int MIN_OPEN_CONNECTION = 5;
private final int MAX_OPEN_CONNECTION = 30;
private ArrayBlockingQueue availableOpenConnections = new ArrayBlockingQueue<>(MAX_OPEN_CONNECTION);
private AtomicInteger amountAvailableConnections;
private final Class dbClazz;
public DBConnectionPool(ConnectionDriver driver, Class clazz) throws DBException {
log.trace("initialize log to connection pool");
this.connectionDriver = driver;
this.dbClazz = clazz;
this.amountAvailableConnections = new AtomicInteger(0);
for (int i = 0; i < MIN_OPEN_CONNECTION; i++) {
addConnection();
}
}
/**
* Get available connection
*
* @return Connection
* @throws DBException
*/
public synchronized T getConnection() throws DBException {
T connection = availableOpenConnections.poll();
amountAvailableConnections.decrementAndGet();
while (connection == null) {
if (amountAvailableConnections.get() >= MAX_OPEN_CONNECTION) {
throw new DBException("Amount connection exceeds MAX_OPEN_CONNECTION");
} else {
openNextConnection();
}
connection = availableOpenConnections.poll();
}
try {
//skip closed connection and remove it from available connections
if (connection.getConnection().isClosed()) {
log.info("Skip connection because connection is closed");
return getConnection();
}
//в постгресе нельзя делать isValid, он ставит timeout который потом киляет другие запросы
//https://stackoverflow.com/questions/13114101/postgresql-error-canceling-statement-due-to-user-request
else if (!connection.checkConnection(3)) {
log.info("Skip connection because connection isn't valid");
return getConnection();
}
} catch (SQLException e) {
throw new DBException("Unable to check if connection is closed " + e.getMessage(), e);
}
return connection;
}
/**
* User finishes using of connection, return this connection to available array
*
* @param connection available connection
*/
public void releaseConnection(T connection) {
amountAvailableConnections.incrementAndGet();
availableOpenConnections.add(connection);
}
/**
* Open next connection if available
*
* @throws DBException
*/
private void openNextConnection() throws DBException {
int countOpen = 0;
//open next 3 connection
if (MAX_OPEN_CONNECTION >= amountAvailableConnections.get() + 3) {
countOpen = 3;
}
//open next 2 connection
else if (MAX_OPEN_CONNECTION >= amountAvailableConnections.get() + 2) {
countOpen = 2;
}
//open next 1 connection
else if (MAX_OPEN_CONNECTION >= amountAvailableConnections.get() + 1) {
countOpen = 1;
}
for (int i = 0; i < countOpen; i++) {
addConnection();
}
log.info("Opened next connection current opened connections = " + amountAvailableConnections);
}
/**
* Add connections to pool
*/
private void addConnection() throws DBException {
try {
T connection = dbClazz.getDeclaredConstructor(Connection.class, DBConnectionPool.class)
.newInstance(connectionDriver.getConnection(), this);
try {
boolean closed = connection.getConnection().isClosed();
if (closed) {
throw new DBException("Connection is closed. Server not available! Where connection address = " + connectionDriver.getURL());
}
boolean valid = connection.checkConnection(5);
if (!valid) {
throw new DBException("Unable to open new connection. Server opened non-valid connection. Where connection address = " + connectionDriver.getURL());
}
availableOpenConnections.add(
connection
);
amountAvailableConnections.incrementAndGet();
} catch (SQLException | DBException e) {
throw new DBException("Unable to open new connection " + e.getMessage(), e);
}
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
log.error("Unable to create new instance of clazz. Server opened non-valid connection. Where connection address = " + connectionDriver.getURL() + " " + dbClazz + " . " + e.getMessage(), e);
}
}
/**
* Get amount available connections in pool
*
* @return amount available connection
*/
public int getAvailableConnectionCount() {
return availableOpenConnections.size();
}
}