All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wizarius.orm.database.connection.DBConnectionPool Maven / Gradle / Ivy

There is a newer version: 0.0.27.6
Show newest version
package com.wizarius.orm.database.connection;

import com.wizarius.orm.database.DBException;
import com.wizarius.orm.database.actions.IDBDialect;
import com.wizarius.orm.database.entityreader.WizEntityManager;
import lombok.extern.slf4j.Slf4j;

import java.sql.SQLException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Vladyslav Shyshkin on 14.03.17.
 */
@Slf4j
public class DBConnectionPool {
    private final WizEntityManager entityManager;
    /**
     * Connection driver to database
     */
    private final ConnectionDriver connectionDriver;
    /**
     * Maximum connections in pool
     */
    private final int maxOpenConnection;
    /**
     * Array of available connections
     */
    private final ArrayBlockingQueue availableOpenConnections;
    /**
     * Available connections count
     */
    private AtomicInteger amountAvailableConnections;

    /**
     * Initialize connection pool
     *
     * @param driver connection driver
     * @throws DBException on unable to connect with database
     */
    public DBConnectionPool(ConnectionDriver driver) throws DBException {
        this(driver, 5, 30);
        log.trace("initialize default connection pool");
    }

    /**
     * Initialize connection pool
     *
     * @param connectionDriver  connection driver
     * @param minOpenConnection min pool size
     * @param maxOpenConnection max pool size
     * @throws DBException on unable to connect with database
     */
    public DBConnectionPool(ConnectionDriver connectionDriver,
                            int minOpenConnection,
                            int maxOpenConnection) throws DBException {
        this.entityManager = new WizEntityManager(this);
        this.connectionDriver = connectionDriver;
        this.maxOpenConnection = maxOpenConnection;
        this.availableOpenConnections = new ArrayBlockingQueue<>(maxOpenConnection);
        this.amountAvailableConnections = new AtomicInteger(0);
        for (int i = 0; i < minOpenConnection; i++) {
            addConnection();
        }
    }

    /**
     * Get available connection
     *
     * @return Connection
     * @throws DBException on unable to get connection
     */
    public synchronized DBConnection getConnection() throws DBException {
        DBConnection connection = availableOpenConnections.poll();
        amountAvailableConnections.decrementAndGet();
        while (connection == null) {
            if (amountAvailableConnections.get() >= maxOpenConnection) {
                throw new DBException("Amount connection exceeds maxOpenConnection");
            } 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(DBConnection connection) {
        amountAvailableConnections.incrementAndGet();
        availableOpenConnections.add(connection);
    }

    /**
     * Open next connection if available
     *
     * @throws DBException on unable to open next connectioon
     */
    private void openNextConnection() throws DBException {
        int countOpen = 0;
        //open next 3 connection
        if (maxOpenConnection >= amountAvailableConnections.get() + 3) {
            countOpen = 3;
        }
        //open next 2 connection
        else if (maxOpenConnection >= amountAvailableConnections.get() + 2) {
            countOpen = 2;
        }
        //open next 1 connection
        else if (maxOpenConnection >= 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 {
        DBConnection connection = new DBConnection(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);
        }
    }

    /**
     * Get amount available connections in pool
     *
     * @return amount available connection
     */
    public int getAvailableConnectionCount() {
        return availableOpenConnections.size();
    }

    /**
     * Returns connection dialect
     *
     * @return connection dialect
     */
    public IDBDialect getDialect() {
        return connectionDriver.getDialect();
    }

    /**
     * Returns entity manager
     *
     * @return entity manager
     */
    public WizEntityManager getEntityManager() {
        return entityManager;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy