ARTEMIS-2955 commons-dbcp2 performance issue with Derby Embedded DBMS

This commit is fixing:
- a missing commit that can make leak a connection
- restricting default specific commons-dbcp2 to the default data source
- setting poolPreparedStatements true by default
- configured embedded Derby to be in-memory to speedup tests
This commit is contained in:
franz1981 2020-10-19 18:09:52 +02:00
parent 0077f354cd
commit 769101ac69
4 changed files with 36 additions and 5 deletions

View File

@ -132,6 +132,7 @@ public abstract class AbstractJDBCDriver {
logger.tracef("Table %s did exist but is empty. Starting initialization.", tableName); logger.tracef("Table %s did exist but is empty. Starting initialization.", tableName);
} else { } else {
logger.tracef("Table %s did exist but is empty. Initialization completed: no initialization statements left.", tableName); logger.tracef("Table %s did exist but is empty. Initialization completed: no initialization statements left.", tableName);
connection.commit();
} }
} }
} catch (SQLException e) { } catch (SQLException e) {

View File

@ -24,6 +24,7 @@ import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.activemq.artemis.jdbc.store.logging.LoggingConnection; import org.apache.activemq.artemis.jdbc.store.logging.LoggingConnection;
import org.apache.activemq.artemis.jdbc.store.sql.PropertySQLProvider;
import org.apache.activemq.artemis.journal.ActiveMQJournalLogger; import org.apache.activemq.artemis.journal.ActiveMQJournalLogger;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -34,19 +35,31 @@ public class JDBCConnectionProvider {
private Executor networkTimeoutExecutor; private Executor networkTimeoutExecutor;
private int networkTimeoutMillis; private int networkTimeoutMillis;
private boolean supportNetworkTimeout; private boolean supportNetworkTimeout;
private final String user;
private final String password;
public JDBCConnectionProvider(DataSource dataSource) { public JDBCConnectionProvider(DataSource dataSource) {
this(dataSource, null, null);
}
public JDBCConnectionProvider(DataSource dataSource, String user, String password) {
this.dataSource = dataSource; this.dataSource = dataSource;
this.networkTimeoutExecutor = null; this.networkTimeoutExecutor = null;
this.networkTimeoutMillis = -1; this.networkTimeoutMillis = -1;
this.supportNetworkTimeout = true; this.supportNetworkTimeout = true;
this.user = user;
this.password = password;
addDerbyShutdownHook(); addDerbyShutdownHook();
} }
public synchronized Connection getConnection() throws SQLException { public synchronized Connection getConnection() throws SQLException {
Connection connection; Connection connection;
try { try {
if (user != null || password != null) {
connection = dataSource.getConnection(user, password);
} else {
connection = dataSource.getConnection(); connection = dataSource.getConnection();
}
if (logger.isTraceEnabled() && !(connection instanceof LoggingConnection)) { if (logger.isTraceEnabled() && !(connection instanceof LoggingConnection)) {
connection = new LoggingConnection(connection, logger); connection = new LoggingConnection(connection, logger);
} }
@ -92,7 +105,8 @@ public class JDBCConnectionProvider {
public void addDerbyShutdownHook() { public void addDerbyShutdownHook() {
// Shutdown the derby if using the derby embedded driver. // Shutdown the derby if using the derby embedded driver.
try (Connection connection = getConnection()) { try (Connection connection = getConnection()) {
if (connection.getMetaData().getDriverName().equals("org.apache.derby.jdbc.EmbeddedDriver")) { PropertySQLProvider.Factory.SQLDialect sqlDialect = PropertySQLProvider.Factory.investigateDialect(connection);
if (sqlDialect == PropertySQLProvider.Factory.SQLDialect.DERBY) {
if (shutAdded.compareAndSet(false, true)) { if (shutAdded.compareAndSet(false, true)) {
Runtime.getRuntime().addShutdownHook(new ShutdownDerby()); Runtime.getRuntime().addShutdownHook(new ShutdownDerby());
} }

View File

@ -151,7 +151,8 @@ public class DatabaseStorageConfiguration implements StoreConfiguration {
*/ */
private DataSource getDataSource() { private DataSource getDataSource() {
if (dataSource == null) { if (dataSource == null) {
if (dataSourceProperties.isEmpty()) { // the next settings are going to be applied only if the datasource is the default one
if (dataSourceProperties.isEmpty() && ActiveMQDefaultConfiguration.getDefaultDataSourceClassName().equals(dataSourceClassName)) {
addDataSourceProperty("driverClassName", jdbcDriverClassName); addDataSourceProperty("driverClassName", jdbcDriverClassName);
addDataSourceProperty("url", jdbcConnectionUrl); addDataSourceProperty("url", jdbcConnectionUrl);
if (jdbcUser != null) { if (jdbcUser != null) {
@ -162,6 +163,8 @@ public class DatabaseStorageConfiguration implements StoreConfiguration {
} }
// Let the pool to have unbounded number of connections by default to prevent connection starvation // Let the pool to have unbounded number of connections by default to prevent connection starvation
addDataSourceProperty("maxTotal", "-1"); addDataSourceProperty("maxTotal", "-1");
// Let the pool to have unbounded number of cached prepared statements to save the initialization cost
addDataSourceProperty("poolPreparedStatements", "true");
} }
dataSource = JDBCDataSourceUtils.getDataSource(dataSourceClassName, dataSourceProperties); dataSource = JDBCDataSourceUtils.getDataSource(dataSourceClassName, dataSourceProperties);
} }
@ -179,7 +182,12 @@ public class DatabaseStorageConfiguration implements StoreConfiguration {
public JDBCConnectionProvider getConnectionProvider() { public JDBCConnectionProvider getConnectionProvider() {
if (connectionProvider == null) { if (connectionProvider == null) {
// commons-dbcp2 doesn't support DataSource::getConnection(user, password)
if (dataSourceClassName == ActiveMQDefaultConfiguration.getDefaultDataSourceClassName()) {
connectionProvider = new JDBCConnectionProvider(getDataSource()); connectionProvider = new JDBCConnectionProvider(getDataSource());
} else {
connectionProvider = new JDBCConnectionProvider(getDataSource(), getJdbcUser(), getJdbcPassword());
}
} }
return connectionProvider; return connectionProvider;
} }

View File

@ -257,6 +257,10 @@ public abstract class ActiveMQTestBase extends Assert {
@After @After
public void shutdownDerby() { public void shutdownDerby() {
try {
DriverManager.getConnection("jdbc:derby:" + getEmbeddedDataBaseName() + ";destroy=true");
} catch (Exception ignored) {
}
try { try {
DriverManager.getConnection("jdbc:derby:;shutdown=true"); DriverManager.getConnection("jdbc:derby:;shutdown=true");
} catch (Exception ignored) { } catch (Exception ignored) {
@ -837,8 +841,12 @@ public abstract class ActiveMQTestBase extends Assert {
return testDir; return testDir;
} }
private String getEmbeddedDataBaseName() {
return "memory:" + getTestDir();
}
protected final String getTestJDBCConnectionUrl() { protected final String getTestJDBCConnectionUrl() {
return System.getProperty("jdbc.connection.url", "jdbc:derby:" + getTestDir() + File.separator + "derby;create=true"); return System.getProperty("jdbc.connection.url", "jdbc:derby:" + getEmbeddedDataBaseName() + ";create=true");
} }
protected final String getJDBCClassName() { protected final String getJDBCClassName() {