From 053fdf4abb571ed3a73e09d77ff058dbbba240ec Mon Sep 17 00:00:00 2001 From: rbygrave Date: Fri, 29 May 2015 20:49:55 +1200 Subject: [PATCH] No effective change - format and tidy --- .../server/lib/sql/PooledConnection.java | 1014 ++++++++--------- 1 file changed, 485 insertions(+), 529 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnection.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnection.java index 7c9a7a475..611daa827 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnection.java +++ b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnection.java @@ -19,17 +19,17 @@ import com.avaje.ebeaninternal.jdbc.ConnectionDelegator; /** * Is a connection that belongs to a DataSourcePool. - * + *

*

* It is designed to be part of DataSourcePool. Closing the connection puts it * back into the pool. *

- * + *

*

* It defaults autoCommit and Transaction Isolation to the defaults of the * DataSourcePool. *

- * + *

*

* It has caching of Statements and PreparedStatements. Remembers the last * statement that was executed. Keeps statistics on how long it is in use. @@ -37,153 +37,153 @@ import com.avaje.ebeaninternal.jdbc.ConnectionDelegator; */ public class PooledConnection extends ConnectionDelegator { - private static final Logger logger = LoggerFactory.getLogger(PooledConnection.class); + private static final Logger logger = LoggerFactory.getLogger(PooledConnection.class); - private static final String IDLE_CONNECTION_ACCESSED_ERROR = "Pooled Connection has been accessed whilst idle in the pool, via method: "; + private static final String IDLE_CONNECTION_ACCESSED_ERROR = "Pooled Connection has been accessed whilst idle in the pool, via method: "; - /** - * Marker for when connection is closed due to exceeding the max allowed age. - */ - private static final String REASON_MAXAGE = "maxAge"; - - /** - * Marker for when connection is closed due to exceeding the max inactive time. - */ - private static final String REASON_IDLE = "idleTime"; - - /** - * Marker for when the connection is closed due to a reset. - */ + /** + * Marker for when connection is closed due to exceeding the max allowed age. + */ + private static final String REASON_MAXAGE = "maxAge"; + + /** + * Marker for when connection is closed due to exceeding the max inactive time. + */ + private static final String REASON_IDLE = "idleTime"; + + /** + * Marker for when the connection is closed due to a reset. + */ private static final String REASON_RESET = "reset"; - - /** - * Set when connection is idle in the pool. In general when in the pool the - * connection should not be modified. - */ - private static final int STATUS_IDLE = 88; - /** - * Set when connection given to client. - */ - private static final int STATUS_ACTIVE = 89; + /** + * Set when connection is idle in the pool. In general when in the pool the + * connection should not be modified. + */ + private static final int STATUS_IDLE = 88; - /** - * Set when commit() or rollback() called. - */ - private static final int STATUS_ENDED = 87; + /** + * Set when connection given to client. + */ + private static final int STATUS_ACTIVE = 89; - /** - * Name used to identify the PooledConnection for logging. - */ - private final String name; + /** + * Set when commit() or rollback() called. + */ + private static final int STATUS_ENDED = 87; - /** - * The pool this connection belongs to. - */ - private final DataSourcePool pool; + /** + * Name used to identify the PooledConnection for logging. + */ + private final String name; - /** - * The underlying connection. - */ - private final Connection connection; + /** + * The pool this connection belongs to. + */ + private final DataSourcePool pool; - /** - * The time this connection was created. - */ - private final long creationTime; + /** + * The underlying connection. + */ + private final Connection connection; - /** - * Cache of the PreparedStatements - */ - private final PstmtCache pstmtCache; + /** + * The time this connection was created. + */ + private final long creationTime; - private final Object pstmtMonitor = new Object(); - - /** - * Helper for statistics collection. - */ - private final PooledConnectionStatistics stats = new PooledConnectionStatistics(); + /** + * Cache of the PreparedStatements + */ + private final PstmtCache pstmtCache; - /** - * The status of the connection. IDLE, ACTIVE or ENDED. - */ - private int status = STATUS_IDLE; + private final Object pstmtMonitor = new Object(); - /** - * The reason for a connection closing. - */ - private String closeReason; - - /** - * Set this to true if the connection will be busy for a long time. - *

- * This means it should skip the suspected connection pool leak checking. - *

- */ - private boolean longRunning; - - /** - * Flag to indicate that this connection had errors and should be checked to - * make sure it is okay. - */ - private boolean hadErrors; + /** + * Helper for statistics collection. + */ + private final PooledConnectionStatistics stats = new PooledConnectionStatistics(); - /** - * The last start time. When the connection was given to a thread. - */ - private long startUseTime; + /** + * The status of the connection. IDLE, ACTIVE or ENDED. + */ + private int status = STATUS_IDLE; - /** - * The last end time of this connection. This is to calculate the usage - * time. - */ - private long lastUseTime; - - private long exeStartNanos; - - /** - * The last statement executed by this connection. - */ - private String lastStatement; + /** + * The reason for a connection closing. + */ + private String closeReason; - /** - * The non avaje method that created the connection. - */ - private String createdByMethod; + /** + * Set this to true if the connection will be busy for a long time. + *

+ * This means it should skip the suspected connection pool leak checking. + *

+ */ + private boolean longRunning; - /** - * Used to find connection pool leaks. - */ - private StackTraceElement[] stackTrace; + /** + * Flag to indicate that this connection had errors and should be checked to + * make sure it is okay. + */ + private boolean hadErrors; - private int maxStackTrace; - - /** - * Slot position in the BusyConnectionBuffer. - */ - private int slotId; + /** + * The last start time. When the connection was given to a thread. + */ + private long startUseTime; - private boolean resetIsolationReadOnlyRequired; + /** + * The last end time of this connection. This is to calculate the usage + * time. + */ + private long lastUseTime; - - /** - * Construct the connection that can refer back to the pool it belongs to. - *

- * close() will return the connection back to the pool , while - * closeDestroy() will close() the underlining connection properly. - *

- */ - public PooledConnection(DataSourcePool pool, int uniqueId, Connection connection) throws SQLException { - super(connection); - - this.pool = pool; - this.connection = connection; - this.name = pool.getName() + "." + uniqueId; - this.pstmtCache = new PstmtCache(name, pool.getPstmtCacheSize()); - this.maxStackTrace = pool.getMaxStackTraceSize(); - this.creationTime = System.currentTimeMillis(); - this.lastUseTime = creationTime; - } + private long exeStartNanos; + + /** + * The last statement executed by this connection. + */ + private String lastStatement; + + /** + * The non avaje method that created the connection. + */ + private String createdByMethod; + + /** + * Used to find connection pool leaks. + */ + private StackTraceElement[] stackTrace; + + private int maxStackTrace; + + /** + * Slot position in the BusyConnectionBuffer. + */ + private int slotId; + + private boolean resetIsolationReadOnlyRequired; + + + /** + * Construct the connection that can refer back to the pool it belongs to. + *

+ * close() will return the connection back to the pool , while + * closeDestroy() will close() the underlining connection properly. + *

+ */ + public PooledConnection(DataSourcePool pool, int uniqueId, Connection connection) throws SQLException { + super(connection); + + this.pool = pool; + this.connection = connection; + this.name = pool.getName() + "." + uniqueId; + this.pstmtCache = new PstmtCache(name, pool.getPstmtCacheSize()); + this.maxStackTrace = pool.getMaxStackTraceSize(); + this.creationTime = System.currentTimeMillis(); + this.lastUseTime = creationTime; + } /** * For testing the pool without real connections. @@ -214,467 +214,427 @@ public class PooledConnection extends ConnectionDelegator { } /** - * Return the DataSourcePool that this connection belongs to. + * Return a string to identify the connection. */ - public DataSourcePool getDataSourcePool() { - return pool; + public String getName() { + return name; + } + + public String getNameSlot() { + return name + ":" + slotId; + } + + public String toString() { + return getDescription(); + } + + public long getBusySeconds() { + return (System.currentTimeMillis() - startUseTime) / 1000; + } + + public String getDescription() { + return "name[" + name + "] slot[" + slotId + "] startTime[" + getStartUseTime() + "] busySeconds[" + getBusySeconds() + "] createdBy[" + getCreatedByMethod() + "] stmt[" + getLastStatement() + "]"; + } + + public String getFullDescription() { + return "name[" + name + "] slot[" + slotId + "] startTime[" + getStartUseTime() + "] busySeconds[" + getBusySeconds() + "] stackTrace[" + getStackTraceAsString() + "] stmt[" + getLastStatement() + "]"; + } + + public PooledConnectionStatistics getStatistics() { + return stats; } /** - * Return the time the connection was created. + * Return true if the connection should be treated as long running (skip connection pool leak check). */ - public long getCreationTime() { - return creationTime; + public boolean isLongRunning() { + return longRunning; } - /** - * Return a string to identify the connection. - */ - public String getName() { - return name; - } - - public String getNameSlot() { - return name+":"+slotId; - } - - public String toString() { - return getDescription(); - } - - public long getBusySeconds() { - return (System.currentTimeMillis() - startUseTime)/1000; - } - - public String getDescription() { - return "name["+name+"] slot["+slotId+"] startTime["+getStartUseTime()+"] busySeconds["+getBusySeconds()+"] createdBy["+getCreatedByMethod()+"] stmt["+getLastStatement()+"]"; - } - - public String getFullDescription() { - return "name["+name+"] slot["+slotId+"] startTime["+getStartUseTime()+"] busySeconds["+getBusySeconds()+"] stackTrace["+getStackTraceAsString()+"] stmt["+getLastStatement()+"]"; + /** + * Set this to true if the connection is a long running connection and should skip the + * 'suspected connection pool leak' checking. + */ + public void setLongRunning(boolean longRunning) { + this.longRunning = longRunning; } - public String getPstmtStatistics() { - return "name["+name+"] startTime["+getStartUseTime()+"] "+pstmtCache.getDescription(); - } - - public PooledConnectionStatistics getStatistics() { - return stats; - } - - /** - * Return true if the connection should be treated as long running (skip connection pool leak check). - */ - public boolean isLongRunning() { - return longRunning; - } + /** + * Close the connection fully NOT putting in back into the pool. + *

+ * The logErrors parameter exists so that expected errors are not logged + * such as when the database is known to be down. + *

+ * + * @param logErrors if false then don't log errors when closing + */ + public void closeConnectionFully(boolean logErrors) { - /** - * Set this to true if the connection is a long running connection and should skip the - * 'suspected connection pool leak' checking. - */ - public void setLongRunning(boolean longRunning) { - this.longRunning = longRunning; - } + if (pool != null) { + // allow collection of load statistics + pool.reportClosingConnection(this); + } - /** - * Close the connection fully NOT putting in back into the pool. - *

- * The logErrors parameter exists so that expected errors are not logged - * such as when the database is known to be down. - *

- * - * @param logErrors - * if false then don't log errors when closing - */ - public void closeConnectionFully(boolean logErrors) { + if (logger.isDebugEnabled()) { + logger.debug("Closing Connection[{}] slot[{}] reason[{}] stats: {} , pstmtStats: {} ", name, slotId, closeReason, stats.getValues(false), pstmtCache.getDescription()); + } - if (pool != null) { - // allow collection of load statistics - pool.reportClosingConnection(this); - } - - if (logger.isDebugEnabled()) { - logger.debug("Closing Connection[{}] slot[{}] reason[{}] stats: {} , pstmtStats: {} ", name, slotId, closeReason, stats.getValues(false), pstmtCache.getDescription()); - } + try { + if (connection.isClosed()) { + // Typically the JDBC Driver has its own JVM shutdown hook and already + // closed the connections in our DataSource pool so making this DEBUG level + logger.debug("Closing Connection[{}] that is already closed?", name); + return; + } + } catch (SQLException ex) { + if (logErrors) { + logger.error("Error checking if connection [" + getNameSlot() + "] is closed", ex); + } + } - try { - if (connection.isClosed()) { - // Typically the JDBC Driver has its own JVM shutdown hook and already - // closed the connections in our DataSource pool so making this DEBUG level - logger.debug("Closing Connection[{}] that is already closed?", name); - return; - } - } catch (SQLException ex) { - if (logErrors) { - logger.error("Error checking if connection [" + getNameSlot() + "] is closed", ex); - } - } - - try { - for (ExtendedPreparedStatement ps : pstmtCache.values()) { + try { + for (ExtendedPreparedStatement ps : pstmtCache.values()) { ps.closeDestroy(); } - } catch (SQLException ex) { - if (logErrors) { - logger.warn("Error when closing connection Statements", ex); - } - } + } catch (SQLException ex) { + if (logErrors) { + logger.warn("Error when closing connection Statements", ex); + } + } - try { - connection.close(); - } catch (SQLException ex) { - if (logErrors || logger.isDebugEnabled()) { - logger.error("Error when fully closing connection [" + getFullDescription() + "]", ex); - } - } - } + try { + connection.close(); + } catch (SQLException ex) { + if (logErrors || logger.isDebugEnabled()) { + logger.error("Error when fully closing connection [" + getFullDescription() + "]", ex); + } + } + } - /** - * A Least Recently used cache of PreparedStatements. - */ - public PstmtCache getPstmtCache() { - return pstmtCache; - } + /** + * Creates a wrapper ExtendedStatement so that I can get the executed sql. I + * want to do this so that I can get the slowest query statments etc, and + * log that information. + */ + public Statement createStatement() throws SQLException { + if (status == STATUS_IDLE) { + throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "createStatement()"); + } + try { + return connection.createStatement(); + } catch (SQLException ex) { + addError(ex); + throw ex; + } + } - /** - * Creates a wrapper ExtendedStatement so that I can get the executed sql. I - * want to do this so that I can get the slowest query statments etc, and - * log that information. - */ - public Statement createStatement() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "createStatement()"); - } - try { - return connection.createStatement(); - } catch (SQLException ex) { - addError(ex); - throw ex; - } - } + public Statement createStatement(int resultSetType, int resultSetConcurreny) throws SQLException { + if (status == STATUS_IDLE) { + throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "createStatement()"); + } + try { + return connection.createStatement(resultSetType, resultSetConcurreny); - public Statement createStatement(int resultSetType, int resultSetConcurreny) throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "createStatement()"); - } - try { - return connection.createStatement(resultSetType, resultSetConcurreny); + } catch (SQLException ex) { + addError(ex); + throw ex; + } + } - } catch (SQLException ex) { - addError(ex); - throw ex; - } - } + /** + * Return a PreparedStatement back into the cache. + */ + protected void returnPreparedStatement(ExtendedPreparedStatement pstmt) { - /** - * Return a PreparedStatement back into the cache. - */ - protected void returnPreparedStatement(ExtendedPreparedStatement pstmt) { - - synchronized (pstmtMonitor) { - if (!pstmtCache.returnStatement(pstmt)) { - try { + synchronized (pstmtMonitor) { + if (!pstmtCache.returnStatement(pstmt)) { + try { // Already an entry in the cache with the exact same SQL... pstmt.closeDestroy(); } catch (SQLException e) { logger.error("Error closing Pstmt", e); } - } - } - } + } + } + } - /** - * This will try to use a cache of PreparedStatements. - */ - public PreparedStatement prepareStatement(String sql, int returnKeysFlag) throws SQLException { - String cacheKey = sql + returnKeysFlag; - return prepareStatement(sql, true, returnKeysFlag, cacheKey); - } + /** + * This will try to use a cache of PreparedStatements. + */ + public PreparedStatement prepareStatement(String sql, int returnKeysFlag) throws SQLException { + String cacheKey = sql + returnKeysFlag; + return prepareStatement(sql, true, returnKeysFlag, cacheKey); + } - /** - * This will try to use a cache of PreparedStatements. - */ - public PreparedStatement prepareStatement(String sql) throws SQLException { - return prepareStatement(sql, false, 0, sql); - } + /** + * This will try to use a cache of PreparedStatements. + */ + public PreparedStatement prepareStatement(String sql) throws SQLException { + return prepareStatement(sql, false, 0, sql); + } - /** - * This will try to use a cache of PreparedStatements. - */ - private PreparedStatement prepareStatement(String sql, boolean useFlag, int flag, String cacheKey) throws SQLException { - - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "prepareStatement()"); - } - try { - synchronized (pstmtMonitor) { - lastStatement = sql; - - // try to get a matching cached PStmt from the cache. - ExtendedPreparedStatement pstmt = pstmtCache.remove(cacheKey); - - if (pstmt != null) { - return pstmt; - } - - // create a new PreparedStatement - PreparedStatement actualPstmt; - if (useFlag) { - actualPstmt = connection.prepareStatement(sql, flag); - } else { - actualPstmt = connection.prepareStatement(sql); - } - return new ExtendedPreparedStatement(this, actualPstmt, sql, cacheKey); - } + /** + * This will try to use a cache of PreparedStatements. + */ + private PreparedStatement prepareStatement(String sql, boolean useFlag, int flag, String cacheKey) throws SQLException { - } catch (SQLException ex) { - addError(ex); - throw ex; - } - } + if (status == STATUS_IDLE) { + throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "prepareStatement()"); + } + try { + synchronized (pstmtMonitor) { + lastStatement = sql; - public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurreny) throws SQLException { - - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "prepareStatement()"); - } - try { - // no caching when creating PreparedStatements this way - lastStatement = sql; - return connection.prepareStatement(sql, resultSetType, resultSetConcurreny); - } catch (SQLException ex) { - addError(ex); - throw ex; - } - } + // try to get a matching cached PStmt from the cache. + ExtendedPreparedStatement pstmt = pstmtCache.remove(cacheKey); - /** - * Reset the connection for returning to the client. Resets the status, - * startUseTime and hadErrors. - */ - protected void resetForUse() { - this.status = STATUS_ACTIVE; - this.startUseTime = System.currentTimeMillis(); - this.exeStartNanos = System.nanoTime(); - this.createdByMethod = null; - this.lastStatement = null; - this.hadErrors = false; - this.longRunning = false; - } + if (pstmt != null) { + return pstmt; + } - /** - * When an error occurs during use add it the connection. - *

- * Any PooledConnection that has an error is checked to make sure it works - * before it is placed back into the connection pool. - *

- */ - public void addError(Throwable e) { - hadErrors = true; - } + // create a new PreparedStatement + PreparedStatement actualPstmt; + if (useFlag) { + actualPstmt = connection.prepareStatement(sql, flag); + } else { + actualPstmt = connection.prepareStatement(sql); + } + return new ExtendedPreparedStatement(this, actualPstmt, sql, cacheKey); + } - /** - * Returns true if the connect threw any errors during use. - *

- * Connections with errors are testing to make sure they are still good - * before putting them back into the pool. - *

- */ - public boolean hadErrors() { - return hadErrors; - } + } catch (SQLException ex) { + addError(ex); + throw ex; + } + } - /** - * close the connection putting it back into the connection pool. - *

- * Note that to ensure that the next transaction starts at the correct time - * a commit() or rollback() should be called. If neither has occured at this - * time then a rollback() is used (to end the transaction). - *

- *

- * To close the connection fully use closeConnectionFully(). - *

- */ - public void close() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "close()"); - } + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurreny) throws SQLException { - long durationNanos = System.nanoTime() - exeStartNanos; - stats.add(durationNanos, hadErrors); - - if (hadErrors) { - if (!pool.validateConnection(this)) { - // the connection is BAD, remove it, close it and test the pool - pool.returnConnectionForceClose(this); - return; - } - } + if (status == STATUS_IDLE) { + throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "prepareStatement()"); + } + try { + // no caching when creating PreparedStatements this way + lastStatement = sql; + return connection.prepareStatement(sql, resultSetType, resultSetConcurreny); + } catch (SQLException ex) { + addError(ex); + throw ex; + } + } - try { - // reset the autoCommit back if client code changed it - if (connection.getAutoCommit() != pool.getAutoCommit()) { - connection.setAutoCommit(pool.getAutoCommit()); - } - // Generally resetting Isolation level seems expensive. - // Hence using resetIsolationReadOnlyRequired flag - // performance reasons. - if (resetIsolationReadOnlyRequired) { - resetIsolationReadOnly(); - resetIsolationReadOnlyRequired = false; - } + /** + * Reset the connection for returning to the client. Resets the status, + * startUseTime and hadErrors. + */ + protected void resetForUse() { + this.status = STATUS_ACTIVE; + this.startUseTime = System.currentTimeMillis(); + this.exeStartNanos = System.nanoTime(); + this.createdByMethod = null; + this.lastStatement = null; + this.hadErrors = false; + this.longRunning = false; + } - // the connection is assumed GOOD so put it back in the pool - lastUseTime = System.currentTimeMillis(); - // connection.clearWarnings(); - status = STATUS_IDLE; - pool.returnConnection(this); + /** + * When an error occurs during use add it the connection. + *

+ * Any PooledConnection that has an error is checked to make sure it works + * before it is placed back into the connection pool. + *

+ */ + public void addError(Throwable throwable) { + hadErrors = true; + } - } catch (Exception ex) { + /** + * close the connection putting it back into the connection pool. + *

+ * Note that to ensure that the next transaction starts at the correct time + * a commit() or rollback() should be called. If neither has occured at this + * time then a rollback() is used (to end the transaction). + *

+ *

+ * To close the connection fully use closeConnectionFully(). + *

+ */ + public void close() throws SQLException { + if (status == STATUS_IDLE) { + throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "close()"); + } + + long durationNanos = System.nanoTime() - exeStartNanos; + stats.add(durationNanos, hadErrors); + + if (hadErrors) { + if (!pool.validateConnection(this)) { + // the connection is BAD, remove it, close it and test the pool + pool.returnConnectionForceClose(this); + return; + } + } + + try { + // reset the autoCommit back if client code changed it + if (connection.getAutoCommit() != pool.getAutoCommit()) { + connection.setAutoCommit(pool.getAutoCommit()); + } + // Generally resetting Isolation level seems expensive. + // Hence using resetIsolationReadOnlyRequired flag + // performance reasons. + if (resetIsolationReadOnlyRequired) { + resetIsolationReadOnly(); + resetIsolationReadOnlyRequired = false; + } + + // the connection is assumed GOOD so put it back in the pool + lastUseTime = System.currentTimeMillis(); + // connection.clearWarnings(); + status = STATUS_IDLE; + pool.returnConnection(this); + + } catch (Exception ex) { // the connection is BAD, remove it, close it and test the pool - logger.warn("Error when trying to return connection to pool, closing fully.", ex); + logger.warn("Error when trying to return connection to pool, closing fully.", ex); pool.returnConnectionForceClose(this); - } - } + } + } - private void resetIsolationReadOnly() throws SQLException { - // reset the transaction isolation if the client code changed it - if (connection.getTransactionIsolation() != pool.getTransactionIsolation()) { - connection.setTransactionIsolation(pool.getTransactionIsolation()); - } - // reset readonly to false - if (connection.isReadOnly()) { - connection.setReadOnly(false); - } - } + private void resetIsolationReadOnly() throws SQLException { + // reset the transaction isolation if the client code changed it + if (connection.getTransactionIsolation() != pool.getTransactionIsolation()) { + connection.setTransactionIsolation(pool.getTransactionIsolation()); + } + // reset readonly to false + if (connection.isReadOnly()) { + connection.setReadOnly(false); + } + } - protected void finalize() throws Throwable { - try { - if (connection != null && !connection.isClosed()) { - // connect leak? - logger.warn("Closing Connection on finalize() - {}", getFullDescription()); - closeConnectionFully(false); - } - } catch (Exception e) { - logger.error("Error when finalize is closing a connection? (unexpected)", e); - } - super.finalize(); - } + protected void finalize() throws Throwable { + try { + if (connection != null && !connection.isClosed()) { + // connect leak? + logger.warn("Closing Connection on finalize() - {}", getFullDescription()); + closeConnectionFully(false); + } + } catch (Exception e) { + logger.error("Error when finalize is closing a connection? (unexpected)", e); + } + super.finalize(); + } - /** - * Return true if the connection is too old. - */ + /** + * Return true if the connection is too old. + */ public boolean exceedsMaxAge(long maxAgeMillis) { - if (maxAgeMillis > 0 && (creationTime < (System.currentTimeMillis() - maxAgeMillis))){ + if (maxAgeMillis > 0 && (creationTime < (System.currentTimeMillis() - maxAgeMillis))) { this.closeReason = REASON_MAXAGE; return true; } return false; } - + public boolean shouldTrimOnReturn(long lastResetTime, long maxAgeMillis) { if (creationTime <= lastResetTime) { this.closeReason = REASON_RESET; return true; } - if (exceedsMaxAge(maxAgeMillis)) { + return exceedsMaxAge(maxAgeMillis); + } + + /** + * Return true if the connection has been idle for too long or is too old. + */ + public boolean shouldTrim(long usedSince, long createdSince) { + if (lastUseTime < usedSince) { + // been idle for too long so trim it + this.closeReason = REASON_IDLE; + return true; + } + if (createdSince > 0 && createdSince > creationTime) { + // exceeds max age so trim it + this.closeReason = REASON_MAXAGE; return true; } return false; } - + /** - * Return true if the connection has been idle for too long or is too old. + * Return the time the connection was passed to the client code. + *

+ * Used to detect busy connections that could be leaks. + *

*/ - public boolean shouldTrim(long usedSince, long createdSince) { - if (lastUseTime < usedSince) { - // been idle for too long so trim it - this.closeReason = REASON_IDLE; - return true; - } - if (createdSince > 0 && createdSince > creationTime) { - // exceeds max age so trim it - this.closeReason = REASON_MAXAGE; - return true; - } - return false; - } - - /** - * Return the time the connection was passed to the client code. - *

- * Used to detect busy connections that could be leaks. - *

- */ - public long getStartUseTime() { - return startUseTime; - } + public long getStartUseTime() { + return startUseTime; + } - /** - * Returns the time the connection was last used. - *

- * Used to close connections that have been idle for some time. Typically 5 - * minutes. - *

- */ - public long getLastUsedTime() { - return lastUseTime; - } + /** + * Returns the time the connection was last used. + *

+ * Used to close connections that have been idle for some time. Typically 5 + * minutes. + *

+ */ + public long getLastUsedTime() { + return lastUseTime; + } - /** - * Returns the last sql statement executed. - */ - public String getLastStatement() { - return lastStatement; - } + /** + * Returns the last sql statement executed. + */ + public String getLastStatement() { + return lastStatement; + } - /** - * Called by ExtendedStatement to trace the sql being executed. - *

- * Note with addBatch() this will not really work. - *

- */ - protected void setLastStatement(String lastStatement) { - this.lastStatement = lastStatement; - if (logger.isTraceEnabled()) { - logger.trace(".setLastStatement[" + lastStatement + "]"); - } - } + /** + * Called by ExtendedStatement to trace the sql being executed. + *

+ * Note with addBatch() this will not really work. + *

+ */ + protected void setLastStatement(String lastStatement) { + this.lastStatement = lastStatement; + if (logger.isTraceEnabled()) { + logger.trace(".setLastStatement[" + lastStatement + "]"); + } + } - /** - * Also note the read only status needs to be reset when put back into the - * pool. - */ - public void setReadOnly(boolean readOnly) throws SQLException { - // A bit loose not checking for STATUS_IDLE - // if (status == STATUS_IDLE) { - // throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + - // "setReadOnly()"); - // } - resetIsolationReadOnlyRequired = true; - connection.setReadOnly(readOnly); - } + /** + * Also note the read only status needs to be reset when put back into the + * pool. + */ + public void setReadOnly(boolean readOnly) throws SQLException { + // A bit loose not checking for STATUS_IDLE + // if (status == STATUS_IDLE) { + // throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + + // "setReadOnly()"); + // } + resetIsolationReadOnlyRequired = true; + connection.setReadOnly(readOnly); + } - /** - * Also note the Isolation level needs to be reset when put back into the - * pool. - */ - public void setTransactionIsolation(int level) throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "setTransactionIsolation()"); - } - try { - resetIsolationReadOnlyRequired = true; - connection.setTransactionIsolation(level); - } catch (SQLException ex) { - addError(ex); - throw ex; - } - } + /** + * Also note the Isolation level needs to be reset when put back into the + * pool. + */ + public void setTransactionIsolation(int level) throws SQLException { + if (status == STATUS_IDLE) { + throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "setTransactionIsolation()"); + } + try { + resetIsolationReadOnlyRequired = true; + connection.setTransactionIsolation(level); + } catch (SQLException ex) { + addError(ex); + throw ex; + } + } // // @@ -937,9 +897,7 @@ public class PooledConnection extends ConnectionDelegator { for (int j = 0; j < stackTrace.length; j++) { String methodLine = stackTrace[j].toString(); - if (skipElement(methodLine)) { - // ignore these methods... - } else { + if (!skipElement(methodLine)) { createdByMethod = methodLine; return createdByMethod; } @@ -959,10 +917,8 @@ public class PooledConnection extends ConnectionDelegator { } else if (methodLine.startsWith("com.avaje.ebeaninternal.server.query.Callable")) { // it is a future task being executed... return false; - } else if (methodLine.startsWith("com.avaje.ebeaninternal")) { - return true; } else { - return false; + return methodLine.startsWith("com.avaje.ebeaninternal"); } } @@ -978,7 +934,7 @@ public class PooledConnection extends ConnectionDelegator { */ public String getStackTraceAsString() { StackTraceElement[] stackTrace = getStackTrace(); - if (stackTrace == null){ + if (stackTrace == null) { return ""; } return Arrays.toString(stackTrace);