Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ static DataSourceBuilder builder() {
*/
SQLException dataSourceDownReason();

int forceTrim(int trimCount);

/**
* Set a new maximum size.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,59 @@
*/
public interface DataSourcePoolListener {

/**
* Called before a connection has been created
*/
default void onBeforeCreateConnection(DataSourcePool pool) {}

/**
* Called after a connection has been created
*/
default void onAfterCreateConnection(DataSourcePool pool, Connection connection) {}

/**
* Called before a connection has been retrieved from the connection pool
*/
default void onBeforeBorrowConnection(DataSourcePool pool) {}

/**
* Called after a connection has been retrieved from the connection pool
*/
default void onAfterBorrowConnection(DataSourcePool pool, Connection connection) {onAfterBorrowConnection(connection);}

/**
* Called after a connection has been retrieved from the connection pool.
*
* Migrate to <code>onAfterBorrowConnection(DataSourcePool pool, Connection connection)</code>
*/
@Deprecated
default void onAfterBorrowConnection(Connection connection) {}

/**
* Called before a connection will be put back to the connection pool
*/
default void onBeforeReturnConnection(DataSourcePool pool, Connection connection) {onBeforeReturnConnection(connection);}

/**
* Called before a connection will be put back to the connection pool.
*
* Migrate to <code>onBeforeReturnConnection(DataSourcePool pool, Connection connection)</code>
*/
@Deprecated
default void onBeforeReturnConnection(Connection connection) {}

/**
* Called after a connection will be put back to the connection pool
*/
default void onAfterReturnConnection(DataSourcePool pool) {}

/**
* Called before a connection has been closed
*/
default void onBeforeCloseConnection(DataSourcePool pool, Connection connection) {}

/**
* Called after a connection had been closed
*/
default void onAfterCloseConnection(DataSourcePool pool) {}
}
9 changes: 8 additions & 1 deletion ebean-datasource/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test-containers</artifactId>
<version>7.3</version>
<version>7.6</version>
<scope>test</scope>
</dependency>

Expand Down Expand Up @@ -83,6 +83,13 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>3.5.1</version>
<scope>test</scope>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ void pstmtCacheMetrics(PstmtCache pstmtCache) {
pscRem.add(pstmtCache.removeCount());
}



final class HeartBeatRunnable extends TimerTask {
@Override
public void run() {
Expand Down Expand Up @@ -446,7 +448,20 @@ private Connection initConnection(Connection conn) throws SQLException {
}

private Connection createConnection() throws SQLException {
return initConnection(source.getConnection());

if (poolListener != null) {
poolListener.onBeforeCreateConnection(this);
}
Connection connection = initConnection(source.getConnection());
if (poolListener != null) {
poolListener.onAfterCreateConnection(this, connection);
}
return connection;
}

@Override
public int forceTrim(int trimCount) {
return queue.forceTrim(trimCount);
}

@Override
Expand Down Expand Up @@ -559,9 +574,12 @@ void removeClosedConnection(PooledConnection pooledConnection) {
*/
private void returnTheConnection(PooledConnection pooledConnection, boolean forceClose) {
if (poolListener != null && !forceClose) {
poolListener.onBeforeReturnConnection(pooledConnection);
poolListener.onBeforeReturnConnection(this, pooledConnection);
}
queue.returnPooledConnection(pooledConnection, forceClose);
if (poolListener != null && !forceClose) {
poolListener.onAfterReturnConnection(this);
}
}

void returnConnectionReset(PooledConnection pooledConnection) {
Expand All @@ -570,6 +588,17 @@ void returnConnectionReset(PooledConnection pooledConnection) {
reset();
}

void onBeforeCloseConnection(PooledConnection pooledConnection) {
if (poolListener != null) {
poolListener.onBeforeCloseConnection(this, pooledConnection);
}
}

void onAfterCloseConnection() {
if (poolListener != null) {
poolListener.onAfterCloseConnection(this);
}
}
/**
* Grow the pool by creating a new connection. The connection can either be
* added to the available list, or returned.
Expand Down Expand Up @@ -608,7 +637,14 @@ private void reset() {
*/
@Override
public Connection getConnection(String username, String password) throws SQLException {
return initConnection(source.getConnection(username, password));
if (poolListener != null) {
poolListener.onBeforeCreateConnection(this);
}
Connection connection = initConnection(source.getConnection(username, password));
if (poolListener != null) {
poolListener.onAfterCreateConnection(this, connection);
}
return connection;
}

/**
Expand All @@ -626,12 +662,15 @@ public Connection getConnection() throws SQLException {
* will go into a wait if the pool has hit its maximum size.
*/
private PooledConnection getPooledConnection() throws SQLException {
if (poolListener != null) {
poolListener.onBeforeBorrowConnection(this);
}
PooledConnection c = queue.obtainConnection();
if (captureStackTrace) {
c.setStackTrace(Thread.currentThread().getStackTrace());
}
if (poolListener != null) {
poolListener.onAfterBorrowConnection(c);
poolListener.onAfterBorrowConnection(this, c);
}
return c;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ void closeAll(boolean logErrors) {
/**
* Trim any inactive connections that have not been used since usedSince.
*/
int trim(int minSize, long usedSince, long createdSince) {
int trim(int minSize, long usedSince, long createdSince, boolean forced) {
int trimCount = 0;
ListIterator<PooledConnection> iterator = freeBuffer.listIterator(minSize);
while (iterator.hasNext()) {
PooledConnection pooledConnection = iterator.next();
if (pooledConnection.shouldTrim(usedSince, createdSince)) {
if (pooledConnection.shouldTrim(usedSince, createdSince, forced)) {
iterator.remove();
pooledConnection.closeConnectionFully(true);
trimCount++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ final class PooledConnection extends ConnectionDelegator {
*/
private static final String REASON_RESET = "reset";

/**
* Marker for when connection is closed due a forced trim.
*/
private static final String REASON_FORCED = "forced";

/**
* Set when connection is idle in the pool. In general when in the pool the
* connection should not be modified.
Expand Down Expand Up @@ -237,6 +242,7 @@ void closeConnectionFully(boolean logErrors) {
}
if (pool != null) {
pool.pstmtCacheMetrics(pstmtCache);
pool.onBeforeCloseConnection(this);
}
try {
if (connection.isClosed()) {
Expand Down Expand Up @@ -276,6 +282,7 @@ void closeConnectionFully(boolean logErrors) {
try {
connection.close();
pool.dec();
pool.onAfterCloseConnection();
} catch (SQLException ex) {
if (logErrors || Log.isLoggable(System.Logger.Level.DEBUG)) {
Log.error("Error when fully closing connection [" + fullDescription() + "]", ex);
Expand Down Expand Up @@ -363,7 +370,7 @@ private PreparedStatement prepareStatement(String sql, boolean useFlag, int flag
lastStatement = sql;
// try to get a matching cached PStmt from the cache.
ExtendedPreparedStatement pstmt = pstmtCache.remove(cacheKey);
if (pstmt != null) {
if (pstmt != null && !pstmt.isClosed()) {
return pstmt.reset();
}

Expand Down Expand Up @@ -543,7 +550,7 @@ boolean shouldTrimOnReturn(long lastResetTime, long maxAgeMillis) {
/**
* Return true if the connection has been idle for too long or is too old.
*/
boolean shouldTrim(long usedSince, long createdSince) {
boolean shouldTrim(long usedSince, long createdSince, boolean forced) {
if (lastUseTime < usedSince) {
// been idle for too long so trim it
this.closeReason = REASON_IDLE;
Expand All @@ -554,6 +561,10 @@ boolean shouldTrim(long usedSince, long createdSince) {
this.closeReason = REASON_MAXAGE;
return true;
}
if (forced) {
this.closeReason = REASON_FORCED;
return true;
}
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io.ebean.datasource.pool.ConnectionPool.Status;

import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
Expand Down Expand Up @@ -376,10 +377,10 @@ private boolean trimInactiveConnections(long maxInactiveMillis, long maxAgeMilli
if (freeList.size() > minSize) {
// trim on maxInactive and maxAge
long usedSince = System.currentTimeMillis() - maxInactiveMillis;
trimmedCount = freeList.trim(minSize, usedSince, createdSince);
trimmedCount = freeList.trim(minSize, usedSince, createdSince, false);
} else if (createdSince > 0) {
// trim only on maxAge
trimmedCount = freeList.trim(0, createdSince, createdSince);
trimmedCount = freeList.trim(0, createdSince, createdSince, false);
} else {
trimmedCount = 0;
}
Expand All @@ -401,6 +402,27 @@ private void closeFreeConnections(boolean logErrors) {
}
}

int forceTrim(int trimCount) {
int trimmedCount = 0;
lock.lock();
try {
int trimStart = freeList.size() - trimCount;
trimStart = Math.max(trimStart, 0);

if (freeList.size() > trimStart) {
trimmedCount = freeList.trim(trimStart, 0, 0, true);
}
} finally {
lock.unlock();
}
if (trimmedCount != 0) {
if (Log.isLoggable(DEBUG)) {
Log.debug("DataSource [{0}] forced trimmed [{1}] connections. New size[{2}]", name, trimmedCount, totalConnections());
}
}
return trimmedCount;
}

/**
* Close any busy connections that have not been used for some time.
* <p>
Expand Down
Loading
Loading