aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build.gradle3
-rw-r--r--server/sonar-ce/build.gradle2
-rw-r--r--server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBean.java13
-rw-r--r--server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBeanImpl.java81
-rw-r--r--server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeDatabaseMBeanImplTest.java11
-rw-r--r--server/sonar-db-core/build.gradle4
-rw-r--r--server/sonar-db-core/src/main/java/org/sonar/db/DefaultDatabase.java79
-rw-r--r--server/sonar-db-core/src/main/java/org/sonar/db/profiling/ConnectionInterceptor.java6
-rw-r--r--server/sonar-db-core/src/main/java/org/sonar/db/profiling/NullConnectionInterceptor.java6
-rw-r--r--server/sonar-db-core/src/main/java/org/sonar/db/profiling/ProfiledConnectionInterceptor.java6
-rw-r--r--server/sonar-db-core/src/main/java/org/sonar/db/profiling/ProfiledDataSource.java501
-rw-r--r--server/sonar-db-core/src/test/java/org/sonar/db/DefaultDatabaseTest.java59
-rw-r--r--server/sonar-db-core/src/test/java/org/sonar/db/profiling/InvocationUtilsTest.java11
-rw-r--r--server/sonar-db-core/src/test/java/org/sonar/db/profiling/ProfiledDataSourceTest.java46
-rw-r--r--server/sonar-db-core/src/testFixtures/java/org/sonar/db/CoreH2Database.java14
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/DatabaseMBean.java75
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/DatabaseMBeanTest.java65
-rw-r--r--server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java4
-rw-r--r--server/sonar-docs/src/pages/instance-administration/monitoring.md11
-rw-r--r--server/sonar-docs/src/pages/setup/upgrade-notes.md5
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java7
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/systeminfo/BaseSectionMBean.java (renamed from server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/BaseSectionMBean.java)7
-rw-r--r--server/sonar-process/src/test/java/org/sonar/process/systeminfo/BaseSectionMBeanTest.java79
-rw-r--r--server/sonar-webserver-core/build.gradle2
-rw-r--r--server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/DbConnectionSection.java63
-rw-r--r--server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/DbConnectionSectionMBean.java28
-rw-r--r--server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/StandaloneSystemSection.java1
-rw-r--r--server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/BaseSectionMBeanTest.java2
-rw-r--r--server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/DbConnectionSectionTest.java21
-rw-r--r--server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/FakeSection.java1
-rw-r--r--sonar-application/src/main/assembly/conf/sonar.properties9
31 files changed, 633 insertions, 589 deletions
diff --git a/build.gradle b/build.gradle
index 5d6e47a4502..2359031dadd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -261,7 +261,7 @@ subprojects {
dependency 'org.awaitility:awaitility:4.2.0'
dependency 'org.apache.commons:commons-csv:1.9.0'
dependency 'org.apache.commons:commons-email:1.5'
- dependency 'org.apache.commons:commons-dbcp2:2.9.0'
+ dependency 'com.zaxxer:HikariCP:5.0.1'
dependency('org.apache.httpcomponents:httpclient:4.5.13'){
exclude 'commons-logging:commons-logging'
}
@@ -304,6 +304,7 @@ subprojects {
dependency('org.mockito:mockito-core:4.7.0') {
exclude 'org.hamcrest:hamcrest-core'
}
+ dependency('org.mockito:mockito-inline:4.7.0')
dependency 'org.mybatis:mybatis:3.5.10'
dependency 'org.nanohttpd:nanohttpd:2.3.1'
dependencySet(group: 'org.slf4j', version: '1.7.30') {
diff --git a/server/sonar-ce/build.gradle b/server/sonar-ce/build.gradle
index 054ac8d7c51..f66a080cfa7 100644
--- a/server/sonar-ce/build.gradle
+++ b/server/sonar-ce/build.gradle
@@ -13,7 +13,7 @@ dependencies {
compile 'com.hazelcast:hazelcast'
compile 'com.hazelcast:hazelcast-kubernetes'
compile 'commons-io:commons-io'
- compile 'org.apache.commons:commons-dbcp2'
+ compile 'com.zaxxer:HikariCP'
compile 'org.sonarsource.api.plugin:sonar-plugin-api'
compile project(':server:sonar-ce-common')
compile project(':server:sonar-ce-task')
diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBean.java b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBean.java
index fa8d6f7ad3e..a2e69a63094 100644
--- a/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBean.java
+++ b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBean.java
@@ -21,23 +21,18 @@ package org.sonar.ce.monitoring;
public interface CeDatabaseMBean {
- String OBJECT_NAME = "SonarQube:name=ComputeEngineDatabaseConnection";
-
int getPoolActiveConnections();
- int getPoolMaxActiveConnections();
+ int getPoolMaxConnections();
- int getPoolIdleConnections();
+ int getPoolTotalConnections();
- int getPoolMaxIdleConnections();
+ int getPoolIdleConnections();
int getPoolMinIdleConnections();
- int getPoolInitialSize();
+ long getPoolMaxLifeTimeMillis();
long getPoolMaxWaitMillis();
- boolean getPoolRemoveAbandoned();
-
- int getPoolRemoveAbandonedTimeoutSeconds();
}
diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBeanImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBeanImpl.java
index c392abd1e05..2adb3b36c11 100644
--- a/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBeanImpl.java
+++ b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBeanImpl.java
@@ -19,95 +19,34 @@
*/
package org.sonar.ce.monitoring;
-import org.apache.commons.dbcp2.BasicDataSource;
-import org.sonar.api.Startable;
+import org.sonar.db.DatabaseMBean;
import org.sonar.db.DbClient;
-import org.sonar.process.Jmx;
-import org.sonar.process.systeminfo.SystemInfoSection;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
-public class CeDatabaseMBeanImpl implements CeDatabaseMBean, Startable, SystemInfoSection {
- private final DbClient dbClient;
+public class CeDatabaseMBeanImpl extends DatabaseMBean implements CeDatabaseMBean {
- public CeDatabaseMBeanImpl(DbClient dbClient) {
- this.dbClient = dbClient;
- }
-
- @Override
- public void start() {
- Jmx.register(OBJECT_NAME, this);
- }
-
- /**
- * Unregister, if needed
- */
- @Override
- public void stop() {
- Jmx.unregister(OBJECT_NAME);
- }
-
- @Override
- public int getPoolActiveConnections() {
- return commonsDbcp().getNumActive();
- }
-
- @Override
- public int getPoolMaxActiveConnections() {
- return commonsDbcp().getMaxTotal();
- }
-
- @Override
- public int getPoolIdleConnections() {
- return commonsDbcp().getNumIdle();
- }
+ private static final String OBJECT_NAME = "ComputeEngineDatabaseConnection";
- @Override
- public int getPoolMaxIdleConnections() {
- return commonsDbcp().getMaxIdle();
- }
-
- @Override
- public int getPoolMinIdleConnections() {
- return commonsDbcp().getMinIdle();
- }
-
- @Override
- public int getPoolInitialSize() {
- return commonsDbcp().getInitialSize();
- }
-
- @Override
- public long getPoolMaxWaitMillis() {
- return commonsDbcp().getMaxWaitMillis();
- }
-
- @Override
- public boolean getPoolRemoveAbandoned() {
- return commonsDbcp().getRemoveAbandonedOnBorrow();
+ public CeDatabaseMBeanImpl(DbClient dbClient) {
+ super(dbClient);
}
@Override
- public int getPoolRemoveAbandonedTimeoutSeconds() {
- return commonsDbcp().getRemoveAbandonedTimeout();
- }
-
- private BasicDataSource commonsDbcp() {
- return (BasicDataSource) dbClient.getDatabase().getDataSource();
+ protected String name() {
+ return OBJECT_NAME;
}
@Override
public ProtobufSystemInfo.Section toProtobuf() {
ProtobufSystemInfo.Section.Builder builder = ProtobufSystemInfo.Section.newBuilder();
builder.setName("Compute Engine Database Connection");
- builder.addAttributesBuilder().setKey("Pool Initial Size").setLongValue(getPoolInitialSize()).build();
+ builder.addAttributesBuilder().setKey("Pool Total Connections").setLongValue(getPoolTotalConnections()).build();
builder.addAttributesBuilder().setKey("Pool Active Connections").setLongValue(getPoolActiveConnections()).build();
builder.addAttributesBuilder().setKey("Pool Idle Connections").setLongValue(getPoolIdleConnections()).build();
- builder.addAttributesBuilder().setKey("Pool Max Active Connections").setLongValue(getPoolMaxActiveConnections()).build();
- builder.addAttributesBuilder().setKey("Pool Max Idle Connections").setLongValue(getPoolMaxIdleConnections()).build();
+ builder.addAttributesBuilder().setKey("Pool Max Connections").setLongValue(getPoolMaxConnections()).build();
builder.addAttributesBuilder().setKey("Pool Min Idle Connections").setLongValue(getPoolMinIdleConnections()).build();
builder.addAttributesBuilder().setKey("Pool Max Wait (ms)").setLongValue(getPoolMaxWaitMillis()).build();
- builder.addAttributesBuilder().setKey("Pool Remove Abandoned").setBooleanValue(getPoolRemoveAbandoned()).build();
- builder.addAttributesBuilder().setKey("Pool Remove Abandoned Timeout (sec)").setLongValue(getPoolRemoveAbandonedTimeoutSeconds()).build();
+ builder.addAttributesBuilder().setKey("Pool Max Lifetime (ms)").setLongValue(getPoolMaxLifeTimeMillis()).build();
return builder.build();
}
}
diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeDatabaseMBeanImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeDatabaseMBeanImplTest.java
index 35894dd9fdb..cd8e0de1eaa 100644
--- a/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeDatabaseMBeanImplTest.java
+++ b/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeDatabaseMBeanImplTest.java
@@ -33,7 +33,6 @@ import org.sonar.process.Jmx;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.ce.monitoring.CeDatabaseMBean.OBJECT_NAME;
public class CeDatabaseMBeanImplTest {
@@ -45,7 +44,7 @@ public class CeDatabaseMBeanImplTest {
@BeforeClass
public static void beforeClass() {
// if any other class starts a container where CeDatabaseMBeanImpl is added, it will have been registered
- Jmx.unregister(OBJECT_NAME);
+ Jmx.unregister("SonarQube:name=ComputeEngineDatabaseConnection");
}
@Test
@@ -63,15 +62,15 @@ public class CeDatabaseMBeanImplTest {
public void export_system_info() {
ProtobufSystemInfo.Section section = underTest.toProtobuf();
assertThat(section.getName()).isEqualTo("Compute Engine Database Connection");
- assertThat(section.getAttributesCount()).isEqualTo(9);
- assertThat(section.getAttributes(0).getKey()).isEqualTo("Pool Initial Size");
- assertThat(section.getAttributes(0).getLongValue()).isGreaterThanOrEqualTo(0);
+ assertThat(section.getAttributesCount()).isEqualTo(7);
+ assertThat(section.getAttributes(0).getKey()).isEqualTo("Pool Total Connections");
+ assertThat(section.getAttributes(0).getLongValue()).isPositive();
}
@CheckForNull
private ObjectInstance getMBean() throws Exception {
try {
- return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(OBJECT_NAME));
+ return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName("SonarQube:name=ComputeEngineDatabaseConnection"));
} catch (InstanceNotFoundException e) {
return null;
}
diff --git a/server/sonar-db-core/build.gradle b/server/sonar-db-core/build.gradle
index 83bd1e9c8c2..c37d4764667 100644
--- a/server/sonar-db-core/build.gradle
+++ b/server/sonar-db-core/build.gradle
@@ -12,7 +12,7 @@ dependencies {
compile 'com.google.guava:guava'
compile 'commons-io:commons-io'
compile 'commons-lang:commons-lang'
- compile 'org.apache.commons:commons-dbcp2'
+ compile 'com.zaxxer:HikariCP'
compile 'org.mybatis:mybatis'
compile 'org.slf4j:slf4j-api'
compile 'org.sonarsource.api.plugin:sonar-plugin-api'
@@ -27,7 +27,9 @@ dependencies {
testCompile 'com.oracle.database.jdbc:ojdbc8'
testCompile 'com.tngtech.java:junit-dataprovider'
testCompile 'org.mockito:mockito-core'
+ testCompile 'org.mockito:mockito-inline'
testCompile 'org.postgresql:postgresql'
+
testCompile project(':sonar-testing-harness')
testRuntime 'com.h2database:h2'
diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/DefaultDatabase.java b/server/sonar-db-core/src/main/java/org/sonar/db/DefaultDatabase.java
index be9cd2b872c..837b941f445 100644
--- a/server/sonar-db-core/src/main/java/org/sonar/db/DefaultDatabase.java
+++ b/server/sonar-db-core/src/main/java/org/sonar/db/DefaultDatabase.java
@@ -21,15 +21,15 @@ package org.sonar.db;
import ch.qos.logback.classic.Level;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableMap;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
import javax.sql.DataSource;
-import org.apache.commons.dbcp2.BasicDataSource;
-import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.config.internal.Settings;
import org.sonar.api.utils.log.Logger;
@@ -43,7 +43,12 @@ import org.sonar.process.logging.LogbackHelper;
import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;
+import static org.sonar.process.ProcessProperties.Property.JDBC_DRIVER_PATH;
+import static org.sonar.process.ProcessProperties.Property.JDBC_EMBEDDED_PORT;
+import static org.sonar.process.ProcessProperties.Property.JDBC_MIN_IDLE;
+import static org.sonar.process.ProcessProperties.Property.JDBC_PASSWORD;
import static org.sonar.process.ProcessProperties.Property.JDBC_URL;
+import static org.sonar.process.ProcessProperties.Property.JDBC_USERNAME;
/**
* @since 2.12
@@ -57,12 +62,25 @@ public class DefaultDatabase implements Database {
private static final String SONAR_JDBC_DIALECT = "sonar.jdbc.dialect";
private static final String SONAR_JDBC_DRIVER = "sonar.jdbc.driverClassName";
private static final String SONAR_JDBC_MAX_ACTIVE = "sonar.jdbc.maxActive";
- private static final String DBCP_JDBC_MAX_ACTIVE = "maxTotal";
private static final String SONAR_JDBC_MAX_WAIT = "sonar.jdbc.maxWait";
- private static final String DBCP_JDBC_MAX_WAIT = "maxWaitMillis";
- private static final Map<String, String> SONAR_JDBC_TO_DBCP_PROPERTY_MAPPINGS = ImmutableMap.of(
- SONAR_JDBC_MAX_ACTIVE, DBCP_JDBC_MAX_ACTIVE,
- SONAR_JDBC_MAX_WAIT, DBCP_JDBC_MAX_WAIT);
+ private static final Set<String> DEPRECATED_SONAR_PROPERTIES = Set.of(
+ "sonar.jdbc.maxIdle",
+ "sonar.jdbc.minEvictableIdleTimeMillis",
+ "sonar.jdbc.timeBetweenEvictionRunsMillis");
+
+ private static final Set<String> IGNORED_SONAR_PROPERTIES = Set.of(SONAR_JDBC_DIALECT, JDBC_DRIVER_PATH.getKey(),
+ "sonar.jdbc.maxIdle",
+ "sonar.jdbc.minEvictableIdleTimeMillis",
+ "sonar.jdbc.timeBetweenEvictionRunsMillis");
+
+ private static final Map<String, String> SONAR_JDBC_TO_HIKARI_PROPERTY_MAPPINGS = Map.of(
+ JDBC_USERNAME.getKey(), "dataSource.user",
+ JDBC_PASSWORD.getKey(), "dataSource.password",
+ JDBC_EMBEDDED_PORT.getKey(), "dataSource.portNumber",
+ JDBC_URL.getKey(), "jdbcUrl",
+ SONAR_JDBC_MAX_WAIT, "connectionTimeout",
+ SONAR_JDBC_MAX_ACTIVE, "maximumPoolSize",
+ JDBC_MIN_IDLE.getKey(), "minimumIdle");
private final LogbackHelper logbackHelper;
private final Settings settings;
@@ -99,16 +117,22 @@ public class DefaultDatabase implements Database {
properties.setProperty(SONAR_JDBC_DRIVER, dialect.getDefaultDriverClassName());
}
- private void initDataSource() throws Exception {
- // but it's correctly caught by start()
- LOG.info("Create JDBC data source for {}", properties.getProperty(JDBC_URL.getKey()), DEFAULT_URL);
- BasicDataSource basicDataSource = BasicDataSourceFactory.createDataSource(extractCommonsDbcpProperties(properties));
- datasource = new ProfiledDataSource(basicDataSource, NullConnectionInterceptor.INSTANCE);
- datasource.setConnectionInitSqls(dialect.getConnectionInitStatements());
- datasource.setValidationQuery(dialect.getValidationQuery());
+ private void initDataSource() {
+ LOG.info("Create JDBC data source for {}", properties.getProperty(JDBC_URL.getKey(), DEFAULT_URL));
+ HikariDataSource ds = createHikariDataSource();
+ datasource = new ProfiledDataSource(ds, NullConnectionInterceptor.INSTANCE);
enableSqlLogging(datasource, logbackHelper.getLoggerLevel("sql") == Level.TRACE);
}
+ private HikariDataSource createHikariDataSource() {
+ HikariConfig config = new HikariConfig(extractCommonsHikariProperties(properties));
+ if (!dialect.getConnectionInitStatements().isEmpty()) {
+ config.setConnectionInitSql(dialect.getConnectionInitStatements().get(0));
+ }
+ config.setConnectionTestQuery(dialect.getValidationQuery());
+ return new HikariDataSource(config);
+ }
+
private void checkConnection() {
Connection connection = null;
try {
@@ -124,11 +148,7 @@ public class DefaultDatabase implements Database {
@Override
public void stop() {
if (datasource != null) {
- try {
- datasource.close();
- } catch (SQLException e) {
- throw new IllegalStateException("Fail to stop JDBC connection pool", e);
- }
+ datasource.close();
}
}
@@ -171,17 +191,22 @@ public class DefaultDatabase implements Database {
}
@VisibleForTesting
- static Properties extractCommonsDbcpProperties(Properties properties) {
+ static Properties extractCommonsHikariProperties(Properties properties) {
Properties result = new Properties();
- result.setProperty("accessToUnderlyingConnectionAllowed", "true");
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
String key = (String) entry.getKey();
+ if (IGNORED_SONAR_PROPERTIES.contains(key)) {
+ if (DEPRECATED_SONAR_PROPERTIES.contains(key)) {
+ LOG.warn("Property [{}] has no effect as pool connection implementation changed, check 9.7 upgrade notes.", key);
+ }
+ continue;
+ }
if (StringUtils.startsWith(key, SONAR_JDBC)) {
- String resolvedKey = toDbcpPropertyKey(key);
+ String resolvedKey = toHikariPropertyKey(key);
String existingValue = (String) result.setProperty(resolvedKey, (String) entry.getValue());
checkState(existingValue == null || existingValue.equals(entry.getValue()),
"Duplicate property declaration for resolved jdbc key '%s': conflicting values are '%s' and '%s'", resolvedKey, existingValue, entry.getValue());
- result.setProperty(toDbcpPropertyKey(key), (String) entry.getValue());
+ result.setProperty(resolvedKey, (String) entry.getValue());
}
}
return result;
@@ -193,9 +218,9 @@ public class DefaultDatabase implements Database {
}
}
- private static String toDbcpPropertyKey(String key) {
- if (SONAR_JDBC_TO_DBCP_PROPERTY_MAPPINGS.containsKey(key)) {
- return SONAR_JDBC_TO_DBCP_PROPERTY_MAPPINGS.get(key);
+ private static String toHikariPropertyKey(String key) {
+ if (SONAR_JDBC_TO_HIKARI_PROPERTY_MAPPINGS.containsKey(key)) {
+ return SONAR_JDBC_TO_HIKARI_PROPERTY_MAPPINGS.get(key);
}
return StringUtils.removeStart(key, SONAR_JDBC);
diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/profiling/ConnectionInterceptor.java b/server/sonar-db-core/src/main/java/org/sonar/db/profiling/ConnectionInterceptor.java
index 1a856ca23ce..650405c19c5 100644
--- a/server/sonar-db-core/src/main/java/org/sonar/db/profiling/ConnectionInterceptor.java
+++ b/server/sonar-db-core/src/main/java/org/sonar/db/profiling/ConnectionInterceptor.java
@@ -21,12 +21,12 @@ package org.sonar.db.profiling;
import java.sql.Connection;
import java.sql.SQLException;
-import org.apache.commons.dbcp2.BasicDataSource;
+import javax.sql.DataSource;
public interface ConnectionInterceptor {
- Connection getConnection(BasicDataSource dataSource) throws SQLException;
+ Connection getConnection(DataSource dataSource) throws SQLException;
- Connection getConnection(BasicDataSource dataSource, String login, String password) throws SQLException;
+ Connection getConnection(DataSource dataSource, String login, String password) throws SQLException;
}
diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/profiling/NullConnectionInterceptor.java b/server/sonar-db-core/src/main/java/org/sonar/db/profiling/NullConnectionInterceptor.java
index 9e069ccb408..c8d4d3b2915 100644
--- a/server/sonar-db-core/src/main/java/org/sonar/db/profiling/NullConnectionInterceptor.java
+++ b/server/sonar-db-core/src/main/java/org/sonar/db/profiling/NullConnectionInterceptor.java
@@ -21,18 +21,18 @@ package org.sonar.db.profiling;
import java.sql.Connection;
import java.sql.SQLException;
-import org.apache.commons.dbcp2.BasicDataSource;
+import javax.sql.DataSource;
public enum NullConnectionInterceptor implements ConnectionInterceptor {
INSTANCE;
@Override
- public Connection getConnection(BasicDataSource dataSource) throws SQLException {
+ public Connection getConnection(DataSource dataSource) throws SQLException {
return dataSource.getConnection();
}
@Override
- public Connection getConnection(BasicDataSource dataSource, String user, String password) throws SQLException {
+ public Connection getConnection(DataSource dataSource, String user, String password) throws SQLException {
return dataSource.getConnection(user, password);
}
}
diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/profiling/ProfiledConnectionInterceptor.java b/server/sonar-db-core/src/main/java/org/sonar/db/profiling/ProfiledConnectionInterceptor.java
index 43f79c54c68..b2c384f3572 100644
--- a/server/sonar-db-core/src/main/java/org/sonar/db/profiling/ProfiledConnectionInterceptor.java
+++ b/server/sonar-db-core/src/main/java/org/sonar/db/profiling/ProfiledConnectionInterceptor.java
@@ -22,18 +22,18 @@ package org.sonar.db.profiling;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
-import org.apache.commons.dbcp2.BasicDataSource;
+import javax.sql.DataSource;
public enum ProfiledConnectionInterceptor implements ConnectionInterceptor {
INSTANCE;
@Override
- public Connection getConnection(BasicDataSource dataSource) throws SQLException {
+ public Connection getConnection(DataSource dataSource) throws SQLException {
return buildConnectionProxy(new ProfilingConnectionHandler(dataSource.getConnection()));
}
@Override
- public Connection getConnection(BasicDataSource dataSource, String login, String password) throws SQLException {
+ public Connection getConnection(DataSource dataSource, String login, String password) throws SQLException {
return buildConnectionProxy(new ProfilingConnectionHandler(dataSource.getConnection(login, password)));
}
diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/profiling/ProfiledDataSource.java b/server/sonar-db-core/src/main/java/org/sonar/db/profiling/ProfiledDataSource.java
index 579a4dc2bea..410aecb0e7a 100644
--- a/server/sonar-db-core/src/main/java/org/sonar/db/profiling/ProfiledDataSource.java
+++ b/server/sonar-db-core/src/main/java/org/sonar/db/profiling/ProfiledDataSource.java
@@ -19,32 +19,37 @@
*/
package org.sonar.db.profiling;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariConfigMXBean;
+import com.zaxxer.hikari.HikariDataSource;
+import com.zaxxer.hikari.HikariPoolMXBean;
+import com.zaxxer.hikari.metrics.MetricsTrackerFactory;
import java.io.PrintWriter;
import java.sql.Connection;
-import java.sql.Driver;
+import java.sql.ConnectionBuilder;
import java.sql.SQLException;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-import org.apache.commons.dbcp2.BasicDataSource;
+import java.sql.SQLFeatureNotSupportedException;
+import java.sql.ShardingKeyBuilder;
+import java.util.Properties;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import javax.sql.DataSource;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-public class ProfiledDataSource extends BasicDataSource {
+public class ProfiledDataSource extends HikariDataSource {
static final Logger SQL_LOGGER = Loggers.get("sql");
- private final BasicDataSource delegate;
+ private final HikariDataSource delegate;
private ConnectionInterceptor connectionInterceptor;
- public ProfiledDataSource(BasicDataSource delegate, ConnectionInterceptor connectionInterceptor) {
+ public ProfiledDataSource(HikariDataSource delegate, ConnectionInterceptor connectionInterceptor) {
this.delegate = delegate;
this.connectionInterceptor = connectionInterceptor;
}
- public BasicDataSource getDelegate() {
+ public HikariDataSource getDelegate() {
return delegate;
}
@@ -53,33 +58,33 @@ public class ProfiledDataSource extends BasicDataSource {
}
@Override
- public Boolean getDefaultAutoCommit() {
- return delegate.getDefaultAutoCommit();
+ public boolean isAutoCommit() {
+ return delegate.isAutoCommit();
}
@Override
- public Boolean getDefaultReadOnly() {
- return delegate.getDefaultReadOnly();
+ public boolean isReadOnly() {
+ return delegate.isReadOnly();
}
@Override
- public int getDefaultTransactionIsolation() {
- return delegate.getDefaultTransactionIsolation();
+ public String getTransactionIsolation() {
+ return delegate.getTransactionIsolation();
}
@Override
- public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
- delegate.setDefaultTransactionIsolation(defaultTransactionIsolation);
+ public void setTransactionIsolation(String defaultTransactionIsolation) {
+ delegate.setTransactionIsolation(defaultTransactionIsolation);
}
@Override
- public String getDefaultCatalog() {
- return delegate.getDefaultCatalog();
+ public String getCatalog() {
+ return delegate.getCatalog();
}
@Override
- public void setDefaultCatalog(String defaultCatalog) {
- delegate.setDefaultCatalog(defaultCatalog);
+ public void setCatalog(String defaultCatalog) {
+ delegate.setCatalog(defaultCatalog);
}
@Override
@@ -93,153 +98,158 @@ public class ProfiledDataSource extends BasicDataSource {
}
@Override
- public synchronized ClassLoader getDriverClassLoader() {
- return delegate.getDriverClassLoader();
+ public int getMaximumPoolSize() {
+ return delegate.getMaximumPoolSize();
}
@Override
- public synchronized void setDriverClassLoader(ClassLoader driverClassLoader) {
- delegate.setDriverClassLoader(driverClassLoader);
+ public void setMaximumPoolSize(int maxActive) {
+ delegate.setMaximumPoolSize(maxActive);
}
@Override
- public synchronized int getMaxTotal() {
- return delegate.getMaxTotal();
+ public Connection getConnection() throws SQLException {
+ return connectionInterceptor.getConnection(delegate);
}
@Override
- public synchronized void setMaxTotal(int maxActive) {
- delegate.setMaxTotal(maxActive);
+ public Connection getConnection(String login, String password) throws SQLException {
+ return connectionInterceptor.getConnection(this, login, password);
}
@Override
- public synchronized int getMaxIdle() {
- return delegate.getMaxIdle();
+ public PrintWriter getLogWriter() throws SQLException {
+ return delegate.getLogWriter();
}
@Override
- public synchronized void setMaxIdle(int maxIdle) {
- delegate.setMaxIdle(maxIdle);
+ public void setLogWriter(PrintWriter out) throws SQLException {
+ delegate.setLogWriter(out);
}
@Override
- public synchronized int getMinIdle() {
- return delegate.getMinIdle();
+ public void setLoginTimeout(int seconds) throws SQLException {
+ delegate.setLoginTimeout(seconds);
}
@Override
- public synchronized void setMinIdle(int minIdle) {
- delegate.setMinIdle(minIdle);
+ public int getLoginTimeout() throws SQLException {
+ return delegate.getLoginTimeout();
}
@Override
- public synchronized int getInitialSize() {
- return delegate.getInitialSize();
+ public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ return delegate.getParentLogger();
}
@Override
- public synchronized void setInitialSize(int initialSize) {
- delegate.setInitialSize(initialSize);
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ return delegate.unwrap(iface);
}
@Override
- public synchronized long getMaxWaitMillis() {
- return delegate.getMaxWaitMillis();
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ return delegate.isWrapperFor(iface);
}
@Override
- public synchronized void setMaxWaitMillis(long maxWait) {
- delegate.setMaxWaitMillis(maxWait);
+ public void setMetricRegistry(Object metricRegistry) {
+ delegate.setMetricRegistry(metricRegistry);
}
@Override
- public synchronized boolean isPoolPreparedStatements() {
- return delegate.isPoolPreparedStatements();
+ public void setMetricsTrackerFactory(MetricsTrackerFactory metricsTrackerFactory) {
+ delegate.setMetricsTrackerFactory(metricsTrackerFactory);
}
@Override
- public synchronized void setPoolPreparedStatements(boolean poolingStatements) {
- delegate.setPoolPreparedStatements(poolingStatements);
+ public void setHealthCheckRegistry(Object healthCheckRegistry) {
+ delegate.setHealthCheckRegistry(healthCheckRegistry);
}
@Override
- public synchronized int getMaxOpenPreparedStatements() {
- return delegate.getMaxOpenPreparedStatements();
+ public boolean isRunning() {
+ return delegate.isRunning();
}
@Override
- public synchronized void setMaxOpenPreparedStatements(int maxOpenStatements) {
- delegate.setMaxOpenPreparedStatements(maxOpenStatements);
+ public HikariPoolMXBean getHikariPoolMXBean() {
+ return delegate.getHikariPoolMXBean();
}
@Override
- public synchronized boolean getTestOnBorrow() {
- return delegate.getTestOnBorrow();
+ public HikariConfigMXBean getHikariConfigMXBean() {
+ return delegate.getHikariConfigMXBean();
}
@Override
- public synchronized void setTestOnBorrow(boolean testOnBorrow) {
- delegate.setTestOnBorrow(testOnBorrow);
+ public void evictConnection(Connection connection) {
+ delegate.evictConnection(connection);
}
@Override
- public synchronized boolean getTestOnReturn() {
- return delegate.getTestOnReturn();
+ public void close() {
+ delegate.close();
}
@Override
- public synchronized void setTestOnReturn(boolean testOnReturn) {
- delegate.setTestOnReturn(testOnReturn);
+ public boolean isClosed() {
+ return delegate.isClosed();
}
@Override
- public synchronized long getTimeBetweenEvictionRunsMillis() {
- return delegate.getTimeBetweenEvictionRunsMillis();
+ public String toString() {
+ return delegate.toString();
}
@Override
- public synchronized void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
- delegate.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+ public long getConnectionTimeout() {
+ return delegate.getConnectionTimeout();
}
@Override
- public synchronized int getNumTestsPerEvictionRun() {
- return delegate.getNumTestsPerEvictionRun();
+ public void setConnectionTimeout(long connectionTimeoutMs) {
+ delegate.setConnectionTimeout(connectionTimeoutMs);
}
@Override
- public synchronized void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
- delegate.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
+ public long getIdleTimeout() {
+ return delegate.getIdleTimeout();
}
@Override
- public synchronized long getMinEvictableIdleTimeMillis() {
- return delegate.getMinEvictableIdleTimeMillis();
+ public void setIdleTimeout(long idleTimeoutMs) {
+ delegate.setIdleTimeout(idleTimeoutMs);
}
@Override
- public synchronized void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
- delegate.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
+ public long getLeakDetectionThreshold() {
+ return delegate.getLeakDetectionThreshold();
}
@Override
- public synchronized boolean getTestWhileIdle() {
- return delegate.getTestWhileIdle();
+ public void setLeakDetectionThreshold(long leakDetectionThresholdMs) {
+ delegate.setLeakDetectionThreshold(leakDetectionThresholdMs);
}
@Override
- public synchronized void setTestWhileIdle(boolean testWhileIdle) {
- delegate.setTestWhileIdle(testWhileIdle);
+ public long getMaxLifetime() {
+ return delegate.getMaxLifetime();
}
@Override
- public synchronized int getNumActive() {
- return delegate.getNumActive();
+ public void setMaxLifetime(long maxLifetimeMs) {
+ delegate.setMaxLifetime(maxLifetimeMs);
}
@Override
- public synchronized int getNumIdle() {
- return delegate.getNumIdle();
+ public int getMinimumIdle() {
+ return delegate.getMinimumIdle();
+ }
+
+ @Override
+ public void setMinimumIdle(int minIdle) {
+ delegate.setMinimumIdle(minIdle);
}
@Override
@@ -253,16 +263,6 @@ public class ProfiledDataSource extends BasicDataSource {
}
@Override
- public synchronized String getUrl() {
- return delegate.getUrl();
- }
-
- @Override
- public synchronized void setUrl(String url) {
- delegate.setUrl(url);
- }
-
- @Override
public String getUsername() {
return delegate.getUsername();
}
@@ -273,368 +273,249 @@ public class ProfiledDataSource extends BasicDataSource {
}
@Override
- public String getValidationQuery() {
- return delegate.getValidationQuery();
- }
-
- @Override
- public void setValidationQuery(String validationQuery) {
- delegate.setValidationQuery(validationQuery);
- }
-
- @Override
- public int getValidationQueryTimeout() {
- return delegate.getValidationQueryTimeout();
- }
-
- @Override
- public void setValidationQueryTimeout(int timeout) {
- delegate.setValidationQueryTimeout(timeout);
- }
-
- @Override
- public List<String> getConnectionInitSqls() {
- return delegate.getConnectionInitSqls();
- }
-
- @Override
- public void setConnectionInitSqls(Collection<String> connectionInitSqls) {
- delegate.setConnectionInitSqls(connectionInitSqls);
- }
-
- @Override
- public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
- return delegate.isAccessToUnderlyingConnectionAllowed();
- }
-
- @Override
- public synchronized void setAccessToUnderlyingConnectionAllowed(boolean allow) {
- delegate.setAccessToUnderlyingConnectionAllowed(allow);
- }
-
- @Override
- public Connection getConnection() throws SQLException {
- return connectionInterceptor.getConnection(delegate);
- }
-
- @Override
- public Connection getConnection(String login, String password) throws SQLException {
- return connectionInterceptor.getConnection(this, login, password);
- }
-
- @Override
- public int getLoginTimeout() throws SQLException {
- return delegate.getLoginTimeout();
- }
-
- @Override
- public java.util.logging.Logger getParentLogger() {
- return java.util.logging.Logger.getLogger(getClass().getName());
- }
-
- @Override
- public PrintWriter getLogWriter() throws SQLException {
- return delegate.getLogWriter();
- }
-
- @Override
- public void setLoginTimeout(int loginTimeout) throws SQLException {
- delegate.setLoginTimeout(loginTimeout);
- }
-
- @Override
- public void setLogWriter(PrintWriter logWriter) throws SQLException {
- delegate.setLogWriter(logWriter);
- }
-
- @Override
- public boolean getRemoveAbandonedOnBorrow() {
- return delegate.getRemoveAbandonedOnBorrow();
- }
-
- @Override
- public void setRemoveAbandonedOnBorrow(boolean removeAbandoned) {
- delegate.setRemoveAbandonedOnBorrow(removeAbandoned);
- }
-
-
- @Override
- public boolean getRemoveAbandonedOnMaintenance() {
- return delegate.getRemoveAbandonedOnMaintenance();
+ public long getValidationTimeout() {
+ return delegate.getValidationTimeout();
}
@Override
- public void setRemoveAbandonedOnMaintenance(boolean removeAbandoned) {
- delegate.setRemoveAbandonedOnMaintenance(removeAbandoned);
+ public void setValidationTimeout(long validationTimeoutMs) {
+ delegate.setValidationTimeout(validationTimeoutMs);
}
@Override
- public int getRemoveAbandonedTimeout() {
- return delegate.getRemoveAbandonedTimeout();
+ public String getConnectionTestQuery() {
+ return delegate.getConnectionTestQuery();
}
@Override
- public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
- delegate.setRemoveAbandonedTimeout(removeAbandonedTimeout);
+ public void setConnectionTestQuery(String connectionTestQuery) {
+ delegate.setConnectionTestQuery(connectionTestQuery);
}
@Override
- public boolean getLogAbandoned() {
- return delegate.getLogAbandoned();
+ public String getConnectionInitSql() {
+ return delegate.getConnectionInitSql();
}
@Override
- public void setLogAbandoned(boolean logAbandoned) {
- delegate.setLogAbandoned(logAbandoned);
+ public void setConnectionInitSql(String connectionInitSql) {
+ delegate.setConnectionInitSql(connectionInitSql);
}
@Override
- public void addConnectionProperty(String name, String value) {
- delegate.addConnectionProperty(name, value);
+ public DataSource getDataSource() {
+ return delegate.getDataSource();
}
@Override
- public void removeConnectionProperty(String name) {
- delegate.removeConnectionProperty(name);
+ public void setDataSource(DataSource dataSource) {
+ delegate.setDataSource(dataSource);
}
@Override
- public void setConnectionProperties(String connectionProperties) {
- delegate.setConnectionProperties(connectionProperties);
+ public String getDataSourceClassName() {
+ return delegate.getDataSourceClassName();
}
@Override
- public synchronized void close() throws SQLException {
- delegate.close();
- }
-
- @Override
- public synchronized boolean isClosed() {
- return delegate.isClosed();
+ public void setDataSourceClassName(String className) {
+ delegate.setDataSourceClassName(className);
}
@Override
- public boolean isWrapperFor(Class<?> iface) throws SQLException {
- return delegate.isWrapperFor(iface);
+ public void addDataSourceProperty(String propertyName, Object value) {
+ delegate.addDataSourceProperty(propertyName, value);
}
@Override
- public <T> T unwrap(Class<T> iface) throws SQLException {
- return delegate.unwrap(iface);
+ public String getDataSourceJNDI() {
+ return delegate.getDataSourceJNDI();
}
@Override
- public void setDefaultAutoCommit(Boolean defaultAutoCommit) {
- delegate.setDefaultAutoCommit(defaultAutoCommit);
+ public void setDataSourceJNDI(String jndiDataSource) {
+ delegate.setDataSourceJNDI(jndiDataSource);
}
@Override
- public void setDefaultReadOnly(Boolean defaultReadOnly) {
- delegate.setDefaultReadOnly(defaultReadOnly);
+ public Properties getDataSourceProperties() {
+ return delegate.getDataSourceProperties();
}
@Override
- public Integer getDefaultQueryTimeout() {
- return delegate.getDefaultQueryTimeout();
+ public void setDataSourceProperties(Properties dsProperties) {
+ delegate.setDataSourceProperties(dsProperties);
}
@Override
- public void setDefaultQueryTimeout(Integer defaultQueryTimeoutSeconds) {
- delegate.setDefaultQueryTimeout(defaultQueryTimeoutSeconds);
+ public String getJdbcUrl() {
+ return delegate.getJdbcUrl();
}
@Override
- public String getDefaultSchema() {
- return delegate.getDefaultSchema();
+ public void setJdbcUrl(String jdbcUrl) {
+ delegate.setJdbcUrl(jdbcUrl);
}
@Override
- public void setDefaultSchema(String defaultSchema) {
- delegate.setDefaultSchema(defaultSchema);
+ public void setAutoCommit(boolean isAutoCommit) {
+ delegate.setAutoCommit(isAutoCommit);
}
@Override
- public boolean getCacheState() {
- return delegate.getCacheState();
+ public boolean isAllowPoolSuspension() {
+ return delegate.isAllowPoolSuspension();
}
@Override
- public void setCacheState(boolean cacheState) {
- delegate.setCacheState(cacheState);
+ public void setAllowPoolSuspension(boolean isAllowPoolSuspension) {
+ delegate.setAllowPoolSuspension(isAllowPoolSuspension);
}
@Override
- public synchronized Driver getDriver() {
- return delegate.getDriver();
+ public long getInitializationFailTimeout() {
+ return delegate.getInitializationFailTimeout();
}
@Override
- public synchronized void setDriver(Driver driver) {
- delegate.setDriver(driver);
+ public void setInitializationFailTimeout(long initializationFailTimeout) {
+ delegate.setInitializationFailTimeout(initializationFailTimeout);
}
@Override
- public synchronized boolean getLifo() {
- return delegate.getLifo();
+ public boolean isIsolateInternalQueries() {
+ return delegate.isIsolateInternalQueries();
}
@Override
- public synchronized void setLifo(boolean lifo) {
- delegate.setLifo(lifo);
+ public void setIsolateInternalQueries(boolean isolate) {
+ delegate.setIsolateInternalQueries(isolate);
}
@Override
- public synchronized boolean getTestOnCreate() {
- return delegate.getTestOnCreate();
+ public MetricsTrackerFactory getMetricsTrackerFactory() {
+ return delegate.getMetricsTrackerFactory();
}
@Override
- public synchronized void setTestOnCreate(boolean testOnCreate) {
- delegate.setTestOnCreate(testOnCreate);
+ public Object getMetricRegistry() {
+ return delegate.getMetricRegistry();
}
@Override
- public synchronized void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis) {
- delegate.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
+ public Object getHealthCheckRegistry() {
+ return delegate.getHealthCheckRegistry();
}
@Override
- public synchronized long getSoftMinEvictableIdleTimeMillis() {
- return delegate.getSoftMinEvictableIdleTimeMillis();
+ public Properties getHealthCheckProperties() {
+ return delegate.getHealthCheckProperties();
}
@Override
- public synchronized String getEvictionPolicyClassName() {
- return delegate.getEvictionPolicyClassName();
+ public void setHealthCheckProperties(Properties healthCheckProperties) {
+ delegate.setHealthCheckProperties(healthCheckProperties);
}
@Override
- public synchronized void setEvictionPolicyClassName(String evictionPolicyClassName) {
- delegate.setEvictionPolicyClassName(evictionPolicyClassName);
+ public void addHealthCheckProperty(String key, String value) {
+ delegate.addHealthCheckProperty(key, value);
}
@Override
- public String[] getConnectionInitSqlsAsArray() {
- return delegate.getConnectionInitSqlsAsArray();
+ public long getKeepaliveTime() {
+ return delegate.getKeepaliveTime();
}
@Override
- public long getMaxConnLifetimeMillis() {
- return delegate.getMaxConnLifetimeMillis();
+ public void setKeepaliveTime(long keepaliveTimeMs) {
+ delegate.setKeepaliveTime(keepaliveTimeMs);
}
@Override
- public boolean getLogExpiredConnections() {
- return delegate.getLogExpiredConnections();
+ public void setReadOnly(boolean readOnly) {
+ delegate.setReadOnly(readOnly);
}
@Override
- public void setMaxConnLifetimeMillis(long maxConnLifetimeMillis) {
- delegate.setMaxConnLifetimeMillis(maxConnLifetimeMillis);
+ public boolean isRegisterMbeans() {
+ return delegate.isRegisterMbeans();
}
@Override
- public void setLogExpiredConnections(boolean logExpiredConnections) {
- delegate.setLogExpiredConnections(logExpiredConnections);
+ public void setRegisterMbeans(boolean register) {
+ delegate.setRegisterMbeans(register);
}
@Override
- public String getJmxName() {
- return delegate.getJmxName();
+ public String getPoolName() {
+ return delegate.getPoolName();
}
@Override
- public void setJmxName(String jmxName) {
- delegate.setJmxName(jmxName);
+ public void setPoolName(String poolName) {
+ delegate.setPoolName(poolName);
}
@Override
- public boolean getEnableAutoCommitOnReturn() {
- return delegate.getEnableAutoCommitOnReturn();
+ public ScheduledExecutorService getScheduledExecutor() {
+ return delegate.getScheduledExecutor();
}
@Override
- public void setEnableAutoCommitOnReturn(boolean enableAutoCommitOnReturn) {
- delegate.setEnableAutoCommitOnReturn(enableAutoCommitOnReturn);
+ public void setScheduledExecutor(ScheduledExecutorService executor) {
+ delegate.setScheduledExecutor(executor);
}
@Override
- public boolean getRollbackOnReturn() {
- return delegate.getRollbackOnReturn();
+ public String getSchema() {
+ return delegate.getSchema();
}
@Override
- public void setRollbackOnReturn(boolean rollbackOnReturn) {
- delegate.setRollbackOnReturn(rollbackOnReturn);
+ public void setSchema(String schema) {
+ delegate.setSchema(schema);
}
@Override
- public Set<String> getDisconnectionSqlCodes() {
- return delegate.getDisconnectionSqlCodes();
+ public String getExceptionOverrideClassName() {
+ return delegate.getExceptionOverrideClassName();
}
@Override
- public String[] getDisconnectionSqlCodesAsArray() {
- return delegate.getDisconnectionSqlCodesAsArray();
+ public void setExceptionOverrideClassName(String exceptionOverrideClassName) {
+ delegate.setExceptionOverrideClassName(exceptionOverrideClassName);
}
@Override
- public void setDisconnectionSqlCodes(Collection<String> disconnectionSqlCodes) {
- delegate.setDisconnectionSqlCodes(disconnectionSqlCodes);
+ public ThreadFactory getThreadFactory() {
+ return delegate.getThreadFactory();
}
@Override
- public boolean getFastFailValidation() {
- return delegate.getFastFailValidation();
+ public void setThreadFactory(ThreadFactory threadFactory) {
+ delegate.setThreadFactory(threadFactory);
}
@Override
- public void setFastFailValidation(boolean fastFailValidation) {
- delegate.setFastFailValidation(fastFailValidation);
+ public void copyStateTo(HikariConfig other) {
+ delegate.copyStateTo(other);
}
@Override
- public PrintWriter getAbandonedLogWriter() {
- return delegate.getAbandonedLogWriter();
+ public void validate() {
+ delegate.validate();
}
@Override
- public void setAbandonedLogWriter(PrintWriter logWriter) {
- delegate.setAbandonedLogWriter(logWriter);
+ public ConnectionBuilder createConnectionBuilder() throws SQLException {
+ return delegate.createConnectionBuilder();
}
@Override
- public boolean getAbandonedUsageTracking() {
- return delegate.getAbandonedUsageTracking();
+ public ShardingKeyBuilder createShardingKeyBuilder() throws SQLException {
+ return delegate.createShardingKeyBuilder();
}
- @Override
- public void setAbandonedUsageTracking(boolean usageTracking) {
- delegate.setAbandonedUsageTracking(usageTracking);
- }
- @Override
- public void invalidateConnection(Connection connection) {
- delegate.invalidateConnection(connection);
- }
-
- @Override
- public ObjectName preRegister(MBeanServer server, ObjectName objectName) {
- return delegate.preRegister(server, objectName);
- }
-
- @Override
- public void postRegister(Boolean registrationDone) {
- delegate.postRegister(registrationDone);
- }
-
- @Override
- public void preDeregister() throws Exception {
- delegate.preDeregister();
- }
-
- @Override
- public void postDeregister() {
- delegate.postDeregister();
- }
}
diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/DefaultDatabaseTest.java b/server/sonar-db-core/src/test/java/org/sonar/db/DefaultDatabaseTest.java
index 67d05f4e1e8..07488e08e90 100644
--- a/server/sonar-db-core/src/test/java/org/sonar/db/DefaultDatabaseTest.java
+++ b/server/sonar-db-core/src/test/java/org/sonar/db/DefaultDatabaseTest.java
@@ -22,11 +22,13 @@ package org.sonar.db;
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
+import com.zaxxer.hikari.HikariDataSource;
import java.util.Properties;
-import org.apache.commons.dbcp2.BasicDataSource;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.utils.log.LogTester;
import org.sonar.db.dialect.PostgreSql;
import org.sonar.process.logging.LogbackHelper;
@@ -38,9 +40,11 @@ import static org.mockito.Mockito.mock;
@RunWith(DataProviderRunner.class)
public class DefaultDatabaseTest {
- private LogbackHelper logbackHelper = mock(LogbackHelper.class);
+ private final LogbackHelper logbackHelper = mock(LogbackHelper.class);
private static final String SONAR_JDBC = "sonar.jdbc.";
+ @Rule
+ public final LogTester logTester = new LogTester();
@Test
public void shouldLoadDefaultValues() {
@@ -54,19 +58,36 @@ public class DefaultDatabaseTest {
}
@Test
- public void shouldExtractCommonsDbcpProperties() {
+ public void shouldExtractHikariProperties() {
Properties props = new Properties();
props.setProperty("sonar.jdbc.driverClassName", "my.Driver");
props.setProperty("sonar.jdbc.username", "me");
- props.setProperty("sonar.jdbc.maxActive", "5");
- props.setProperty("sonar.jdbc.maxWait", "5000");
+ props.setProperty("sonar.jdbc.maximumPoolSize", "5");
+ props.setProperty("sonar.jdbc.connectionTimeout", "5000");
- Properties commonsDbcpProps = DefaultDatabase.extractCommonsDbcpProperties(props);
+ Properties hikariProps = DefaultDatabase.extractCommonsHikariProperties(props);
- assertThat(commonsDbcpProps.getProperty("username")).isEqualTo("me");
- assertThat(commonsDbcpProps.getProperty("driverClassName")).isEqualTo("my.Driver");
- assertThat(commonsDbcpProps.getProperty("maxTotal")).isEqualTo("5");
- assertThat(commonsDbcpProps.getProperty("maxWaitMillis")).isEqualTo("5000");
+ assertThat(hikariProps.getProperty("dataSource.user")).isEqualTo("me");
+ assertThat(hikariProps.getProperty("driverClassName")).isEqualTo("my.Driver");
+ assertThat(hikariProps.getProperty("maximumPoolSize")).isEqualTo("5");
+ assertThat(hikariProps.getProperty("connectionTimeout")).isEqualTo("5000");
+ }
+
+ @Test
+ public void logWarningIfDeprecatedPropertyUsed() {
+ Properties props = new Properties();
+
+ props.setProperty("sonar.jdbc.maxIdle", "5");
+ props.setProperty("sonar.jdbc.minEvictableIdleTimeMillis", "300000");
+ props.setProperty("sonar.jdbc.timeBetweenEvictionRunsMillis", "1000");
+ props.setProperty("sonar.jdbc.connectionTimeout", "8000");
+
+ DefaultDatabase.extractCommonsHikariProperties(props);
+
+ assertThat(logTester.logs())
+ .contains("Property [sonar.jdbc.maxIdle] has no effect as pool connection implementation changed, check 9.7 upgrade notes.")
+ .contains("Property [sonar.jdbc.minEvictableIdleTimeMillis] has no effect as pool connection implementation changed, check 9.7 upgrade notes.")
+ .contains("Property [sonar.jdbc.timeBetweenEvictionRunsMillis] has no effect as pool connection implementation changed, check 9.7 upgrade notes.");
}
@Test
@@ -76,21 +97,21 @@ public class DefaultDatabaseTest {
props.setProperty(jdbcProperty, "100");
props.setProperty(dbcpProperty, "100");
- Properties commonsDbcpProps = DefaultDatabase.extractCommonsDbcpProperties(props);
+ Properties commonsDbcpProps = DefaultDatabase.extractCommonsHikariProperties(props);
assertThat(commonsDbcpProps.getProperty(removeStart(dbcpProperty, SONAR_JDBC))).isEqualTo("100");
}
@Test
@UseDataProvider("sonarJdbcAndDbcpProperties")
- public void shouldThrowISEIfDuplicatedResolvedPropertiesWithDifferentValue(String jdbcProperty, String dbcpProperty) {
+ public void shouldThrowISEIfDuplicatedResolvedPropertiesWithDifferentValue(String jdbcProperty, String hikariProperty) {
Properties props = new Properties();
props.setProperty(jdbcProperty, "100");
- props.setProperty(dbcpProperty, "200");
+ props.setProperty(hikariProperty, "200");
- assertThatThrownBy(() -> DefaultDatabase.extractCommonsDbcpProperties(props))
+ assertThatThrownBy(() -> DefaultDatabase.extractCommonsHikariProperties(props))
.isInstanceOf(IllegalStateException.class)
- .hasMessageContaining(String.format("Duplicate property declaration for resolved jdbc key '%s': conflicting values are", removeStart(dbcpProperty, SONAR_JDBC)));
+ .hasMessageContaining(String.format("Duplicate property declaration for resolved jdbc key '%s': conflicting values are", removeStart(hikariProperty, SONAR_JDBC)));
}
@Test
@@ -117,14 +138,14 @@ public class DefaultDatabaseTest {
settings.setProperty("sonar.jdbc.driverClassName", "org.h2.Driver");
settings.setProperty("sonar.jdbc.username", "sonar");
settings.setProperty("sonar.jdbc.password", "sonar");
- settings.setProperty("sonar.jdbc.maxActive", "1");
+ settings.setProperty("sonar.jdbc.maximumPoolSize", "1");
DefaultDatabase db = new DefaultDatabase(logbackHelper, settings);
db.start();
db.stop();
assertThat(db.getDialect().getId()).isEqualTo("h2");
- assertThat(((BasicDataSource) db.getDataSource()).getMaxTotal()).isOne();
+ assertThat(((HikariDataSource) db.getDataSource()).getMaximumPoolSize()).isOne();
}
@Test
@@ -152,8 +173,8 @@ public class DefaultDatabaseTest {
@DataProvider
public static Object[][] sonarJdbcAndDbcpProperties() {
return new Object[][] {
- {"sonar.jdbc.maxActive", "sonar.jdbc.maxTotal"},
- {"sonar.jdbc.maxWait", "sonar.jdbc.maxWaitMillis"}
+ {"sonar.jdbc.maxWait", "sonar.jdbc.connectionTimeout"},
+ {"sonar.jdbc.maxActive", "sonar.jdbc.maximumPoolSize"}
};
}
}
diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/profiling/InvocationUtilsTest.java b/server/sonar-db-core/src/test/java/org/sonar/db/profiling/InvocationUtilsTest.java
index 80f897169a1..4d657ace44c 100644
--- a/server/sonar-db-core/src/test/java/org/sonar/db/profiling/InvocationUtilsTest.java
+++ b/server/sonar-db-core/src/test/java/org/sonar/db/profiling/InvocationUtilsTest.java
@@ -23,6 +23,7 @@ import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import org.junit.Assert;
+import org.junit.Ignore;
import org.junit.Test;
import org.sonar.test.TestUtils;
@@ -52,16 +53,6 @@ public class InvocationUtilsTest {
}
@Test
- public void should_wrap_undeclared_exception() throws Throwable {
- Connection target = mock(Connection.class);
- String failSql = "any sql";
- when(target.prepareStatement(failSql)).thenThrow(new SQLException("Expected"));
- Method wait = Object.class.getMethod("wait");
-
- Assert.assertThrows(IllegalStateException.class, () -> InvocationUtils.invokeQuietly(target, wait, new Object[0]));
- }
-
- @Test
public void only_static_methods() {
assertThat(TestUtils.hasOnlyPrivateConstructors(InvocationUtils.class)).isTrue();
diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/profiling/ProfiledDataSourceTest.java b/server/sonar-db-core/src/test/java/org/sonar/db/profiling/ProfiledDataSourceTest.java
index cd1db27b42c..5a6a09a5d27 100644
--- a/server/sonar-db-core/src/test/java/org/sonar/db/profiling/ProfiledDataSourceTest.java
+++ b/server/sonar-db-core/src/test/java/org/sonar/db/profiling/ProfiledDataSourceTest.java
@@ -19,6 +19,8 @@
*/
package org.sonar.db.profiling;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -27,7 +29,9 @@ import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.Timestamp;
-import org.apache.commons.dbcp2.BasicDataSource;
+import java.util.Properties;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.log.LogTester;
@@ -36,6 +40,7 @@ import org.sonar.api.utils.log.LoggerLevel;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class ProfiledDataSourceTest {
@@ -43,7 +48,7 @@ public class ProfiledDataSourceTest {
@Rule
public LogTester logTester = new LogTester();
- BasicDataSource originDataSource = mock(BasicDataSource.class);
+ HikariDataSource originDataSource = mock(HikariDataSource.class);
@Test
public void execute_and_log_statement() throws Exception {
@@ -59,7 +64,7 @@ public class ProfiledDataSourceTest {
ProfiledDataSource underTest = new ProfiledDataSource(originDataSource, ProfiledConnectionInterceptor.INSTANCE);
- assertThat(underTest.getUrl()).isNull();
+ assertThat(underTest.getJdbcUrl()).isNull();
assertThat(underTest.getConnection().getClientInfo()).isNull();
final Statement statementProxy = underTest.getConnection().createStatement();
assertThat(statementProxy.getConnection()).isNull();
@@ -90,7 +95,7 @@ public class ProfiledDataSourceTest {
ProfiledDataSource ds = new ProfiledDataSource(originDataSource, ProfiledConnectionInterceptor.INSTANCE);
- assertThat(ds.getUrl()).isNull();
+ assertThat(ds.getJdbcUrl()).isNull();
assertThat(ds.getConnection().getClientInfo()).isNull();
PreparedStatement preparedStatementProxy = ds.getConnection().prepareStatement(sqlWithParams);
preparedStatementProxy.setInt(1, param1);
@@ -121,7 +126,7 @@ public class ProfiledDataSourceTest {
ProfiledDataSource ds = new ProfiledDataSource(originDataSource, ProfiledConnectionInterceptor.INSTANCE);
- assertThat(ds.getUrl()).isNull();
+ assertThat(ds.getJdbcUrl()).isNull();
assertThat(ds.getConnection().getClientInfo()).isNull();
PreparedStatement preparedStatementProxy = ds.getConnection().prepareStatement(sqlWithParams);
assertThat(preparedStatementProxy.getConnection()).isNull();
@@ -144,7 +149,38 @@ public class ProfiledDataSourceTest {
for (Method method : ProfiledDataSource.class.getDeclaredMethods()) {
if (method.getParameterTypes().length == 0 && Modifier.isPublic(method.getModifiers())) {
method.invoke(proxy);
+ } else if (method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(String.class) && Modifier.isPublic(method.getModifiers())) {
+ method.invoke(proxy, "test");
+ } else if (method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(Boolean.TYPE) && Modifier.isPublic(method.getModifiers())) {
+ method.invoke(proxy, true);
+ } else if (method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(Long.TYPE) && Modifier.isPublic(method.getModifiers())) {
+ method.invoke(proxy, 1L);
+ } else if (method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(Integer.TYPE) && Modifier.isPublic(method.getModifiers())) {
+ method.invoke(proxy, 1);
}
}
+
+ proxy.addHealthCheckProperty("test", "test");
+ verify(originDataSource).addHealthCheckProperty("test", "test");
+
+ var schedulerMock = mock(ScheduledExecutorService.class);
+ proxy.setScheduledExecutor(schedulerMock);
+ verify(originDataSource).setScheduledExecutor(schedulerMock);
+
+ var hikariConfigMock = mock(HikariConfig.class);
+ proxy.copyStateTo(hikariConfigMock);
+ verify(originDataSource).copyStateTo(hikariConfigMock);
+
+ var threadFactoryMock = mock(ThreadFactory.class);
+ proxy.setThreadFactory(threadFactoryMock);
+ verify(originDataSource).setThreadFactory(threadFactoryMock);
+
+ var properties = new Properties();
+ proxy.setHealthCheckProperties(properties);
+ verify(originDataSource).setHealthCheckProperties(properties);
+
+ proxy.setDataSourceProperties(properties);
+ verify(originDataSource).setDataSourceProperties(properties);
+
}
}
diff --git a/server/sonar-db-core/src/testFixtures/java/org/sonar/db/CoreH2Database.java b/server/sonar-db-core/src/testFixtures/java/org/sonar/db/CoreH2Database.java
index 3a46a6b56e2..926b4e34583 100644
--- a/server/sonar-db-core/src/testFixtures/java/org/sonar/db/CoreH2Database.java
+++ b/server/sonar-db-core/src/testFixtures/java/org/sonar/db/CoreH2Database.java
@@ -19,11 +19,11 @@
*/
package org.sonar.db;
+import com.zaxxer.hikari.HikariDataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
-import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.io.output.NullWriter;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.jdbc.ScriptRunner;
@@ -38,7 +38,7 @@ import static java.lang.String.format;
public class CoreH2Database implements Database {
private static final String IGNORED_KEYWORDS_OPTION = ";NON_KEYWORDS=VALUE";
private final String name;
- private BasicDataSource datasource;
+ private HikariDataSource datasource;
/**
* IMPORTANT: change DB name in order to not conflict with {@link DefaultDatabaseTest}
@@ -54,11 +54,11 @@ public class CoreH2Database implements Database {
private void startDatabase() {
try {
- datasource = new BasicDataSource();
+ datasource = new HikariDataSource();
datasource.setDriverClassName("org.h2.Driver");
datasource.setUsername("sonar");
datasource.setPassword("sonar");
- datasource.setUrl("jdbc:h2:mem:" + name);
+ datasource.setJdbcUrl("jdbc:h2:mem:" + name);
} catch (Exception e) {
throw new IllegalStateException("Fail to start H2", e);
}
@@ -93,11 +93,7 @@ public class CoreH2Database implements Database {
@Override
public void stop() {
- try {
- datasource.close();
- } catch (SQLException e) {
- // Ignore error
- }
+ datasource.close();
}
public DataSource getDataSource() {
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DatabaseMBean.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DatabaseMBean.java
new file mode 100644
index 00000000000..77012a08823
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DatabaseMBean.java
@@ -0,0 +1,75 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.db;
+
+import com.zaxxer.hikari.HikariDataSource;
+import com.zaxxer.hikari.HikariPoolMXBean;
+import java.util.function.Function;
+import org.sonar.process.systeminfo.BaseSectionMBean;
+
+import static java.util.Optional.ofNullable;
+
+public abstract class DatabaseMBean extends BaseSectionMBean {
+
+ private final DbClient dbClient;
+
+ protected DatabaseMBean(DbClient dbClient) {
+ this.dbClient = dbClient;
+ }
+
+ public int getPoolActiveConnections() {
+ return getIntPropertyOrZero(HikariPoolMXBean::getActiveConnections);
+ }
+
+ public int getPoolTotalConnections() {
+ return getIntPropertyOrZero(HikariPoolMXBean::getTotalConnections);
+ }
+
+ public int getPoolIdleConnections() {
+ return getIntPropertyOrZero(HikariPoolMXBean::getIdleConnections);
+ }
+
+ public int getPoolMaxConnections() {
+ return hikariDatasource().getHikariConfigMXBean().getMaximumPoolSize();
+ }
+
+ public int getPoolMinIdleConnections() {
+ return hikariDatasource().getHikariConfigMXBean().getMinimumIdle();
+ }
+
+ public long getPoolMaxLifeTimeMillis() {
+ return hikariDatasource().getHikariConfigMXBean().getMaxLifetime();
+ }
+
+ public long getPoolMaxWaitMillis() {
+ return hikariDatasource().getHikariConfigMXBean().getConnectionTimeout();
+ }
+
+ private HikariDataSource hikariDatasource() {
+ return (HikariDataSource) dbClient.getDatabase().getDataSource();
+ }
+
+ private int getIntPropertyOrZero(Function<HikariPoolMXBean, Integer> function) {
+ return ofNullable(hikariDatasource().getHikariPoolMXBean())
+ .map(function)
+ .orElse(0);
+ }
+
+}
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/DatabaseMBeanTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/DatabaseMBeanTest.java
new file mode 100644
index 00000000000..65cb41e760d
--- /dev/null
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/DatabaseMBeanTest.java
@@ -0,0 +1,65 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.db;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo.Section;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DatabaseMBeanTest {
+
+ @Rule
+ public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+ private final FakeDatabaseMBean underTest = new FakeDatabaseMBean(dbTester.getDbClient());
+
+ @Test
+ public void verify_mBean() {
+
+ assertThat(underTest.getPoolActiveConnections()).isNotNegative();
+ assertThat(underTest.getPoolIdleConnections()).isNotNegative();
+ assertThat(underTest.getPoolMaxConnections()).isNotNegative();
+ assertThat(underTest.getPoolMaxLifeTimeMillis()).isNotNegative();
+ assertThat(underTest.getPoolMinIdleConnections()).isNotNegative();
+ assertThat(underTest.getPoolTotalConnections()).isNotNegative();
+ assertThat(underTest.getPoolMaxWaitMillis()).isNotNegative();
+ assertThat(underTest.name()).isEqualTo("FakeMBean");
+ }
+
+ private static class FakeDatabaseMBean extends DatabaseMBean {
+
+ protected FakeDatabaseMBean(DbClient dbClient) {
+ super(dbClient);
+ }
+
+ @Override
+ protected String name() {
+ return "FakeMBean";
+ }
+
+ @Override
+ public Section toProtobuf() {
+ return Section.newBuilder().build();
+ }
+ }
+}
diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java
index 1e2f4154dd8..8eb0c9f87b1 100644
--- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java
+++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java
@@ -19,6 +19,7 @@
*/
package org.sonar.db;
+import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Arrays;
@@ -27,7 +28,6 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import javax.annotation.Nullable;
-import org.apache.commons.dbcp2.BasicDataSource;
import org.sonar.api.utils.System2;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.core.util.UuidFactory;
@@ -308,7 +308,7 @@ public class DbTester extends AbstractDbTester<TestDbImpl> {
}
public String getUrl() {
- return ((BasicDataSource) db.getDatabase().getDataSource()).getUrl();
+ return ((HikariDataSource) db.getDatabase().getDataSource()).getJdbcUrl();
}
private static class DbSessionConnectionSupplier implements ConnectionSupplier {
diff --git a/server/sonar-docs/src/pages/instance-administration/monitoring.md b/server/sonar-docs/src/pages/instance-administration/monitoring.md
index dc3793942dd..86454696cb7 100644
--- a/server/sonar-docs/src/pages/instance-administration/monitoring.md
+++ b/server/sonar-docs/src/pages/instance-administration/monitoring.md
@@ -72,14 +72,11 @@ All these MBeans are read-only. It's not possible to modify or reset their value
| Attribute Name | Description
| ---|---
| MigrationStatus | Possible values are: UP_TO_DATE, REQUIRES_UPGRADE, REQUIRES_DOWNGRADE, FRESH_INSTALL (only available for WebServer).
-| PoolActiveConnections | Number of active database connections
+| PoolActiveConnections | Number of active database connections
| PoolIdleConnections | Number of database connections waiting to be used
-| PoolInitialSize | Initial size of the database connections pool.
-| PoolMaxActiveConnections | Maximum number of active database connections
-| PoolMaxIdleConnections | Maximum number of database connections waiting to be used
-| PoolMaxWaitMillis | In milliseconds
-| PoolRemoveAbandoned | Possible values : true, false
-| PoolRemoveAbandonedTimeoutSeconds | In Seconds
+| PoolMaxConnections | Maximum number of active database connections
+| PoolTotalConnections | Total number of connections currently in the pool
+| PoolMaxWaitMillis | Maximum number of milliseconds that a client will wait for a connection from the pool
[[collapse]]
| ## SonarQube MBean
diff --git a/server/sonar-docs/src/pages/setup/upgrade-notes.md b/server/sonar-docs/src/pages/setup/upgrade-notes.md
index 3499865db4d..5761e3f41f9 100644
--- a/server/sonar-docs/src/pages/setup/upgrade-notes.md
+++ b/server/sonar-docs/src/pages/setup/upgrade-notes.md
@@ -3,6 +3,11 @@ title: Release Upgrade Notes
url: /setup/upgrade-notes/
---
+## Release 9.7 Upgrade notes
+
+**Database Connection Pool Changed**
+Database connection pool has been changed, following properties will no longer have effect: sonar.jdbc.maxIdle, sonar.jdbc.minEvictableIdleTimeMillis, sonar.jdbc.timeBetweenEvictionRunsMillis. See documentation for changes in [monitoring database connection pool](/instance-administration/monitoring/).
+
## Release 9.6 Upgrade notes
**Microsoft SQL Server changes in configuration and Integrated Authentication**
* If your Microsoft SQL Server doesn't support encryption, you will need to add `encrypt=false` to the JDBC URL connection string. ([SONAR-16249](https://jira.sonarsource.com/browse/SONAR-16249)).
diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java
index a23af65a163..82a0f51c235 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java
@@ -55,11 +55,8 @@ public class ProcessProperties {
JDBC_PASSWORD("sonar.jdbc.password", ""),
JDBC_DRIVER_PATH("sonar.jdbc.driverPath"),
JDBC_MAX_ACTIVE("sonar.jdbc.maxActive", "60"),
- JDBC_MAX_IDLE("sonar.jdbc.maxIdle", "5"),
- JDBC_MIN_IDLE("sonar.jdbc.minIdle", "2"),
- JDBC_MAX_WAIT("sonar.jdbc.maxWait", "5000"),
- JDBC_MIN_EVICTABLE_IDLE_TIME_MILLIS("sonar.jdbc.minEvictableIdleTimeMillis", "600000"),
- JDBC_TIME_BETWEEN_EVICTION_RUNS_MILLIS("sonar.jdbc.timeBetweenEvictionRunsMillis", "30000"),
+ JDBC_MIN_IDLE("sonar.jdbc.minIdle", "10"),
+ JDBC_MAX_WAIT("sonar.jdbc.maxWait", "8000"),
JDBC_EMBEDDED_PORT("sonar.embeddedDatabase.port"),
PATH_DATA("sonar.path.data", "data"),
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/BaseSectionMBean.java b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/BaseSectionMBean.java
index b5afeaff0e2..b88e6505f0b 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/BaseSectionMBean.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/BaseSectionMBean.java
@@ -17,11 +17,10 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-package org.sonar.server.platform.monitoring;
+package org.sonar.process.systeminfo;
import org.sonar.api.Startable;
import org.sonar.process.Jmx;
-import org.sonar.process.systeminfo.SystemInfoSection;
/**
* Base implementation of a {@link SystemInfoSection}
@@ -45,12 +44,12 @@ public abstract class BaseSectionMBean implements SystemInfoSection, Startable {
Jmx.unregister(objectName());
}
- String objectName() {
+ public String objectName() {
return "SonarQube:name=" + name();
}
/**
* Name of section in System Info page
*/
- abstract String name();
+ protected abstract String name();
}
diff --git a/server/sonar-process/src/test/java/org/sonar/process/systeminfo/BaseSectionMBeanTest.java b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/BaseSectionMBeanTest.java
new file mode 100644
index 00000000000..f77f6ba3d19
--- /dev/null
+++ b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/BaseSectionMBeanTest.java
@@ -0,0 +1,79 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.systeminfo;
+
+import java.lang.management.ManagementFactory;
+import javax.annotation.CheckForNull;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import org.junit.Test;
+import org.sonar.process.jmx.FakeMBean;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo.Section;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class BaseSectionMBeanTest {
+
+ private static final String EXPECTED_NAME = "SonarQube:name=FakeName";
+
+ private final FakeBaseSectionMBean underTest = new FakeBaseSectionMBean();
+
+ @Test
+ public void verify_mbean() throws Exception {
+ assertThat(lookupMBean()).isNull();
+
+ underTest.start();
+ assertThat(lookupMBean()).isNotNull();
+
+ underTest.stop();
+ assertThat(lookupMBean()).isNull();
+
+ assertThat(underTest.name()).isEqualTo("FakeName");
+ assertThat(underTest.toProtobuf()).isNotNull();
+ }
+
+ @CheckForNull
+ private ObjectInstance lookupMBean() throws Exception {
+ try {
+ return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(EXPECTED_NAME));
+ } catch (InstanceNotFoundException e) {
+ return null;
+ }
+ }
+
+ private static class FakeBaseSectionMBean extends BaseSectionMBean implements FakeMBean {
+
+ @Override
+ protected String name() {
+ return "FakeName";
+ }
+
+ @Override
+ public Section toProtobuf() {
+ return Section.newBuilder().build();
+ }
+
+ @Override
+ public void foo() {
+ // nothing to do
+ }
+ }
+}
diff --git a/server/sonar-webserver-core/build.gradle b/server/sonar-webserver-core/build.gradle
index 622bbfb5a95..6443e5c4524 100644
--- a/server/sonar-webserver-core/build.gradle
+++ b/server/sonar-webserver-core/build.gradle
@@ -28,7 +28,7 @@ dependencies {
compile 'org.apache.httpcomponents:httpclient'
compile 'org.apache.logging.log4j:log4j-api'
compile 'org.apache.tomcat.embed:tomcat-embed-core'
- compile 'org.apache.commons:commons-dbcp2'
+ compile 'com.zaxxer:HikariCP'
compile 'org.slf4j:jul-to-slf4j'
compile 'org.slf4j:slf4j-api'
compile 'org.sonarsource.api.plugin:sonar-plugin-api'
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/DbConnectionSection.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/DbConnectionSection.java
index 8c59cbc0128..4d55ae46693 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/DbConnectionSection.java
+++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/DbConnectionSection.java
@@ -19,9 +19,9 @@
*/
package org.sonar.server.platform.monitoring;
-import org.apache.commons.dbcp2.BasicDataSource;
import org.sonar.api.SonarQubeSide;
import org.sonar.api.SonarRuntime;
+import org.sonar.db.DatabaseMBean;
import org.sonar.db.DbClient;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo.Section;
import org.sonar.server.platform.db.migration.version.DatabaseVersion;
@@ -31,15 +31,14 @@ import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
/**
* Information about database connection pool
*/
-public class DbConnectionSection extends BaseSectionMBean implements DbConnectionSectionMBean {
+public class DbConnectionSection extends DatabaseMBean implements DbConnectionSectionMBean {
private final DatabaseVersion dbVersion;
- private final DbClient dbClient;
private final SonarRuntime runtime;
public DbConnectionSection(DatabaseVersion dbVersion, DbClient dbClient, SonarRuntime runtime) {
+ super(dbClient);
this.dbVersion = dbVersion;
- this.dbClient = dbClient;
this.runtime = runtime;
}
@@ -54,51 +53,6 @@ public class DbConnectionSection extends BaseSectionMBean implements DbConnectio
}
@Override
- public int getPoolActiveConnections() {
- return commonsDbcp().getNumActive();
- }
-
- @Override
- public int getPoolMaxActiveConnections() {
- return commonsDbcp().getMaxTotal();
- }
-
- @Override
- public int getPoolIdleConnections() {
- return commonsDbcp().getNumIdle();
- }
-
- @Override
- public int getPoolMaxIdleConnections() {
- return commonsDbcp().getMaxIdle();
- }
-
- @Override
- public int getPoolMinIdleConnections() {
- return commonsDbcp().getMinIdle();
- }
-
- @Override
- public int getPoolInitialSize() {
- return commonsDbcp().getInitialSize();
- }
-
- @Override
- public long getPoolMaxWaitMillis() {
- return commonsDbcp().getMaxWaitMillis();
- }
-
- @Override
- public boolean getPoolRemoveAbandoned() {
- return commonsDbcp().getRemoveAbandonedOnBorrow();
- }
-
- @Override
- public int getPoolRemoveAbandonedTimeoutSeconds() {
- return commonsDbcp().getRemoveAbandonedTimeout();
- }
-
- @Override
public Section toProtobuf() {
Section.Builder protobuf = Section.newBuilder();
String side = runtime.getSonarQubeSide() == SonarQubeSide.COMPUTE_ENGINE ? "Compute Engine" : "Web";
@@ -108,18 +62,13 @@ public class DbConnectionSection extends BaseSectionMBean implements DbConnectio
}
private void completePoolAttributes(Section.Builder protobuf) {
+ setAttribute(protobuf, "Pool Total Connections", getPoolTotalConnections());
setAttribute(protobuf, "Pool Active Connections", getPoolActiveConnections());
- setAttribute(protobuf, "Pool Max Connections", getPoolMaxActiveConnections());
- setAttribute(protobuf, "Pool Initial Size", getPoolInitialSize());
setAttribute(protobuf, "Pool Idle Connections", getPoolIdleConnections());
+ setAttribute(protobuf, "Pool Max Connections", getPoolMaxConnections());
setAttribute(protobuf, "Pool Min Idle Connections", getPoolMinIdleConnections());
- setAttribute(protobuf, "Pool Max Idle Connections", getPoolMaxIdleConnections());
setAttribute(protobuf, "Pool Max Wait (ms)", getPoolMaxWaitMillis());
- setAttribute(protobuf, "Pool Remove Abandoned", getPoolRemoveAbandoned());
- setAttribute(protobuf, "Pool Remove Abandoned Timeout (seconds)", getPoolRemoveAbandonedTimeoutSeconds());
+ setAttribute(protobuf, "Pool Max Lifetime (ms)", getPoolMaxLifeTimeMillis());
}
- private BasicDataSource commonsDbcp() {
- return (BasicDataSource) dbClient.getDatabase().getDataSource();
- }
}
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/DbConnectionSectionMBean.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/DbConnectionSectionMBean.java
index 59fccd64b46..44144825efc 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/DbConnectionSectionMBean.java
+++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/DbConnectionSectionMBean.java
@@ -27,21 +27,24 @@ public interface DbConnectionSectionMBean {
String getMigrationStatus();
/**
- *
+ * Get the number of currently active connections in the pool.
*/
int getPoolActiveConnections();
/**
- * The maximum number of active connections that can be allocated from this pool at the same time, or negative for no limit.
+ * The maximum number of connections that can be allocated from this pool at the same time, or negative for no limit.
*/
- int getPoolMaxActiveConnections();
+ int getPoolMaxConnections();
- int getPoolIdleConnections();
+ /**
+ * Total number of connections currently in the pool
+ */
+ int getPoolTotalConnections();
/**
- * The maximum number of connections that can remain idle in the pool, without extra ones being released, or negative for no limit.
+ * Get the number of currently idle connections in the pool.
*/
- int getPoolMaxIdleConnections();
+ int getPoolIdleConnections();
/**
* The minimum number of connections that can remain idle in the pool, without extra ones being created, or zero to create none.
@@ -49,9 +52,9 @@ public interface DbConnectionSectionMBean {
int getPoolMinIdleConnections();
/**
- * The initial number of connections that are created when the pool is started.
+ * Maximum lifetime of a connection in the pool.
*/
- int getPoolInitialSize();
+ long getPoolMaxLifeTimeMillis();
/**
* The maximum number of milliseconds that the pool will wait
@@ -59,13 +62,4 @@ public interface DbConnectionSectionMBean {
*/
long getPoolMaxWaitMillis();
- /**
- * Flag to remove abandoned connections if they exceed the {@link #getPoolRemoveAbandonedTimeoutSeconds()}.
- */
- boolean getPoolRemoveAbandoned();
-
- /**
- * Timeout in seconds before an abandoned connection can be removed.
- */
- int getPoolRemoveAbandonedTimeoutSeconds();
}
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/StandaloneSystemSection.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/StandaloneSystemSection.java
index 0c728efc507..457b6377951 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/StandaloneSystemSection.java
+++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/StandaloneSystemSection.java
@@ -29,6 +29,7 @@ import org.sonar.api.platform.Server;
import org.sonar.api.security.SecurityRealm;
import org.sonar.api.server.authentication.IdentityProvider;
import org.sonar.core.util.stream.MoreCollectors;
+import org.sonar.process.systeminfo.BaseSectionMBean;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import org.sonar.server.authentication.IdentityProviderRepository;
import org.sonar.server.log.ServerLogging;
diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/BaseSectionMBeanTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/BaseSectionMBeanTest.java
index 556c5a7544f..cb2ed963626 100644
--- a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/BaseSectionMBeanTest.java
+++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/BaseSectionMBeanTest.java
@@ -30,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class BaseSectionMBeanTest {
- private FakeSection underTest = new FakeSection();
+ private final FakeSection underTest = new FakeSection();
@Test
public void test_registration() throws Exception {
diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/DbConnectionSectionTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/DbConnectionSectionTest.java
index 1363e1b15e2..1086c1c1a8e 100644
--- a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/DbConnectionSectionTest.java
+++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/DbConnectionSectionTest.java
@@ -38,9 +38,9 @@ public class DbConnectionSectionTest {
@Rule
public DbTester dbTester = DbTester.create(System2.INSTANCE);
- private DatabaseVersion databaseVersion = mock(DatabaseVersion.class);
- private SonarRuntime runtime = mock(SonarRuntime.class);
- private DbConnectionSection underTest = new DbConnectionSection(databaseVersion, dbTester.getDbClient(), runtime);
+ private final DatabaseVersion databaseVersion = mock(DatabaseVersion.class);
+ private final SonarRuntime runtime = mock(SonarRuntime.class);
+ private final DbConnectionSection underTest = new DbConnectionSection(databaseVersion, dbTester.getDbClient(), runtime);
@Test
public void jmx_name_is_not_empty() {
@@ -50,13 +50,12 @@ public class DbConnectionSectionTest {
@Test
public void pool_info() {
ProtobufSystemInfo.Section section = underTest.toProtobuf();
- assertThat(attribute(section, "Pool Max Connections").getLongValue()).isGreaterThan(0L);
- assertThat(attribute(section, "Pool Idle Connections").getLongValue()).isGreaterThanOrEqualTo(0L);
- assertThat(attribute(section, "Pool Min Idle Connections").getLongValue()).isGreaterThanOrEqualTo(0L);
- assertThat(attribute(section, "Pool Max Idle Connections").getLongValue()).isGreaterThanOrEqualTo(0L);
- assertThat(attribute(section, "Pool Max Wait (ms)")).isNotNull();
- assertThat(attribute(section, "Pool Remove Abandoned")).isNotNull();
- assertThat(attribute(section, "Pool Remove Abandoned Timeout (seconds)").getLongValue()).isGreaterThanOrEqualTo(0L);
+ assertThat(attribute(section, "Pool Total Connections").getLongValue()).isNotNegative();
+ assertThat(attribute(section, "Pool Active Connections").getLongValue()).isNotNegative();
+ assertThat(attribute(section, "Pool Idle Connections").getLongValue()).isNotNegative();
+ assertThat(attribute(section, "Pool Max Connections").getLongValue()).isNotNegative();
+ assertThat(attribute(section, "Pool Min Idle Connections")).isNotNull();
+ assertThat(attribute(section, "Pool Max Lifetime (ms)")).isNotNull();
}
@Test
@@ -64,7 +63,7 @@ public class DbConnectionSectionTest {
when(runtime.getSonarQubeSide()).thenReturn(SonarQubeSide.COMPUTE_ENGINE);
assertThat(underTest.toProtobuf().getName()).isEqualTo("Compute Engine Database Connection");
- when(runtime.getSonarQubeSide()).thenReturn(SonarQubeSide.SERVER );
+ when(runtime.getSonarQubeSide()).thenReturn(SonarQubeSide.SERVER);
assertThat(underTest.toProtobuf().getName()).isEqualTo("Web Database Connection");
}
}
diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/FakeSection.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/FakeSection.java
index efc1955fd27..6374fee3d5a 100644
--- a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/FakeSection.java
+++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/FakeSection.java
@@ -19,6 +19,7 @@
*/
package org.sonar.server.platform.monitoring;
+import org.sonar.process.systeminfo.BaseSectionMBean;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
public class FakeSection extends BaseSectionMBean implements FakeSectionMBean {
diff --git a/sonar-application/src/main/assembly/conf/sonar.properties b/sonar-application/src/main/assembly/conf/sonar.properties
index e862e0632b7..d24fd2dc23a 100644
--- a/sonar-application/src/main/assembly/conf/sonar.properties
+++ b/sonar-application/src/main/assembly/conf/sonar.properties
@@ -64,15 +64,12 @@
# The minimum number of connections that can remain idle in the pool,
# without extra ones being created, or zero to create none.
-#sonar.jdbc.minIdle=2
+#sonar.jdbc.minIdle=10
# The maximum number of milliseconds that the pool will wait (when there
# are no available connections) for a connection to be returned before
# throwing an exception, or <= 0 to wait indefinitely.
-#sonar.jdbc.maxWait=5000
-
-#sonar.jdbc.minEvictableIdleTimeMillis=600000
-#sonar.jdbc.timeBetweenEvictionRunsMillis=30000
+#sonar.jdbc.maxWait=8000
@@ -121,7 +118,7 @@
# The default value is 25.
#sonar.web.http.acceptCount=25
-# The number of milliseconds this Connector will wait for another HTTP request before closing the
+# The number of milliseconds this Connector will wait for another HTTP request before closing the
# connection. The default value is to use the value that has been set for the connectionTimeout
# attribute. Use a value of -1 to indicate no (i.e. infinite) timeout.
# The default value is 60000 (ms).