From a639774b54d31fd06c906f8ae42b9733f96e569b Mon Sep 17 00:00:00 2001 From: Francesco Nigro Date: Thu, 20 Apr 2017 12:43:40 +0200 Subject: [PATCH] ARTEMIS-1124 JDBC Network Timeout configuration --- .../config/ActiveMQDefaultConfiguration.java | 8 +++++ .../store/drivers/AbstractJDBCDriver.java | 29 +++++++++++++++++++ .../store/file/JDBCSequentialFileFactory.java | 8 +++++ .../storage/DatabaseStorageConfiguration.java | 10 +++++++ .../impl/FileConfigurationParser.java | 1 + .../impl/PagingStoreFactoryDatabase.java | 12 ++++++-- .../journal/JDBCJournalStorageManager.java | 19 ++++++++++-- .../schema/artemis-configuration.xsd | 7 +++++ .../test/resources/artemis-configuration.xsd | 7 +++++ docs/user-manual/en/persistence.md | 5 ++++ 10 files changed, 102 insertions(+), 4 deletions(-) diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java index 6d3cb81ec2c..8c0b973b803 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java @@ -16,6 +16,8 @@ */ package org.apache.activemq.artemis.api.config; +import java.util.concurrent.TimeUnit; + import org.apache.activemq.artemis.ArtemisConstants; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.core.server.DivertConfigurationRoutingType; @@ -429,6 +431,8 @@ public static String getDefaultHapolicyBackupStrategy() { // Default large messages table name, used with Database storage type private static final String DEFAULT_PAGE_STORE_TABLE_NAME = "PAGE_STORE"; + private static final int DEFAULT_JDBC_NETWORK_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(20); + // Default period to wait between connection TTL checks public static final long DEFAULT_CONNECTION_TTL_CHECK_INTERVAL = 2000; @@ -1181,6 +1185,10 @@ public static String getDefaultPageStoreTableName() { return DEFAULT_PAGE_STORE_TABLE_NAME; } + public static int getDefaultJdbcNetworkTimeout() { + return DEFAULT_JDBC_NETWORK_TIMEOUT; + } + public static long getDefaultConnectionTtlCheckInterval() { return DEFAULT_CONNECTION_TTL_CHECK_INTERVAL; } diff --git a/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/drivers/AbstractJDBCDriver.java b/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/drivers/AbstractJDBCDriver.java index 18289117c83..fcbf90d0ad0 100644 --- a/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/drivers/AbstractJDBCDriver.java +++ b/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/drivers/AbstractJDBCDriver.java @@ -26,6 +26,7 @@ import java.sql.Statement; import java.util.Arrays; import java.util.Properties; +import java.util.concurrent.Executor; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -51,18 +52,28 @@ public abstract class AbstractJDBCDriver { private DataSource dataSource; + private Executor networkTimeoutExecutor; + + private int networkTimeoutMillis; + public AbstractJDBCDriver() { + this.networkTimeoutExecutor = null; + this.networkTimeoutMillis = -1; } public AbstractJDBCDriver(SQLProvider sqlProvider, String jdbcConnectionUrl, String jdbcDriverClass) { this.jdbcConnectionUrl = jdbcConnectionUrl; this.jdbcDriverClass = jdbcDriverClass; this.sqlProvider = sqlProvider; + this.networkTimeoutExecutor = null; + this.networkTimeoutMillis = -1; } public AbstractJDBCDriver(DataSource dataSource, SQLProvider provider) { this.dataSource = dataSource; this.sqlProvider = provider; + this.networkTimeoutExecutor = null; + this.networkTimeoutMillis = -1; } public void start() throws SQLException { @@ -76,6 +87,8 @@ public void start() throws SQLException { public AbstractJDBCDriver(Connection connection, SQLProvider sqlProvider) { this.connection = connection; this.sqlProvider = sqlProvider; + this.networkTimeoutExecutor = null; + this.networkTimeoutMillis = -1; } public void stop() throws SQLException { @@ -127,6 +140,17 @@ private void connect() throws SQLException { throw e; } } + if (this.networkTimeoutMillis >= 0 && this.networkTimeoutExecutor != null) { + try { + connection.setNetworkTimeout(this.networkTimeoutExecutor, this.networkTimeoutMillis); + } catch (SQLException e) { + logger.warn(JDBCUtils.appendSQLExceptionDetails(new StringBuilder(), e)); + ActiveMQJournalLogger.LOGGER.warn("Unable to set a network timeout on the JDBC connection"); + } catch (Throwable throwable) { + //it included SecurityExceptions and UnsupportedOperationException + logger.warn("Unable to set a network timeout on the JDBC connection", throwable); + } + } } } @@ -240,4 +264,9 @@ public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } + public void setNetworkTimeout(Executor executor, int milliseconds) { + this.networkTimeoutExecutor = executor; + this.networkTimeoutMillis = milliseconds; + } + } diff --git a/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/JDBCSequentialFileFactory.java b/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/JDBCSequentialFileFactory.java index d5a92a2329c..ae2e793666c 100644 --- a/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/JDBCSequentialFileFactory.java +++ b/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/JDBCSequentialFileFactory.java @@ -101,6 +101,14 @@ public JDBCSequentialFileFactoryDriver getDbDriver() { return dbDriver; } + /** + * @see Connection#setNetworkTimeout(Executor, int) + **/ + public JDBCSequentialFileFactory setNetworkTimeout(Executor executor, int milliseconds) { + this.dbDriver.setNetworkTimeout(executor, milliseconds); + return this; + } + @Override public SequentialFileFactory setDatasync(boolean enabled) { return this; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/storage/DatabaseStorageConfiguration.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/storage/DatabaseStorageConfiguration.java index eb8b435ad43..76626c015ce 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/storage/DatabaseStorageConfiguration.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/storage/DatabaseStorageConfiguration.java @@ -40,6 +40,8 @@ public class DatabaseStorageConfiguration implements StoreConfiguration { private SQLProvider.Factory sqlProviderFactory; + private int jdbcNetworkTimeout = ActiveMQDefaultConfiguration.getDefaultJdbcNetworkTimeout(); + @Override public StoreType getStoreType() { return StoreType.DATABASE; @@ -125,4 +127,12 @@ public SQLProvider.Factory getSqlProviderFactory() { public void setSqlProvider(SQLProvider.Factory sqlProviderFactory) { this.sqlProviderFactory = sqlProviderFactory; } + + public int getJdbcNetworkTimeout() { + return this.jdbcNetworkTimeout; + } + + public void setJdbcNetworkTimeout(int jdbcNetworkTimeout) { + this.jdbcNetworkTimeout = jdbcNetworkTimeout; + } } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java index 030f531605b..6f666b6d34d 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java @@ -1292,6 +1292,7 @@ private DatabaseStorageConfiguration createDatabaseStoreConfig(Element storeNode conf.setPageStoreTableName(getString(storeNode, "page-store-table-name", conf.getPageStoreTableName(), Validators.NO_CHECK)); conf.setJdbcConnectionUrl(getString(storeNode, "jdbc-connection-url", conf.getJdbcConnectionUrl(), Validators.NO_CHECK)); conf.setJdbcDriverClassName(getString(storeNode, "jdbc-driver-class-name", conf.getJdbcDriverClassName(), Validators.NO_CHECK)); + conf.setJdbcNetworkTimeout(getInteger(storeNode, "jdbc-network-timeout", conf.getJdbcNetworkTimeout(), Validators.NO_CHECK)); return conf; } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/PagingStoreFactoryDatabase.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/PagingStoreFactoryDatabase.java index 12e2b35f3a7..2daa89ef822 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/PagingStoreFactoryDatabase.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/PagingStoreFactoryDatabase.java @@ -127,6 +127,10 @@ public synchronized void start() throws Exception { String driverClassName = dbConf.getJdbcDriverClassName(); pagingFactoryFileFactory = new JDBCSequentialFileFactory(dbConf.getJdbcConnectionUrl(), driverClassName, JDBCUtils.getSQLProvider(driverClassName, pageStoreTableNamePrefix, SQLProvider.DatabaseStoreType.PAGE), executorFactory.getExecutor(), criticalErrorListener); } + final int jdbcNetworkTimeout = dbConf.getJdbcNetworkTimeout(); + if (jdbcNetworkTimeout >= 0) { + pagingFactoryFileFactory.setNetworkTimeout(this.executorFactory.getExecutor(), jdbcNetworkTimeout); + } pagingFactoryFileFactory.start(); started = true; } @@ -234,8 +238,12 @@ private synchronized SequentialFileFactory newFileFactory(final String directory } else { sqlProvider = JDBCUtils.getSQLProvider(dbConf.getJdbcDriverClassName(), getTableNameForGUID(directoryName), SQLProvider.DatabaseStoreType.PAGE); } - - return new JDBCSequentialFileFactory(pagingFactoryFileFactory.getDbDriver().getConnection(), sqlProvider, executorFactory.getExecutor(), criticalErrorListener); + final JDBCSequentialFileFactory fileFactory = new JDBCSequentialFileFactory(pagingFactoryFileFactory.getDbDriver().getConnection(), sqlProvider, executorFactory.getExecutor(), criticalErrorListener); + final int jdbcNetworkTimeout = dbConf.getJdbcNetworkTimeout(); + if (jdbcNetworkTimeout >= 0) { + fileFactory.setNetworkTimeout(this.executorFactory.getExecutor(), jdbcNetworkTimeout); + } + return fileFactory; } private String getTableNameForGUID(String guid) { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/JDBCJournalStorageManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/JDBCJournalStorageManager.java index 5592c9e2a57..4b8392da767 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/JDBCJournalStorageManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/JDBCJournalStorageManager.java @@ -55,8 +55,10 @@ public JDBCJournalStorageManager(final Configuration config, @Override protected synchronized void init(Configuration config, IOCriticalErrorListener criticalErrorListener) { try { - DatabaseStorageConfiguration dbConf = (DatabaseStorageConfiguration) config.getStoreConfiguration(); - + final DatabaseStorageConfiguration dbConf = (DatabaseStorageConfiguration) config.getStoreConfiguration(); + final JDBCJournalImpl bindingsJournal; + final JDBCJournalImpl messageJournal; + final JDBCSequentialFileFactory largeMessagesFactory; if (dbConf.getDataSource() != null) { SQLProvider.Factory sqlProviderFactory = dbConf.getSqlProviderFactory(); if (sqlProviderFactory == null) { @@ -71,6 +73,19 @@ protected synchronized void init(Configuration config, IOCriticalErrorListener c messageJournal = new JDBCJournalImpl(dbConf.getJdbcConnectionUrl(), driverClassName, JDBCUtils.getSQLProvider(driverClassName, dbConf.getMessageTableName(), SQLProvider.DatabaseStoreType.MESSAGE_JOURNAL), scheduledExecutorService, executorFactory.getExecutor(), criticalErrorListener); largeMessagesFactory = new JDBCSequentialFileFactory(dbConf.getJdbcConnectionUrl(), driverClassName, JDBCUtils.getSQLProvider(driverClassName, dbConf.getLargeMessageTableName(), SQLProvider.DatabaseStoreType.LARGE_MESSAGE), executor, criticalErrorListener); } + final int networkTimeout = dbConf.getJdbcNetworkTimeout(); + if (networkTimeout >= 0) { + bindingsJournal.setNetworkTimeout(executorFactory.getExecutor(), networkTimeout); + } + if (networkTimeout >= 0) { + messageJournal.setNetworkTimeout(executorFactory.getExecutor(), networkTimeout); + } + if (networkTimeout >= 0) { + largeMessagesFactory.setNetworkTimeout(executorFactory.getExecutor(), networkTimeout); + } + this.bindingsJournal = bindingsJournal; + this.messageJournal = messageJournal; + this.largeMessagesFactory = largeMessagesFactory; largeMessagesFactory.start(); } catch (Exception e) { criticalErrorListener.onIOException(e, e.getMessage(), null); diff --git a/artemis-server/src/main/resources/schema/artemis-configuration.xsd b/artemis-server/src/main/resources/schema/artemis-configuration.xsd index 6fdef44d5c5..e6eaf8b38a1 100644 --- a/artemis-server/src/main/resources/schema/artemis-configuration.xsd +++ b/artemis-server/src/main/resources/schema/artemis-configuration.xsd @@ -1715,6 +1715,13 @@ + + + + The JDBC network connection timeout in milliseconds. + + + diff --git a/artemis-tools/src/test/resources/artemis-configuration.xsd b/artemis-tools/src/test/resources/artemis-configuration.xsd index 090f9689230..eda09320a26 100644 --- a/artemis-tools/src/test/resources/artemis-configuration.xsd +++ b/artemis-tools/src/test/resources/artemis-configuration.xsd @@ -1640,6 +1640,13 @@ + + + + The JDBC network connection timeout in milliseconds. + + + diff --git a/docs/user-manual/en/persistence.md b/docs/user-manual/en/persistence.md index de1f3a1d33b..e6bfe5cdd77 100644 --- a/docs/user-manual/en/persistence.md +++ b/docs/user-manual/en/persistence.md @@ -462,6 +462,11 @@ To configure Apache ActiveMQ Artemis to use a database for persisting messages a The fully qualified class name of the desired database Driver. +- `jdbc-network-timeout` + + The JDBC network connection timeout in milliseconds. The default value + is 20000 milliseconds (ie 20 seconds). + Note that some DBMS (e.g. Oracle, 30 chars) have restrictions on the size of table names, this should be taken into consideration when configuring table names for the Artemis database store, pay particular attention to the page store table name, which can be appended with a unique ID of up to 20 characters. (for Oracle this would mean configuring a page-store-table-name of max size of 10 chars). ## Configuring Apache ActiveMQ Artemis for Zero Persistence