package com.taobao.tddl.matrix.jdbc; import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javax.sql.DataSource; import com.taobao.tddl.common.TddlConstants; import com.taobao.tddl.common.exception.TddlException; import com.taobao.tddl.common.exception.TddlRuntimeException; import com.taobao.tddl.common.model.ExtraCmd; import com.taobao.tddl.common.model.lifecycle.AbstractLifecycle; import com.taobao.tddl.common.utils.GeneralUtil; import com.taobao.tddl.common.utils.thread.NamedThreadFactory; import com.taobao.tddl.executor.MatrixExecutor; import com.taobao.tddl.matrix.config.MatrixConfigHolder; /** * matrix的jdbc datasource实现 * * @author mengshi.sunmengshi 2013-11-22 下午3:26:14 * @since 5.0.0 */ public class TDataSource extends AbstractLifecycle implements DataSource { private String ruleFilePath = null; private String machineTopologyFile = null; private String schemaFile = null; private String appName = null; private boolean dynamicRule = true; // 是否使用动态规则 private MatrixExecutor executor = null; private Map<String, Object> connectionProperties = new HashMap(2); private MatrixConfigHolder configHolder; /** * 用于并行查询的线程池 */ private ExecutorService globalExecutorService = null; private LinkedBlockingQueue<ExecutorService> executorServiceQueue = null; @Override public void doInit() throws TddlException { this.executor = new MatrixExecutor(); executor.init(); MatrixConfigHolder configHolder = new MatrixConfigHolder(); configHolder.setAppName(appName); configHolder.setTopologyFilePath(this.machineTopologyFile); configHolder.setSchemaFilePath(this.schemaFile); configHolder.setRuleFilePath(this.ruleFilePath); configHolder.setConnectionProperties(this.connectionProperties); configHolder.setDynamicRule(dynamicRule); configHolder.init(); this.configHolder = configHolder; /** * 如果不为每个连接都初始化,则为整个ds初始化一个线程池 */ boolean everyConnectionPool = GeneralUtil.getExtraCmdBoolean(this.getConnectionProperties(), ExtraCmd.INIT_CONCURRENT_POOL_EVERY_CONNECTION, true); if (everyConnectionPool) { executorServiceQueue = new LinkedBlockingQueue<ExecutorService>(); } else { // 全局共享线程池 int poolSize; Object poolSizeObj = GeneralUtil.getExtraCmdString(this.getConnectionProperties(), ExtraCmd.CONCURRENT_THREAD_SIZE); if (poolSizeObj == null) { throw new TddlRuntimeException("如果线程池为整个datasource共用,请使用CONCURRENT_THREAD_SIZE指定线程池大小"); } poolSize = Integer.valueOf(poolSizeObj.toString()); // 默认queue队列为poolSize的两倍,超过queue大小后使用当前线程 globalExecutorService = createThreadPool(poolSize); } } @Override public Connection getConnection() throws SQLException { try { return new TConnection(this); } catch (Exception e) { throw new SQLException(e); } } public ExecutorService borrowExecutorService() { if (globalExecutorService != null) { return globalExecutorService; } else { ExecutorService executor = executorServiceQueue.poll(); if (executor == null) { Object poolSizeObj = GeneralUtil.getExtraCmdString(this.getConnectionProperties(), ExtraCmd.CONCURRENT_THREAD_SIZE); int poolSize = 0; if (poolSizeObj != null) { poolSize = Integer.valueOf(poolSizeObj.toString()); } else { poolSize = TddlConstants.DEFAULT_CONCURRENT_THREAD_SIZE; } executor = createThreadPool(poolSize); } if (executor.isShutdown()) { return borrowExecutorService(); } else { return executor; } } } public void releaseExecutorService(ExecutorService executor) { if (executor != null && executor != globalExecutorService) { executorServiceQueue.offer(executor);// 放回队列中 } } private ThreadPoolExecutor createThreadPool(int poolSize) { return new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue(poolSize * 2), new NamedThreadFactory("tddl_concurrent_query_executor"), new ThreadPoolExecutor.CallerRunsPolicy()); } @Override public Connection getConnection(String username, String password) throws SQLException { return this.getConnection(); } @Override public void doDestory() throws TddlException { if (globalExecutorService != null) { globalExecutorService.shutdownNow(); } if (executorServiceQueue != null) { for (ExecutorService executor : executorServiceQueue) { executor.shutdownNow(); } executorServiceQueue.clear(); } if (configHolder != null) { configHolder.destory(); } if (executor.isInited()) { executor.destory(); } } public String getRuleFile() { return ruleFilePath; } public void setRuleFile(String ruleFilePath) { this.ruleFilePath = ruleFilePath; } public String getMachineTopologyFile() { return machineTopologyFile; } public void setTopologyFile(String machineTopologyFile) { this.machineTopologyFile = machineTopologyFile; } public String getSchemaFile() { return schemaFile; } public void setSchemaFile(String schemaFile) { this.schemaFile = schemaFile; } public MatrixExecutor getExecutor() { return this.executor; } public Map<String, Object> getConnectionProperties() { return this.connectionProperties; } public void setConnectionProperties(Map<String, Object> cp) { this.connectionProperties = cp; } public void setAppName(String appName) { this.appName = appName; } public MatrixConfigHolder getConfigHolder() { return this.configHolder; } public void setDynamicRule(boolean dynamicRule) { this.dynamicRule = dynamicRule; } @Override public PrintWriter getLogWriter() throws SQLException { throw new UnsupportedOperationException("getLogWriter"); } @Override public int getLoginTimeout() throws SQLException { throw new UnsupportedOperationException("getLoginTimeout"); } @Override public void setLogWriter(PrintWriter arg0) throws SQLException { throw new UnsupportedOperationException("setLogWriter"); } @Override public void setLoginTimeout(int arg0) throws SQLException { throw new UnsupportedOperationException("setLoginTimeout"); } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return this.getClass().isAssignableFrom(iface); } @Override public <T> T unwrap(Class<T> iface) throws SQLException { try { return (T) this; } catch (Exception e) { throw new SQLException(e); } } }