@@ -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') { |
@@ -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') |
@@ -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(); | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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' |
@@ -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); |
@@ -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; | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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))); | |||
} | |||
@@ -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 | |||
@@ -252,16 +262,6 @@ public class ProfiledDataSource extends BasicDataSource { | |||
delegate.setPassword(password); | |||
} | |||
@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(); | |||
} | |||
} |
@@ -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"} | |||
}; | |||
} | |||
} |
@@ -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; | |||
@@ -51,16 +52,6 @@ public class InvocationUtilsTest { | |||
Assert.assertThrows(SQLException.class, () -> InvocationUtils.invokeQuietly(target, prepareStatement, new Object[] {failSql})); | |||
} | |||
@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(); |
@@ -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); | |||
} | |||
} |
@@ -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() { |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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 { |
@@ -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 |
@@ -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)). |
@@ -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"), |
@@ -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(); | |||
} |
@@ -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 | |||
} | |||
} | |||
} |
@@ -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' |
@@ -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; | |||
} | |||
@@ -53,51 +52,6 @@ public class DbConnectionSection extends BaseSectionMBean implements DbConnectio | |||
return dbVersion.getStatus().name(); | |||
} | |||
@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(); | |||
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} |
@@ -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; |
@@ -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 { |
@@ -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"); | |||
} | |||
} |
@@ -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 { |
@@ -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). |