package org.mariadb.jdbc;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import javax.sql.DataSource;
import java.sql.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ConnectionPoolTest extends BaseTest {
/**
* Tables initialisation.
*
* @throws SQLException exception
*/
@BeforeClass()
public static void initClass() throws SQLException {
for (int i = 0; i < 50; i++) {
createTable("test_pool_batch" + i, "id int not null primary key auto_increment, test varchar(10)");
}
}
@Test
public void testBasicPool() throws SQLException {
final HikariDataSource ds = new HikariDataSource();
ds.setMaximumPoolSize(20);
ds.setDriverClassName("org.mariadb.jdbc.Driver");
ds.setJdbcUrl(connU);
ds.addDataSourceProperty("user", username);
if (password != null ) ds.addDataSourceProperty("password", password);
ds.setAutoCommit(false);
validateDataSource(ds);
}
@Test
public void testPoolHikariCpWithConfig() throws SQLException {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(connU);
config.setUsername(username);
if (password != null ) config.setPassword(password);
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
try (HikariDataSource ds = new HikariDataSource(config)) {
validateDataSource(ds);
}
}
@Test
public void testPoolEffectiveness() throws Exception {
Assume.assumeFalse(sharedIsRewrite()
|| (!sharedOptions().useBatchMultiSend && !sharedOptions().useServerPrepStmts));
HikariConfig config = new HikariConfig();
config.setJdbcUrl(connU);
config.setUsername(username);
if (password != null ) config.addDataSourceProperty("password", password);
try (HikariDataSource ds = new HikariDataSource(config)) {
ds.setAutoCommit(true);
//force pool loading
forcePoolLoading(ds);
long monoConnectionExecutionTime = insert500WithOneConnection(ds);
for (int j = 0; j < 50; j++) {
sharedConnection.createStatement().execute("TRUNCATE test_pool_batch" + j);
}
long poolExecutionTime = insert500WithPool(ds);
System.out.println("mono connection execution time : " + monoConnectionExecutionTime);
System.out.println("pool execution time : " + poolExecutionTime);
if (!sharedIsRewrite() && !sharedOptions().allowMultiQueries) {
Assert.assertTrue(monoConnectionExecutionTime > poolExecutionTime);
}
}
}
private void forcePoolLoading(DataSource ds) {
ExecutorService exec = Executors.newFixedThreadPool(50);
//check blacklist shared
//force pool loading
for (int j = 0; j < 100; j++) {
exec.execute(new ForceLoadPoolThread(ds));
}
exec.shutdown();
try {
exec.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
//eat exception
}
exec = Executors.newFixedThreadPool(50);
}
private void validateDataSource(DataSource ds) throws SQLException {
try (Connection connection = ds.getConnection()) {
try (Statement statement = connection.createStatement()) {
try (ResultSet rs = statement.executeQuery("SELECT 1")) {
Assert.assertTrue(rs.next());
Assert.assertEquals(1, rs.getInt(1));
}
}
}
}
private long insert500WithOneConnection(DataSource ds) throws SQLException {
long startTime = System.currentTimeMillis();
try (Connection connection = ds.getConnection()) {
for (int j = 0; j < 50; j++) {
try {
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO test_pool_batch" + j + "(test) VALUES (?)");
for (int i = 1; i < 30; i++) {
preparedStatement.setString(1, i + "");
preparedStatement.addBatch();
}
preparedStatement.executeBatch();
} catch (SQLException e) {
Assert.fail("ERROR insert : " + e.getMessage());
}
}
}
return System.currentTimeMillis() - startTime;
}
private long insert500WithPool(DataSource ds) throws SQLException {
ExecutorService exec = Executors.newFixedThreadPool(50);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 50; i++) {
exec.execute(new InsertThread(i, 30, ds));
}
exec.shutdown();
try {
exec.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
//eat exception
}
return System.currentTimeMillis() - startTime;
}
private class ForceLoadPoolThread implements Runnable {
private DataSource dataSource;
public ForceLoadPoolThread(DataSource dataSource) {
this.dataSource = dataSource;
}
public void run() {
try (Connection connection = dataSource.getConnection()) {
connection.createStatement().execute("SELECT 1");
} catch (SQLException e) {
Assert.fail("ERROR insert : " + e.getMessage());
}
}
}
private class InsertThread implements Runnable {
private DataSource dataSource;
private int insertNumber;
private int tableNumber;
public InsertThread(int tableNumber, int insertNumber, DataSource dataSource) {
this.insertNumber = insertNumber;
this.tableNumber = tableNumber;
this.dataSource = dataSource;
}
public void run() {
try (Connection connection = dataSource.getConnection()) {
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO test_pool_batch"
+ tableNumber + "(test) VALUES (?)");
for (int i = 1; i < insertNumber; i++) {
preparedStatement.setString(1, i + "");
preparedStatement.addBatch();
}
preparedStatement.executeBatch();
} catch (SQLException e) {
Assert.fail("ERROR insert : " + e.getMessage());
}
}
}
}