io.datarouter.client.mysql.connection.MysqlConnectionPoolHolder Maven / Gradle / Ivy
/*
* Copyright © 2009 HotPads ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.datarouter.client.mysql.connection;
import java.beans.PropertyVetoException;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.DataSources;
import com.mysql.cj.log.Slf4JLogger;
import io.datarouter.client.mysql.ddl.domain.MysqlCharacterSet;
import io.datarouter.client.mysql.ddl.domain.MysqlCollation;
import io.datarouter.client.mysql.factory.MysqlOptions;
import io.datarouter.scanner.Scanner;
import io.datarouter.storage.client.ClientId;
import io.datarouter.util.string.StringTool;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import net.sf.log4jdbc.DriverSpy;
@Singleton
public class MysqlConnectionPoolHolder{
private static final Logger logger = LoggerFactory.getLogger(MysqlConnectionPoolHolder.class);
public static final String UTF8MB4_CHARSET = "utf8mb4";
private static final String UTF8MB4_COLLATION = UTF8MB4_CHARSET + "_bin";
private static final String UTF8 = StandardCharsets.UTF_8.name();
public static final MysqlCharacterSet CHARACTER_SET_CONNECTION = MysqlCharacterSet.valueOf(UTF8MB4_CHARSET);
public static final MysqlCollation COLLATION_CONNECTION = MysqlCollation.valueOf(UTF8MB4_COLLATION);
public static final String CLIENT_NAME_KEY = "clientName=";
static{
System.setProperty("log4jdbc.dump.sql.maxlinelength", "0");
System.setProperty("log4jdbc.trim.sql.extrablanklines", "false");
System.setProperty("log4jdbc.auto.load.popular.drivers", "false");
}
@Inject
private MysqlOptions mysqlOptions;
private final Map connectionPools = new ConcurrentHashMap<>();
public void createConnectionPool(ClientId clientId){
createConnectionPool(clientId, mysqlOptions.url(clientId), mysqlOptions.user(clientId.getName(),
"root"), mysqlOptions.password(clientId.getName(), ""));
}
public void createConnectionPool(ClientId clientId, String url, String userId, String password){
MysqlConnectionPool connectionPool = new MysqlConnectionPool(clientId, url, userId, password);
try{
connectionPool.checkOut().close();
}catch(SQLException e){
throw new RuntimeException(e);
}
connectionPools.put(clientId, connectionPool);
}
public MysqlConnectionPool getConnectionPool(ClientId clientId){
return connectionPools.get(clientId);
}
public class MysqlConnectionPool{
private final ComboPooledDataSource pool;
private final String schemaName;
private MysqlConnectionPool(ClientId clientId, String url, String user, String password){
Integer minPoolSize = mysqlOptions.minPoolSize(clientId.getName(), 3);
Integer maxPoolSize = mysqlOptions.maxPoolSize(clientId.getName(), 50);
Integer acquireIncrement = mysqlOptions.acquireIncrement(clientId.getName(), 1);
Integer numHelperThreads = mysqlOptions.numHelperThreads(clientId.getName(), 10);
Integer maxIdleTime = mysqlOptions.maxIdleTime(clientId.getName(), 300);
Integer idleConnectionTestPeriod = mysqlOptions.idleConnectionTestPeriod(clientId.getName(), 30);
Boolean logging = mysqlOptions.logging(clientId.getName(), false);
List additionalUrlParams = mysqlOptions.urlParams(clientId.getName());
this.schemaName = StringTool.getStringAfterLastOccurrence('/', url);
// configurable props
this.pool = new ComboPooledDataSource();
this.pool.setInitialPoolSize(minPoolSize);
this.pool.setMinPoolSize(minPoolSize);
this.pool.setMaxPoolSize(maxPoolSize);
List standardUrlParams = new ArrayList<>();
// avoid extra RPC on readOnly connections:
// http://dev.mysql.com/doc/relnotes/connector-j/en/news-5-1-23.html
standardUrlParams.add("useLocalSessionState=true");
standardUrlParams.add("zeroDateTimeBehavior=convertToNull");
standardUrlParams.add("connectionCollation=" + UTF8MB4_COLLATION);
standardUrlParams.add("characterEncoding=" + UTF8);
standardUrlParams.add("logger=" + Slf4JLogger.class.getName());
standardUrlParams.add("enabledTLSProtocols=TLSv1.2");
standardUrlParams.add(CLIENT_NAME_KEY + clientId.getName());
List allUrlParams = Scanner.of(standardUrlParams, additionalUrlParams).concat(Scanner::of).list();
String urlWithParams = url + "?" + String.join("&", allUrlParams);
try{
String jdbcUrl;
if(logging){
// log4jdbc - see http://code.google.com/p/log4jdbc/
this.pool.setDriverClass(DriverSpy.class.getName());
jdbcUrl = "jdbc:log4jdbc:mysql://" + urlWithParams;
}else{
jdbcUrl = "jdbc:mysql://" + urlWithParams;
}
this.pool.setJdbcUrl(jdbcUrl);
}catch(PropertyVetoException pve){
throw new RuntimeException(pve);
}
this.pool.setUser(user);
this.pool.setPassword(password);
this.pool.setAcquireIncrement(acquireIncrement);
this.pool.setNumHelperThreads(numHelperThreads);
this.pool.setAcquireRetryAttempts(30);
this.pool.setAcquireRetryDelay(500);
this.pool.setIdleConnectionTestPeriod(idleConnectionTestPeriod);
this.pool.setMaxIdleTime(maxIdleTime); // seconds
Class> connectionCustomizer;
if(clientId.getWritable()){
connectionCustomizer = Utf8mb4ConnectionCustomizer.class;
}else{
connectionCustomizer = ReadOnlyUtf8mb4ConnectionCustomizer.class;
}
this.pool.setConnectionCustomizerClassName(connectionCustomizer.getName());
}
public Connection checkOut() throws SQLException{
try{
return pool.getConnection();
}catch(SQLException e){
logger.warn("could not connect jdbcUrl={} error={}", pool.getJdbcUrl(), e);
throw e;
}
}
public void shutdown(){
try{
logger.warn("destroying {} {}", schemaName, pool);
DataSources.destroy(pool);
}catch(SQLException e){
logger.error("", e);
}
}
public String getSchemaName(){
return schemaName;
}
@Override
public String toString(){
return schemaName + "@" + pool.getJdbcUrl();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy