Author: psteitz Date: Fri Mar 20 17:07:44 2009 New Revision: 756628 URL: http://svn.apache.org/viewvc?rev=756628&view=rev Log: Added a validationQueryTimeout configuration parameter to BasicDataSource allowing the user to specify a timeout value (in seconds) for connection validation queries. JIRA: DBCP-226
Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/PoolableConnectionFactory.java commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSource.java commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterStatement.java commons/proper/dbcp/trunk/xdocs/changes.xml Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java?rev=756628&r1=756627&r2=756628&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java (original) +++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java Fri Mar 20 17:07:44 2009 @@ -811,6 +811,42 @@ } /** + * Timeout in seconds before connection validation queries fail. + * + * @since 1.3 + */ + protected int validationQueryTimeout = -1; + + /** + * Returns the validation query timeout. + * + * @return the timeout in seconds before connection validation queries fail. + * @since 1.3 + */ + public synchronized int getValidationQueryTimeout() { + return validationQueryTimeout; + } + + /** + * Sets the validation query timeout, the amount of time, in seconds, that + * connection validation will wait for a response from the database when + * executing a validation query. Use a value less than or equal to 0 for + * no timeout. + * <p> + * Note: this method currently has no effect once the pool has been + * initialized. The pool is initialized the first time one of the + * following methods is invoked: <code>getConnection, setLogwriter, + * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> + * + * @param timeout new validation query timeout value in seconds + * @since 1.3 + */ + public synchronized void setValidationQueryTimeout(int timeout) { + this.validationQueryTimeout = timeout; + restartNeeded = true; + } + + /** * These SQL statements run once after a Connection is created. * <p> * This property can be used for example to run ALTER SESSION SET @@ -1303,6 +1339,7 @@ connectionPool, statementPoolFactory, validationQuery, + validationQueryTimeout, connectionInitSqls, defaultReadOnly, defaultAutoCommit, Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/PoolableConnectionFactory.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/PoolableConnectionFactory.java?rev=756628&r1=756627&r2=756628&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/PoolableConnectionFactory.java (original) +++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/PoolableConnectionFactory.java Fri Mar 20 17:07:44 2009 @@ -79,6 +79,52 @@ _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE; _defaultAutoCommit = defaultAutoCommit; } + + /** + * Create a new <tt>PoolableConnectionFactory</tt>. + * @param connFactory the {...@link ConnectionFactory} from which to obtain base {...@link Connection}s + * @param pool the {...@link ObjectPool} in which to pool those {...@link Connection}s + * @param stmtPoolFactory the {...@link KeyedObjectPoolFactory} to use to create {...@link KeyedObjectPool}s for pooling {...@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {...@link java.sql.PreparedStatement} pooling + * @param validationQuery a query to use to {...@link #validateObject validate} {...@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. + * @param validationQueryTimeout the number of seconds that validation queries will wait for database response before failing. Use a value less than or equal to 0 for no timeout. + * @param defaultReadOnly the default "read only" setting for borrowed {...@link Connection}s + * @param defaultAutoCommit the default "auto commit" setting for returned {...@link Connection}s + * @since 1.3 + */ + public PoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, int validationQueryTimeout, boolean defaultReadOnly, boolean defaultAutoCommit) { + _connFactory = connFactory; + _pool = pool; + _pool.setFactory(this); + _stmtPoolFactory = stmtPoolFactory; + _validationQuery = validationQuery; + _validationQueryTimeout = validationQueryTimeout; + _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE; + _defaultAutoCommit = defaultAutoCommit; + } + + /** + * Create a new <tt>PoolableConnectionFactory</tt>. + * @param connFactory the {...@link ConnectionFactory} from which to obtain base {...@link Connection}s + * @param pool the {...@link ObjectPool} in which to pool those {...@link Connection}s + * @param stmtPoolFactory the {...@link KeyedObjectPoolFactory} to use to create {...@link KeyedObjectPool}s for pooling {...@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {...@link java.sql.PreparedStatement} pooling + * @param validationQuery a query to use to {...@link #validateObject validate} {...@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. + * @param validationQueryTimeout the number of seconds that validation queries will wait for database response before failing. Use a value less than or equal to 0 for no timeout. + * @param connectionInitSqls a Collection of SQL statements to initialize {...@link Connection}s. Using <tt>null</tt> turns off initialization. + * @param defaultReadOnly the default "read only" setting for borrowed {...@link Connection}s + * @param defaultAutoCommit the default "auto commit" setting for returned {...@link Connection}s + * @since 1.3 + */ + public PoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, int validationQueryTimeout, Collection connectionInitSqls, boolean defaultReadOnly, boolean defaultAutoCommit) { + _connFactory = connFactory; + _pool = pool; + _pool.setFactory(this); + _stmtPoolFactory = stmtPoolFactory; + _validationQuery = validationQuery; + _validationQueryTimeout = validationQueryTimeout; + _connectionInitSqls = connectionInitSqls; + _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE; + _defaultAutoCommit = defaultAutoCommit; + } /** * Create a new <tt>PoolableConnectionFactory</tt>. @@ -124,6 +170,56 @@ _defaultAutoCommit = defaultAutoCommit; _defaultTransactionIsolation = defaultTransactionIsolation; } + + /** + * Create a new <tt>PoolableConnectionFactory</tt>. + * @param connFactory the {...@link ConnectionFactory} from which to obtain base {...@link Connection}s + * @param pool the {...@link ObjectPool} in which to pool those {...@link Connection}s + * @param stmtPoolFactory the {...@link KeyedObjectPoolFactory} to use to create {...@link KeyedObjectPool}s for pooling {...@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {...@link java.sql.PreparedStatement} pooling + * @param validationQuery a query to use to {...@link #validateObject validate} {...@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. + * @param validationQueryTimeout the number of seconds that validation queries will wait for database response before failing. Use a value less than or equal to 0 for no timeout. + * @param defaultReadOnly the default "read only" setting for borrowed {...@link Connection}s + * @param defaultAutoCommit the default "auto commit" setting for returned {...@link Connection}s + * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {...@link Connection}s + * @since 1.3 + */ + public PoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, int validationQueryTimeout, boolean defaultReadOnly, boolean defaultAutoCommit, int defaultTransactionIsolation) { + _connFactory = connFactory; + _pool = pool; + _pool.setFactory(this); + _stmtPoolFactory = stmtPoolFactory; + _validationQuery = validationQuery; + _validationQueryTimeout = validationQueryTimeout; + _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE; + _defaultAutoCommit = defaultAutoCommit; + _defaultTransactionIsolation = defaultTransactionIsolation; + } + + /** + * Create a new <tt>PoolableConnectionFactory</tt>. + * @param connFactory the {...@link ConnectionFactory} from which to obtain base {...@link Connection}s + * @param pool the {...@link ObjectPool} in which to pool those {...@link Connection}s + * @param stmtPoolFactory the {...@link KeyedObjectPoolFactory} to use to create {...@link KeyedObjectPool}s for pooling {...@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {...@link java.sql.PreparedStatement} pooling + * @param validationQuery a query to use to {...@link #validateObject validate} {...@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. + * @param validationQueryTimeout the number of seconds that validation queries will wait for database response before failing. Use a value less than or equal to 0 for no timeout. + * @param connectionInitSqls a Collection of SQL statement to initialize {...@link Connection}s. Using <tt>null</tt> turns off initialization. + * @param defaultReadOnly the default "read only" setting for borrowed {...@link Connection}s + * @param defaultAutoCommit the default "auto commit" setting for returned {...@link Connection}s + * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {...@link Connection}s + * @since 1.3 + */ + public PoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, int validationQueryTimeout, Collection connectionInitSqls, boolean defaultReadOnly, boolean defaultAutoCommit, int defaultTransactionIsolation) { + _connFactory = connFactory; + _pool = pool; + _pool.setFactory(this); + _stmtPoolFactory = stmtPoolFactory; + _validationQuery = validationQuery; + _validationQueryTimeout = validationQueryTimeout; + _connectionInitSqls = connectionInitSqls; + _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE; + _defaultAutoCommit = defaultAutoCommit; + _defaultTransactionIsolation = defaultTransactionIsolation; + } /** * Create a new <tt>PoolableConnectionFactory</tt>. @@ -297,6 +393,87 @@ _defaultTransactionIsolation = defaultTransactionIsolation; _defaultCatalog = defaultCatalog; } + + /** + * Create a new <tt>PoolableConnectionFactory</tt>. + * @param connFactory the {...@link ConnectionFactory} from which to obtain base {...@link Connection}s + * @param pool the {...@link ObjectPool} in which to pool those {...@link Connection}s + * @param stmtPoolFactory the {...@link KeyedObjectPoolFactory} to use to create {...@link KeyedObjectPool}s for pooling {...@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {...@link java.sql.PreparedStatement} pooling + * @param validationQuery a query to use to {...@link #validateObject validate} {...@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. + * @param validationQueryTimeout the number of seconds that validation queries will wait for database response before failing. Use a value less than or equal to 0 for no timeout. + * @param defaultReadOnly the default "read only" setting for borrowed {...@link Connection}s + * @param defaultAutoCommit the default "auto commit" setting for returned {...@link Connection}s + * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {...@link Connection}s + * @param defaultCatalog the default "catalog" setting for returned {...@link Connection}s + * @param config the AbandonedConfig if tracing SQL objects + * @since 1.3 + */ + public PoolableConnectionFactory( + ConnectionFactory connFactory, + ObjectPool pool, + KeyedObjectPoolFactory stmtPoolFactory, + String validationQuery, + int validationQueryTimeout, + Boolean defaultReadOnly, + boolean defaultAutoCommit, + int defaultTransactionIsolation, + String defaultCatalog, + AbandonedConfig config) { + + _connFactory = connFactory; + _pool = pool; + _config = config; + _pool.setFactory(this); + _stmtPoolFactory = stmtPoolFactory; + _validationQuery = validationQuery; + _validationQueryTimeout = validationQueryTimeout; + _defaultReadOnly = defaultReadOnly; + _defaultAutoCommit = defaultAutoCommit; + _defaultTransactionIsolation = defaultTransactionIsolation; + _defaultCatalog = defaultCatalog; + } + + /** + * Create a new <tt>PoolableConnectionFactory</tt>. + * @param connFactory the {...@link ConnectionFactory} from which to obtain base {...@link Connection}s + * @param pool the {...@link ObjectPool} in which to pool those {...@link Connection}s + * @param stmtPoolFactory the {...@link KeyedObjectPoolFactory} to use to create {...@link KeyedObjectPool}s for pooling {...@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {...@link java.sql.PreparedStatement} pooling + * @param validationQuery a query to use to {...@link #validateObject validate} {...@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. + * @param validationQueryTimeout the number of seconds that validation queries will wait for database response before failing. Use a value less than or equal to 0 for no timeout. + * @param connectionInitSqls a Collection of SQL statements to initialize {...@link Connection}s. Using <tt>null</tt> turns off initialization. + * @param defaultReadOnly the default "read only" setting for borrowed {...@link Connection}s + * @param defaultAutoCommit the default "auto commit" setting for returned {...@link Connection}s + * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {...@link Connection}s + * @param defaultCatalog the default "catalog" setting for returned {...@link Connection}s + * @param config the AbandonedConfig if tracing SQL objects + * @since 1.3 + */ + public PoolableConnectionFactory( + ConnectionFactory connFactory, + ObjectPool pool, + KeyedObjectPoolFactory stmtPoolFactory, + String validationQuery, + int validationQueryTimeout, + Collection connectionInitSqls, + Boolean defaultReadOnly, + boolean defaultAutoCommit, + int defaultTransactionIsolation, + String defaultCatalog, + AbandonedConfig config) { + + _connFactory = connFactory; + _pool = pool; + _config = config; + _pool.setFactory(this); + _stmtPoolFactory = stmtPoolFactory; + _validationQuery = validationQuery; + _validationQueryTimeout = validationQueryTimeout; + _connectionInitSqls = connectionInitSqls; + _defaultReadOnly = defaultReadOnly; + _defaultAutoCommit = defaultAutoCommit; + _defaultTransactionIsolation = defaultTransactionIsolation; + _defaultCatalog = defaultCatalog; + } /** * Sets the {...@link ConnectionFactory} from which to obtain base {...@link Connection}s. @@ -315,6 +492,19 @@ synchronized public void setValidationQuery(String validationQuery) { _validationQuery = validationQuery; } + + /** + * Sets the validation query timeout, the amount of time, in seconds, that + * connection validation will wait for a response from the database when + * executing a validation query. Use a value less than or equal to 0 for + * no timeout. + * + * @param timeout new validation query timeout value in seconds + * @since 1.3 + */ + synchronized public void setValidationQueryTimeout(int timeout) { + _validationQueryTimeout = timeout; + } /** * Sets the SQL statements I use to initialize newly created {...@link Connection}s. @@ -465,6 +655,9 @@ ResultSet rset = null; try { stmt = conn.createStatement(); + if (_validationQueryTimeout > 0) { + stmt.setQueryTimeout(_validationQueryTimeout); + } rset = stmt.executeQuery(query); if(!rset.next()) { throw new SQLException("validationQuery didn't return a row"); @@ -531,6 +724,7 @@ protected ConnectionFactory _connFactory = null; protected String _validationQuery = null; + protected int _validationQueryTimeout = -1; protected Collection _connectionInitSqls = null; protected ObjectPool _pool = null; protected KeyedObjectPoolFactory _stmtPoolFactory = null; Modified: commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSource.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSource.java?rev=756628&r1=756627&r2=756628&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSource.java (original) +++ commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSource.java Fri Mar 20 17:07:44 2009 @@ -234,6 +234,43 @@ } } } + + public void testValidationQueryTimoutFail() { + ds.setTestOnBorrow(true); + ds.setValidationQueryTimeout(3); // Too fast for TesterStatement + try { + ds.getConnection(); + fail("expected SQLException"); + } catch (SQLException ex) { + if (ex.toString().indexOf("timeout") < 0) { + fail("expected timeout error message"); + } + } + } + + public void testValidationQueryTimeoutZero() throws Exception { + ds.setTestOnBorrow(true); + ds.setTestOnReturn(true); + ds.setValidationQueryTimeout(0); + Connection con = ds.getConnection(); + con.close(); + } + + public void testValidationQueryTimeoutNegative() throws Exception { + ds.setTestOnBorrow(true); + ds.setTestOnReturn(true); + ds.setValidationQueryTimeout(-1); + Connection con = ds.getConnection(); + con.close(); + } + + public void testValidationQueryTimeoutSucceed() throws Exception { + ds.setTestOnBorrow(true); + ds.setTestOnReturn(true); + ds.setValidationQueryTimeout(100); // Works for TesterStatement + Connection con = ds.getConnection(); + con.close(); + } public void testEmptyInitConnectionSql() throws Exception { ds.setConnectionInitSqls(Arrays.asList(new String[]{"", " "})); Modified: commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterStatement.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterStatement.java?rev=756628&r1=756627&r2=756628&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterStatement.java (original) +++ commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterStatement.java Fri Mar 20 17:07:44 2009 @@ -60,15 +60,22 @@ checkOpen(); if("null".equals(sql)) { return null; - } if("invalid".equals(sql)) { + } + if("invalid".equals(sql)) { throw new SQLException("invalid query"); - } if ("broken".equals(sql)) { + } + if ("broken".equals(sql)) { throw new SQLException("broken connection"); - } if("select username".equals(sql)) { + } + if("select username".equals(sql)) { String username = ((TesterConnection) _connection).getUsername(); Object[][] data = {{username}}; return new TesterResultSet(this, data); } else { + // Simulate timeout if queryTimout is set to less than 5 seconds + if (_queryTimeout > 0 && _queryTimeout < 5) { + throw new SQLException("query timeout"); + } return new TesterResultSet(this); } } Modified: commons/proper/dbcp/trunk/xdocs/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/xdocs/changes.xml?rev=756628&r1=756627&r2=756628&view=diff ============================================================================== --- commons/proper/dbcp/trunk/xdocs/changes.xml (original) +++ commons/proper/dbcp/trunk/xdocs/changes.xml Fri Mar 20 17:07:44 2009 @@ -42,6 +42,11 @@ new features as well as bug fixes and instrumentation. Some bug fixes will change semantics (e.g. connection close will become idempotent). The minimum JDK level will be increased to 1.4"> + <action dev="psteitz" type="update" issue="DBCP-226"> + Added a validationQueryTimeout configuration parameter to BasicDataSource + allowing the user to specify a timeout value (in seconds) for connection + validation queries. + </action> <action dev="psteitz" type="update" issue="DBCP-175" due-to="Jiri Melichna and Jerome Lacoste"> Added a connectionInitSqls configuration parameter to BasicDataSource allowing the user to specify a collection of SQL statements to execute