You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2020/08/10 19:20:57 UTC
[commons-dbcp] branch master updated: Add start,
restart methods to BasicDataSource. JIRA: DBCP-559. (#50)
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-dbcp.git
The following commit(s) were added to refs/heads/master by this push:
new 2ac2a27 Add start, restart methods to BasicDataSource. JIRA: DBCP-559. (#50)
2ac2a27 is described below
commit 2ac2a27e37c4e2beacca6a4df93e09ea364af966
Author: Phil Steitz <ps...@apache.org>
AuthorDate: Mon Aug 10 12:19:41 2020 -0700
Add start, restart methods to BasicDataSource. JIRA: DBCP-559. (#50)
---
.../org/apache/commons/dbcp2/BasicDataSource.java | 51 +++++++++++++++-
.../commons/dbcp2/BasicDataSourceMXBean.java | 19 ++++++
.../apache/commons/dbcp2/TestBasicDataSource.java | 71 ++++++++++++++++++++++
3 files changed, 140 insertions(+), 1 deletion(-)
diff --git a/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java b/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java
index cb96d46..d81af67 100644
--- a/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java
+++ b/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java
@@ -405,7 +405,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* </p>
* <p>
* Attempts to acquire connections using {@link #getConnection()} after this method has been invoked result in
- * SQLExceptions.
+ * SQLExceptions. To reopen a datasource that has been closed using this method, use {@link #start()}.
* </p>
* <p>
* This method is idempotent - i.e., closing an already closed BasicDataSource has no effect and does not generate
@@ -436,6 +436,55 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
+ * Starts the datasource.
+ * <p>
+ * It is not necessary to call this method before using a newly created BasicDataSource instance, but
+ * calling it in that context causes the datasource to be immediately initialized (instead of waiting for
+ * the first {@link #getConnection()} request). Its primary use is to restart and reinitialize a
+ * datasource that has been closed.
+ * <p>
+ * When this method is called after {@link #close()}, connections checked out by clients
+ * before the datasource was stopped do not count in {@link #getMaxTotal()} or {@link #getNumActive()}.
+ * For example, if there are 3 connections checked out by clients when {@link #close()} is invoked and they are
+ * not returned before {@link #start()} is invoked, after this method is called, {@link #getNumActive()} will
+ * return 0. These connections will be physically closed when they are returned, but they will not count against
+ * the maximum allowed in the newly started datasource.
+ *
+ * @throws SQLException if an error occurs initializing the datasource
+ */
+ @Override
+ public synchronized void start() throws SQLException {
+ closed = false;
+ createDataSource();
+ }
+
+ /**
+ * Restarts the datasource.
+ * <p>
+ * This method calls {@link #close()} and {@link #start()} in sequence within synchronized scope so any
+ * connection requests that come in while the datsource is shutting down will be served by the new pool.
+ * <p>
+ * Idle connections that are stored in the connection pool when this method is invoked are closed, but
+ * connections that are checked out to clients when this method is invoked are not affected. When client
+ * applications subsequently invoke {@link Connection#close()} to return these connections to the pool, the
+ * underlying JDBC connections are closed. These connections do not count in {@link #getMaxTotal()} or
+ * {@link #getNumActive()} after invoking this method. For example, if there are 3 connections checked out by
+ * clients when {@link #restart()} is invoked, after this method is called, {@link #getNumActive()} will
+ * return 0 and up to {@link #getMaxTotal()} + 3 connections may be open until the connections sourced from
+ * the original pool are returned.
+ * <p>
+ * The new connection pool created by this method is initialized with currently set configuration properties.
+ *
+ * @throws SQLException if an error occurs initializing the datasource
+ */
+ @Override
+ public synchronized void restart() throws SQLException {
+ close();
+ start();
+ }
+
+
+ /**
* Closes the connection pool, silently swallowing any exception that occurs.
*/
private void closeConnectionPool() {
diff --git a/src/main/java/org/apache/commons/dbcp2/BasicDataSourceMXBean.java b/src/main/java/org/apache/commons/dbcp2/BasicDataSourceMXBean.java
index 85f8a58..3d3033b 100644
--- a/src/main/java/org/apache/commons/dbcp2/BasicDataSourceMXBean.java
+++ b/src/main/java/org/apache/commons/dbcp2/BasicDataSourceMXBean.java
@@ -16,6 +16,8 @@
*/
package org.apache.commons.dbcp2;
+import java.sql.SQLException;
+
/**
* Defines the methods that will be made available via JMX.
*
@@ -325,4 +327,21 @@ public interface BasicDataSourceMXBean {
* @since 2.1
*/
String[] getDisconnectionSqlCodesAsArray();
+
+ /**
+ * See {@link BasicDataSource#start()}
+ *
+ * @throws SQLException if an error occurs initializing the datasource
+ *
+ * @since 2.8
+ */
+ default void start() throws SQLException {}
+
+ /**
+ * See {@link BasicDataSource#restart()}
+ * @throws SQLException if an error occurs initializing the datasource
+ *
+ * @since 2.8
+ */
+ default void restart() throws SQLException {}
}
diff --git a/src/test/java/org/apache/commons/dbcp2/TestBasicDataSource.java b/src/test/java/org/apache/commons/dbcp2/TestBasicDataSource.java
index bc63c7a..4be757d 100644
--- a/src/test/java/org/apache/commons/dbcp2/TestBasicDataSource.java
+++ b/src/test/java/org/apache/commons/dbcp2/TestBasicDataSource.java
@@ -951,8 +951,79 @@ public class TestBasicDataSource extends TestConnectionPool {
+ ds.getMinIdle() + ")");
}
}
+
+ @Test
+ public void testStart() throws Exception {
+ ds.setAccessToUnderlyingConnectionAllowed(true);
+ ds.setMaxTotal(2);
+ final DelegatingConnection<?> conn1 = (DelegatingConnection<?>) ds.getConnection();
+ final DelegatingConnection<?> conn2 = (DelegatingConnection<?>) ds.getConnection();
+ final Connection inner1 = conn1.getInnermostDelegate();
+ final Connection inner2 = conn2.getInnermostDelegate();
+ assertFalse(inner2.isClosed());
+ conn2.close();
+ assertFalse(inner2.isClosed());
+ // One active, one idle in the pool
+ ds.close();
+ // Idle connection should be physically closed, checked out unaffected
+ assertFalse(conn1.isClosed());
+ assertTrue(inner2.isClosed());
+ assertEquals(0, ds.getNumIdle());
+
+ // Reopen creates a new pool, so we can have three out
+ ds.start();
+ final Connection conn3 = ds.getConnection();
+ final Connection conn4 = ds.getConnection();
+ conn3.close();
+ conn4.close();
+
+ // Old pool's orphan should get physically closed on return
+ conn1.close();
+ assertTrue(inner1.isClosed());
+ }
+
+ @Test
+ public void testStartInitializes() throws Exception {
+ ds.setInitialSize(2);
+ // Note: if we ever move away from lazy init, next two will fail
+ assertEquals(0, ds.getNumIdle());
+ assertNull(ds.getRegisteredJmxName());
+
+ // Start forces init
+ ds.start();
+ assertEquals(2, ds.getNumIdle());
+ assertNotNull(ds.getRegisteredJmxName());
+ }
+
+ @Test
+ public void testRestart() throws Exception {
+ ds.setMaxTotal(2);
+ ds.setTimeBetweenEvictionRunsMillis(100);
+ ds.setNumTestsPerEvictionRun(2);
+ ds.setMinEvictableIdleTimeMillis(60000);
+ ds.setInitialSize(2);
+ ds.setDefaultCatalog("foo");
+ final Connection conn1 = ds.getConnection();
+ Thread.sleep(200);
+ // Now set some property that will not have effect until restart
+ ds.setDefaultCatalog("bar");
+ ds.setInitialSize(1);
+ // restart will load new properties
+ ds.restart();
+ assertEquals("bar", ds.getDefaultCatalog());
+ assertEquals(1, ds.getInitialSize());
+ ds.getLogWriter(); // side effect is to init
+ assertEquals(0, ds.getNumActive());
+ assertEquals(1, ds.getNumIdle());
+ conn1.close();
+ // verify old pool connection is not returned to pool
+ assertEquals(1, ds.getNumIdle());
+ ds.close();
+ }
}
+
+
/**
* TesterDriver that keeps a static count of connection requests.
*/