提交 cee8afbb authored 作者: Thomas Mueller's avatar Thomas Mueller

The built-in connection pool (JdbcConnectionPool) did not always honor the login…

The built-in connection pool (JdbcConnectionPool) did not always honor the login timeout (the timeout could occur much too early).
上级 3c2aeb8c
...@@ -18,10 +18,12 @@ Change Log ...@@ -18,10 +18,12 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul><li>The table INFORMATION_SCHEMA.SETTINGS now contains all H2-specific system properties <ul><li>The built-in connection pool (JdbcConnectionPool) did not always honor the login timeout
(the timeout could occur much too early). Thanks a lot to Dario Fassi for the patch!
</li><li>Translation: the new messages have been translated to Spanish. Thanks a lot to Dario Fassi!
</li><li>The table INFORMATION_SCHEMA.SETTINGS now contains all H2-specific system properties
(the ones that start with "h2.") and that are explicitly set. Previously, some H2-specific settings (the ones that start with "h2.") and that are explicitly set. Previously, some H2-specific settings
(for example h2.analyzeAuto) were missing in this list. (for example h2.analyzeAuto) were missing in this list.
</li><li>Translation: the new messages have been translated to Spanish. Thanks a lot to Dario Fassi!
</li><li>EXPLAIN ANALYZE with an in-memory database threw an exception. Issue 216. </li><li>EXPLAIN ANALYZE with an in-memory database threw an exception. Issue 216.
</li><li>Data modifications (inserts, updates, and deletes) are now up to 5 times faster </li><li>Data modifications (inserts, updates, and deletes) are now up to 5 times faster
because converting objects to byte arrays is avoided if possible. because converting objects to byte arrays is avoided if possible.
......
...@@ -65,11 +65,12 @@ import org.h2.message.DbException; ...@@ -65,11 +65,12 @@ import org.h2.message.DbException;
public class JdbcConnectionPool implements DataSource, ConnectionEventListener { public class JdbcConnectionPool implements DataSource, ConnectionEventListener {
private static final int DEFAULT_TIMEOUT = 30; private static final int DEFAULT_TIMEOUT = 30;
private static final int DEFAULT_MAX_CONNECTIONS = 10;
private final ConnectionPoolDataSource dataSource; private final ConnectionPoolDataSource dataSource;
private final Stack<PooledConnection> recycledConnections = new Stack<PooledConnection>(); private final Stack<PooledConnection> recycledConnections = new Stack<PooledConnection>();
private PrintWriter logWriter; private PrintWriter logWriter;
private int maxConnections = 10; private int maxConnections = DEFAULT_MAX_CONNECTIONS;
private int timeout = DEFAULT_TIMEOUT; private int timeout = DEFAULT_TIMEOUT;
private int activeConnections; private int activeConnections;
private boolean isDisposed; private boolean isDisposed;
...@@ -144,7 +145,7 @@ public class JdbcConnectionPool implements DataSource, ConnectionEventListener { ...@@ -144,7 +145,7 @@ public class JdbcConnectionPool implements DataSource, ConnectionEventListener {
/** /**
* Sets the maximum time in seconds to wait for a free connection. * Sets the maximum time in seconds to wait for a free connection.
* The default timeout is 5 minutes. Calling this method with the * The default timeout is 30 seconds. Calling this method with the
* value 0 will set the timeout to the default value. * value 0 will set the timeout to the default value.
* *
* @param seconds the timeout, 0 meaning the default * @param seconds the timeout, 0 meaning the default
...@@ -194,14 +195,12 @@ public class JdbcConnectionPool implements DataSource, ConnectionEventListener { ...@@ -194,14 +195,12 @@ public class JdbcConnectionPool implements DataSource, ConnectionEventListener {
* or a timeout occurred * or a timeout occurred
*/ */
public Connection getConnection() throws SQLException { public Connection getConnection() throws SQLException {
for (int i = 0;; i++) { long max = System.currentTimeMillis() + timeout * 1000;
while (System.currentTimeMillis() <= max) {
synchronized (this) { synchronized (this) {
if (activeConnections < maxConnections) { if (activeConnections < maxConnections) {
return getConnectionNow(); return getConnectionNow();
} }
if (i >= timeout) {
throw new SQLException("Login timeout", "08001", 8001);
}
try { try {
wait(1000); wait(1000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
...@@ -209,6 +208,7 @@ public class JdbcConnectionPool implements DataSource, ConnectionEventListener { ...@@ -209,6 +208,7 @@ public class JdbcConnectionPool implements DataSource, ConnectionEventListener {
} }
} }
} }
throw new SQLException("Login timeout", "08001", 8001);
} }
private Connection getConnectionNow() throws SQLException { private Connection getConnectionNow() throws SQLException {
......
...@@ -33,6 +33,7 @@ public class TestConnectionPool extends TestBase { ...@@ -33,6 +33,7 @@ public class TestConnectionPool extends TestBase {
public void test() throws Exception { public void test() throws Exception {
deleteDb("connectionPool"); deleteDb("connectionPool");
testTimeout();
testUncommittedTransaction(); testUncommittedTransaction();
testPerformance(); testPerformance();
testKeepOpen(); testKeepOpen();
...@@ -41,6 +42,40 @@ public class TestConnectionPool extends TestBase { ...@@ -41,6 +42,40 @@ public class TestConnectionPool extends TestBase {
deleteDb("connectionPool"); deleteDb("connectionPool");
} }
private void testTimeout() throws Exception {
String url = getURL("connectionPool", true), user = getUser(), password = getPassword();
final JdbcConnectionPool man = JdbcConnectionPool.create(url, user, password);
man.setLoginTimeout(1);
man.setMaxConnections(2);
Connection conn = man.getConnection();
final boolean[] stop = { false };
Thread t = new Thread() {
public void run() {
while (!stop[0]) {
// this calls notifyAll
man.setMaxConnections(1);
man.setMaxConnections(2);
}
}
};
t.start();
long time = System.currentTimeMillis();
try {
man.getConnection();
man.getConnection();
fail();
} catch (SQLException e) {
time = System.currentTimeMillis() - time;
assertTrue("timeout after " + time + " ms", time > 1000);
} finally {
conn.close();
stop[0] = true;
t.join();
}
man.dispose();
}
private void testUncommittedTransaction() throws SQLException { private void testUncommittedTransaction() throws SQLException {
String url = getURL("connectionPool", true), user = getUser(), password = getPassword(); String url = getURL("connectionPool", true), user = getUser(), password = getPassword();
JdbcConnectionPool man = JdbcConnectionPool.create(url, user, password); JdbcConnectionPool man = JdbcConnectionPool.create(url, user, password);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论