diff --git a/ConnectionPoolManager.java b/ConnectionPoolManager.java new file mode 100644 index 0000000..f8c19a8 --- /dev/null +++ b/ConnectionPoolManager.java @@ -0,0 +1,196 @@ + + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Object pool manager: Responsible for DatabaseConnection creation, reuse, and recycling + * @author chuyang + * @version 1.0 + */ +public class ConnectionPoolManager { + + /** + * Connection pool storage + */ + private final List connectionPool; + /** + * Database URL + */ + private final String databaseUrl; + /** + * Initial pool size + */ + private final int initialSize; + /** + * Maximum pool size + */ + private final int maxSize; + /** + * For thread safety + */ + private final Lock poolLock = new ReentrantLock(); + public DatabaseConnection m_DatabaseConnection; + + public ConnectionPoolManager(){ + this.connectionPool = new ArrayList<>(); + this.databaseUrl = ""; + this.initialSize = 0; + this.maxSize = 0; + } + + @Override + public void finalize() throws Throwable { + // Close all connections + poolLock.lock(); + try { + for (DatabaseConnection conn : connectionPool) { + System.out.println("Closing connection " + conn.getConnectionId()); + } + connectionPool.clear(); + } finally { + poolLock.unlock(); + } + } + /** + * Constructor: Initialize object pool + * + * @param initialSize Initial number of connections + * @param maxSize Maximum number of connections + * @param databaseUrl Database URL + */ + public ConnectionPoolManager(int initialSize, int maxSize, String databaseUrl){ + if (initialSize < 0 || maxSize < initialSize) { + throw new IllegalArgumentException("Invalid pool size parameters"); + } + this.connectionPool = new ArrayList<>(maxSize); + this.databaseUrl = databaseUrl; + this.initialSize = initialSize; + this.maxSize = maxSize; + + // Initialize connection pool + initializePool(); + } + + /** + * Initialize the connection pool, create initial connections + */ + private void initializePool() { + System.out.println("Initializing connection pool with " + initialSize + " connections"); + for (int i = 0; i < initialSize; i++) { + String connId = "conn-" + i; + DatabaseConnection conn = new DatabaseConnection(connId, databaseUrl); + connectionPool.add(conn); + } + System.out.println("Connection pool initialized with " + connectionPool.size() + " connections"); + } + + /** + * Borrow a connection from the pool + * @return Available connection, or null (pool is full) + */ + public DatabaseConnection borrowConnection(){ + poolLock.lock(); + try { + // 1. Look for idle connection + for (DatabaseConnection conn : connectionPool) { + if (!conn.isInUse()) { + conn.setInUse(true); + System.out.println("Borrowed existing connection: " + conn.getConnectionId()); + return conn; + } + } + + // 2. If no idle connections and max size not reached, create new connection + if (connectionPool.size() < maxSize) { + String connId = "conn-" + connectionPool.size(); + DatabaseConnection newConn = new DatabaseConnection(connId, databaseUrl); + newConn.setInUse(true); + connectionPool.add(newConn); + System.out.println("Created and borrowed new connection: " + newConn.getConnectionId()); + return newConn; + } + + // 3. Pool is full, return null + System.out.println("Connection pool is full, no available connections"); + return null; + } finally { + poolLock.unlock(); + } + } + + /** + * Return connection to the pool + * + * @param conn Connection to return + */ + public void returnConnection(DatabaseConnection conn){ + if (conn == null) { + return; + } + + poolLock.lock(); + try { + // Check if connection belongs to this pool + if (connectionPool.contains(conn)) { + // Reset connection state + conn.reset(); + conn.setInUse(false); + System.out.println("Connection returned to pool: " + conn.getConnectionId()); + } else { + System.out.println("Warning: Attempting to return a connection not managed by this pool"); + } + } finally { + poolLock.unlock(); + } + } + + /** + * Shrink pool: Destroy idle connections + */ + public void shrinkPool(){ + poolLock.lock(); + try { + // Only keep initial size of connections + List connectionsToRemove = new ArrayList<>(); + int activeConnections = 0; + + for (DatabaseConnection conn : connectionPool) { + if (conn.isInUse()) { + activeConnections++; + } else if (connectionPool.size() - connectionsToRemove.size() > initialSize) { + connectionsToRemove.add(conn); + System.out.println("Removing idle connection: " + conn.getConnectionId()); + } + } + + connectionPool.removeAll(connectionsToRemove); + System.out.println("Pool shrunk. Active connections: " + activeConnections + ", Idle connections: " + connectionPool.size() + ", Removed: " + connectionsToRemove.size()); + } finally { + poolLock.unlock(); + } + } + + /** + * Get pool status information + */ + public String getPoolStatus() { + poolLock.lock(); + try { + int activeConnections = 0; + for (DatabaseConnection conn : connectionPool) { + if (conn.isInUse()) { + activeConnections++; + } + } + return "Pool status: " + connectionPool.size() + " total connections, " + + activeConnections + " active, " + + (connectionPool.size() - activeConnections) + " idle, " + + "Max capacity: " + maxSize; + } finally { + poolLock.unlock(); + } + } +} \ No newline at end of file