package com.taobao.tddl.group.config; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javax.sql.DataSource; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject; import com.taobao.tddl.atom.TAtomDataSource; import com.taobao.tddl.atom.TAtomDbStatusEnum; import com.taobao.tddl.atom.TAtomDsStandard; import com.taobao.tddl.common.model.DBType; import com.taobao.tddl.common.model.DataSourceType; import com.taobao.tddl.common.utils.TStringUtil; import com.taobao.tddl.common.utils.thread.NamedThreadFactory; import com.taobao.tddl.config.ConfigDataHandler; import com.taobao.tddl.config.ConfigDataHandlerFactory; import com.taobao.tddl.config.ConfigDataListener; import com.taobao.tddl.config.impl.ConfigDataHandlerCity; import com.taobao.tddl.group.dbselector.AbstractDBSelector; import com.taobao.tddl.group.dbselector.DBSelector; import com.taobao.tddl.group.dbselector.EquityDbManager; import com.taobao.tddl.group.dbselector.OneDBSelector; import com.taobao.tddl.group.dbselector.PriorityDbGroupSelector; import com.taobao.tddl.group.dbselector.RuntimeWritableAtomDBSelector; import com.taobao.tddl.group.exception.ConfigException; import com.taobao.tddl.group.exception.TAtomDataSourceException; import com.taobao.tddl.group.jdbc.DataSourceFetcher; import com.taobao.tddl.group.jdbc.DataSourceWrapper; import com.taobao.tddl.group.jdbc.TGroupDataSource; import com.taobao.tddl.group.listener.DataSourceChangeListener; import com.taobao.tddl.common.utils.logger.Logger; import com.taobao.tddl.common.utils.logger.LoggerFactory; /** * 一个ConfigManager对应一个TGroupDataSource, * 主要用于将根据Group的dataID取得的对应配置字符串信(比如db0:rwp1q1i0, db1:rwp0q0i1), * 转化为真正的Group层的配置体系结构:一个Group层挂着两个Atom db0 与 db1 , 则我们使用一个 Map<String, * DataSourceWrapper> 来表示 其中的String 为每个Atom DS 的dbKey ,DataSourceWrapper * 为经过封装的TAtomDataSource * ---这里需要解释一下,为什么不直接使用AtomDataSource?因为每个AtomDataSource还有相应的权重和优先级信息 因此,需要***方法 * 其中,配置的每一个Atom DataSource也只是用Atom * 的dbKey表示,因此,我们还需要根据此dbKey取得Atom的配置信息,并且将它封装成一个AtomDataSource对象。 因此需要***方法 * 有了这个map能根据dbKey迅速的找到对应的Datasource也是不够的,我们的Group层应该是对应用透明的, * 因此,当我们的读写请求进来时,Group层应该能够根据配置的权重和优先级,自动的选择一个合适的DB上进行读写, * 所以,我们还需要将配置信息生成一个DBSelector来自动的完成根据权重、优先级选择合适的目标库 因此,需要***方法 * * @author yangzhu * @author linxuan refactor */ public class GroupConfigManager { private static final Logger logger = LoggerFactory.getLogger(GroupConfigManager.class); private final ConfigDataListener configReceiver; // //动态接收Diamond推送过来的信息 private ConfigDataHandlerFactory configFactory; private ConfigDataHandler globalHandler; // add by junyu private final ConfigDataListener extraGroupConfigReceiver; private ConfigDataHandler extraHandler; private ConfigDataHandlerFactory extraFactory; private final TGroupDataSource tGroupDataSource; private boolean createTAtomDataSource = true; private Map<String/* Atom dbIndex */, DataSourceWrapper/* Wrapper过的Atom DS */> dataSourceWrapperMap = new HashMap<String, DataSourceWrapper>(); private volatile GroupExtraConfig groupExtraConfig = new GroupExtraConfig(); public GroupConfigManager(TGroupDataSource tGroupDataSource){ this.tGroupDataSource = tGroupDataSource; this.configReceiver = new ConfigReceiver(); this.extraGroupConfigReceiver = new ExtraGroupConfigReceiver(); ((ConfigReceiver) this.configReceiver).setConfigManager(this); } /** * 从Diamond配置中心提取信息,构造TAtomDataSource、构造有优先级信息的读写DBSelector ---add by * mazhidan.pt */ public void init() { // 警告: 不要在构造DefaultDiamondManager时就注册ManagerListener(比如:configReceiver) // 也就是说,不要这样用: new DefaultDiamondManager(dbGroupKey, configReceiver), // 而是要设成null,等第一次取得信息并解析完成后再注册,这样可以不用同步,避免任何与并发相关的问题, // 因为有可能在第一次刚取回信息后,Diamond配置中心那边马上修改了记录,导致ManagerListener这个线程立刻收到信息, // 造成初始化线程和ManagerListener线程同时解析信息。 // 目前针对parse方法会做同步处理,避免并发操作. 同时针对diamond相同配置的进行cache,避免重复相同内容的通知 configFactory = ConfigDataHandlerCity.getFactory(tGroupDataSource.getAppName(), tGroupDataSource.getUnitName()); globalHandler = configFactory.getConfigDataHandler(tGroupDataSource.getFullDbGroupKey(), configReceiver); String dsWeightCommaStr = globalHandler.getData(tGroupDataSource.getConfigReceiveTimeout(), ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY); // extra config extraFactory = ConfigDataHandlerCity.getFactory(tGroupDataSource.getAppName(), tGroupDataSource.getUnitName()); extraHandler = extraFactory.getConfigDataHandler(tGroupDataSource.getDbGroupExtraConfigKey(), extraGroupConfigReceiver); String extraConfig = extraHandler.getNullableData(tGroupDataSource.getConfigReceiveTimeout(), ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY); if (extraConfig != null) { parseExtraConfig(extraConfig); } parse(dsWeightCommaStr); // 已经使用过的配置移除 // destoryConfigHoderFactory(); } /** * 根据普通的DataSource构造读写DBSelector */ public void init(List<DataSourceWrapper> dataSourceWrappers) { if ((dataSourceWrappers == null) || dataSourceWrappers.size() < 1) { throw new ConfigException("dataSourceWrappers不能为null且长度要大于0"); } createTAtomDataSource = false; // update(createDBSelectors2(dataSourceWrappers)); resetByDataSourceWrapper(dataSourceWrappers); } private TAtomDsStandard initAtomDataSource(String appName, String dsKey, String unitName) { try { if (tGroupDataSource.getDataSourceType().equals(DataSourceType.DruidDataSource)) { TAtomDsStandard atomDataSource = new TAtomDataSource(); atomDataSource.init(appName, dsKey, unitName); atomDataSource.setLogWriter(tGroupDataSource.getLogWriter()); atomDataSource.setLoginTimeout(tGroupDataSource.getLoginTimeout()); return atomDataSource; } else { throw new IllegalArgumentException("do not have this datasource type : " + tGroupDataSource.getDataSourceType()); } } catch (Exception e) { throw new TAtomDataSourceException("TAtomDataSource无法初始化: dsKey=" + dsKey, e); } } private class MyDataSourceFetcher implements DataSourceFetcher { private DBType dbType = DBType.MYSQL; @Override public DataSource getDataSource(String dsKey) { DataSourceWrapper dsw = dataSourceWrapperMap.get(dsKey); if (dsw != null) { dbType = dsw.getDBType(); return dsw.getWrappedDataSource(); } else { if (createTAtomDataSource) { TAtomDsStandard atomDs = initAtomDataSource(tGroupDataSource.getAppName(), dsKey, tGroupDataSource.getUnitName()); dbType = DBType.valueOf(atomDs.getDbType().name()); return atomDs; } else { throw new IllegalArgumentException(dsKey + " not exist!"); } } } @Override public DBType getDataSourceDBType(String key) { return dbType; } }; // configInfo样例: db1:rw, db2:r, db3:r private synchronized void parse(String dsWeightCommaStr) { List<DataSourceWrapper> dswList = parse2DataSourceWrapperList(dsWeightCommaStr); resetByDataSourceWrapper(dswList); } /** * extraConfig is a json format string,include table dataSourceIndex * relation or sql dataSourceIndex relation or default go main db config. * example: {sqlDsIndex: { 0:[sql1,sql2,sql3], 1:[sql0], 2:[sql4] }, * tabDsIndex: { 0:[table1,table2] 1:[table3,table4] }, defaultMain:true} * * @throws JSONException **/ @SuppressWarnings("rawtypes") private synchronized void parseExtraConfig(String extraConfig) { if (extraConfig == null) { this.groupExtraConfig.getSqlForbidSet().clear(); this.groupExtraConfig.getSqlDsIndexMap().clear(); this.groupExtraConfig.getTableDsIndexMap().clear(); this.groupExtraConfig.setDefaultMain(false); } try { JSONObject obj = JSONObject.parseObject(extraConfig); if (obj.containsKey("sqlForbid")) { Set<String> tempSqlForbidSet = new HashSet<String>(); JSONArray array = obj.getJSONArray("sqlForbid"); for (int i = 0; i < array.size(); i++) { String sql = array.getString(i); String nomalSql = TStringUtil.fillTabWithSpace(sql.trim().toLowerCase()); if (nomalSql != null && !nomalSql.trim().isEmpty()) { tempSqlForbidSet.add(nomalSql); } } this.groupExtraConfig.setSqlForbidSet(tempSqlForbidSet); } else { this.groupExtraConfig.getSqlForbidSet().clear(); } if (obj.containsKey("sqlDsIndex")) { Map<String, Integer> tempSqlDsIndexMap = new HashMap<String, Integer>(); JSONObject sqlDsIndex = obj.getJSONObject("sqlDsIndex"); Iterator it = sqlDsIndex.keySet().iterator(); while (it.hasNext()) { String key = String.valueOf(it.next()).trim(); Integer index = Integer.valueOf(key); JSONArray array = sqlDsIndex.getJSONArray(key); for (int i = 0; i < array.size(); i++) { String sql = array.getString(i); String nomalSql = TStringUtil.fillTabWithSpace(sql.trim().toLowerCase()); if (tempSqlDsIndexMap.get(nomalSql) == null) { tempSqlDsIndexMap.put(nomalSql, index); } else { // have a nice log throw new ConfigException("sql can not be route to different dataSourceIndex:" + sql); } } } this.groupExtraConfig.setSqlDsIndexMap(tempSqlDsIndexMap); } else { this.groupExtraConfig.getSqlDsIndexMap().clear(); } if (obj.containsKey("tabDsIndex")) { Map<String, Integer> tempTabDsIndexMap = new HashMap<String, Integer>(); JSONObject sqlDsIndex = obj.getJSONObject("tabDsIndex"); Iterator it = sqlDsIndex.keySet().iterator(); while (it.hasNext()) { String key = String.valueOf(it.next()).trim(); Integer index = Integer.valueOf(key); JSONArray array = sqlDsIndex.getJSONArray(key); for (int i = 0; i < array.size(); i++) { String table = array.getString(i); String nomalTable = table.trim().toLowerCase(); if (tempTabDsIndexMap.get(nomalTable) == null) { tempTabDsIndexMap.put(nomalTable, index); } else { // have a nice log throw new ConfigException("table can not be route to different dataSourceIndex:" + table); } } } this.groupExtraConfig.setTableDsIndexMap(tempTabDsIndexMap); } else { this.groupExtraConfig.getTableDsIndexMap().clear(); } if (obj.containsKey("defaultMain")) { this.groupExtraConfig.setDefaultMain(obj.getBoolean("defaultMain")); } else { this.groupExtraConfig.setDefaultMain(false); } } catch (JSONException e) { throw new ConfigException("group extraConfig is not json valid string:" + extraConfig, e); } } /** * 警告: 逗号的位置很重要,要是有连续的两个逗号也不要人为的省略掉, 数据库的个数 = * 逗号的个数+1,用0、1、2...编号,比如"db1,,db3",实际上有3个数据库, * 业务层通过传一个ThreadLocal进来,ThreadLocal中就是这种索引编号。 */ private List<DataSourceWrapper> parse2DataSourceWrapperList(String dsWeightCommaStr) { logger.warn("[parse2DataSourceWrapperList]dsWeightCommaStr=" + dsWeightCommaStr); this.tGroupDataSource.setDsKeyAndWeightCommaArray(dsWeightCommaStr); if ((dsWeightCommaStr == null) || (dsWeightCommaStr = dsWeightCommaStr.trim()).length() == 0) { throw new ConfigException("与dbGroupKey:'" + tGroupDataSource.getFullDbGroupKey() + "'对应的配置信息不能为null且长度要大于0"); } return buildDataSourceWrapperParallel(dsWeightCommaStr, new MyDataSourceFetcher()); } /** * 将封装好的AtomDataSource的列表,进一步封装为可以根据权重优先级随机选择模板库的DBSelector ---add by * mazhidan.pt * * @param dswList */ private void resetByDataSourceWrapper(List<DataSourceWrapper> dswList) { // 删掉已经不存在的DataSourceWrapper Map<String, DataSourceWrapper> newDataSourceWrapperMap = new HashMap<String, DataSourceWrapper>(dswList.size()); for (DataSourceWrapper dsw : dswList) { newDataSourceWrapperMap.put(dsw.getDataSourceKey(), dsw); } Map<String, DataSourceWrapper> old = this.dataSourceWrapperMap; this.dataSourceWrapperMap = newDataSourceWrapperMap; // TODO 需要考虑关闭老的DataSource对象 old.clear(); old = null; DBSelector r_DBSelector = null; DBSelector w_DBSelector = null; // 如果只有一个db,则用OneDBSelector if (dswList.size() == 1) { DataSourceWrapper dsw2 = dswList.get(0); r_DBSelector = new OneDBSelector(dsw2); r_DBSelector.setDbType(dsw2.getDBType()); w_DBSelector = r_DBSelector; } else { // 读写优先级Map Map<Integer/* 优先级 */, List<DataSourceWrapper>/* 优先级为key的DS 列表 */> rPriority2DswList = new HashMap<Integer, List<DataSourceWrapper>>(); Map<Integer, List<DataSourceWrapper>> wPriority2DswList = new HashMap<Integer, List<DataSourceWrapper>>(); for (DataSourceWrapper dsw1 : dswList) { add2LinkedListMap(rPriority2DswList, dsw1.getWeight().p, dsw1); add2LinkedListMap(wPriority2DswList, dsw1.getWeight().q, dsw1); } r_DBSelector = createDBSelector(rPriority2DswList, true); w_DBSelector = createDBSelector(wPriority2DswList, false); } r_DBSelector.setReadable(true); w_DBSelector.setReadable(false); this.readDBSelectorWrapper = r_DBSelector; this.writeDBSelectorWrapper = w_DBSelector; if (tGroupDataSource.getAutoSelectWriteDataSource()) { runtimeWritableAtomDBSelectorWrapper = new RuntimeWritableAtomDBSelector(dataSourceWrapperMap, groupExtraConfig); } // System.out.println("dataSourceWrapperMap=" + dataSourceWrapperMap); if (this.dataSourceChangeListener != null) { dataSourceChangeListener.onDataSourceChanged(null);// 业务通过getDataSource()获取更新后的结果 } } private DataSourceChangeListener dataSourceChangeListener; public void setDataSourceChangeListener(DataSourceChangeListener dataSourceChangeListener) { this.dataSourceChangeListener = dataSourceChangeListener; } /* * //返回的数组元素个数固定是2,第1个是read,第二个是write private DBSelector[] * createDBSelectors(List<String> dbKeyAndWeightList) { DBSelector * r_DBSelector = null; DBSelector w_DBSelector = null; * //如果只有一个db,则用OneDBSelector if (dbKeyAndWeightList.size() == 1) { String[] * dbKeyAndWeight = split(dbKeyAndWeightList.get(0), ":"); DataSourceWrapper * dsw = createDataSourceWrapper(dbKeyAndWeight[0], (dbKeyAndWeight.length * == 2 ? dbKeyAndWeight[1] : null), 0); //只有一个数据源时,数据源索引为0 r_DBSelector = * new OneDBSelector(dsw); r_DBSelector.setDbType(dsw.getDBType()); * w_DBSelector = r_DBSelector; } else { List<List<DataSourceWrapper>> * rDataSourceWrappers = new ArrayList<List<DataSourceWrapper>>(); * List<List<DataSourceWrapper>> wDataSourceWrappers = new * ArrayList<List<DataSourceWrapper>>(); for (int i = 0; i < * dbKeyAndWeightList.size(); i++) { String[] dbKeyAndWeight = * split(dbKeyAndWeightList.get(i), ":"); DataSourceWrapper dsw = * createDataSourceWrapper(dbKeyAndWeight[0], (dbKeyAndWeight.length == 2 ? * dbKeyAndWeight[1] : null), i); insertSort(rDataSourceWrappers, dsw, * true); insertSort(wDataSourceWrappers, dsw, false); } r_DBSelector = * createDBSelector(rDataSourceWrappers, true); w_DBSelector = * createDBSelector(wDataSourceWrappers, false); } * r_DBSelector.setReadable(true); w_DBSelector.setReadable(false); return * new DBSelector[] { r_DBSelector, w_DBSelector }; } */ /** * 将给定的k 优先级 加入这个优先级对应的V list 里面。 ----因为可能有多个DS具有相同的优先级 ---add by * mazhidan.pt */ private static <K, V> void add2LinkedListMap(Map<K, List<V>> m, K key, V value) { // 从Map中先取出这个优先级的List List<V> c = (List<V>) m.get(key); // 如果为空,则new一个 if (c == null) { c = new LinkedList<V>(); m.put(key, c); } // 不为空,在后面add() c.add(value); } /** * @param dsWeightCommaStr : 例如 db0:rwp1q1i0, db1:rwp0q0i1 */ public static List<DataSourceWrapper> buildDataSourceWrapper(String dsWeightCommaStr, DataSourceFetcher fetcher) { String[] dsWeightArray = dsWeightCommaStr.split(","); // 逗号分隔:db0:rwp1q1i0, // db1:rwp0q0i1 List<DataSourceWrapper> dss = new ArrayList<DataSourceWrapper>(dsWeightArray.length); for (int i = 0; i < dsWeightArray.length; i++) { String[] dsAndWeight = dsWeightArray[i].split(":"); // 冒号分隔:db0:rwp1q1i0 String dsKey = dsAndWeight[0].trim(); String weightStr = dsAndWeight.length == 2 ? dsAndWeight[1] : null; DataSourceWrapper dsw = getDataSourceWrapper(dsKey, weightStr, i, fetcher); dss.add(dsw); } return dss; } public static DataSourceWrapper getDataSourceWrapper(String dsKey, String weightStr, int index, DataSourceFetcher fetcher) { // 如果多个group复用一个真实dataSource,会造成所有group引用 // 这个dataSource的配置 会以最后一个dataSource的配置为准 DataSource dataSource = fetcher.getDataSource(dsKey); DBType fetcherDbType = fetcher.getDataSourceDBType(dsKey); // dbType = fetcherDbType == null ? dbType : // fetcherDbType; DataSourceWrapper dsw = new DataSourceWrapper(dsKey, weightStr, dataSource, fetcherDbType, index); return dsw; } public static List<DataSourceWrapper> buildDataSourceWrapperParallel(String dsWeightCommaStr, final DataSourceFetcher fetcher) { final String[] dsWeightArray = dsWeightCommaStr.split(","); // 逗号分隔:db0:rwp1q1i0, // db1:rwp0q0i1 List<DataSourceWrapper> dss = new ArrayList<DataSourceWrapper>(dsWeightArray.length); ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new NamedThreadFactory("TDDL_GROUP_INIT"), new ThreadPoolExecutor.CallerRunsPolicy()); Map<String, Future<DataSourceWrapper>> m = new HashMap<String, Future<DataSourceWrapper>>(); for (int i = 0; i < dsWeightArray.length; i++) { final int j = i; final String[] dsAndWeight = dsWeightArray[j].split(":"); // 冒号分隔:db0:rwp1q1i0 final String dsKey = dsAndWeight[0].trim(); Future<DataSourceWrapper> f = executor.submit(new Callable<DataSourceWrapper>() { @Override public DataSourceWrapper call() throws Exception { String weightStr = dsAndWeight.length == 2 ? dsAndWeight[1] : null; return getDataSourceWrapper(dsKey, weightStr, j, fetcher); } }); m.put(dsKey, f); } for (Map.Entry<String, Future<DataSourceWrapper>> en : m.entrySet()) { try { dss.add(en.getValue().get()); } catch (Exception e) { throw new RuntimeException("init ds error! atom key is " + en.getKey(), e); } } executor.shutdown(); return dss; } /** * 根据给定的具有读写优先级及每个优先级对应的DataSource链表的Map,构造DBSelector---add by mazhidan.pt * * @param priority2DswList * @param isRead * @return */ private DBSelector createDBSelector(Map<Integer/* 优先级 */, List<DataSourceWrapper>> priority2DswList, boolean isRead) { if (priority2DswList.size() == 1) { // 只有一个优先级直接使用EquityDbManager return createDBSelector2(priority2DswList.entrySet().iterator().next().getValue(), isRead); } else { List<Integer> priorityKeys = new LinkedList<Integer>(); priorityKeys.addAll(priority2DswList.keySet()); Collections.sort(priorityKeys); // 优先级从小到大排序 EquityDbManager[] priorityGroups = new EquityDbManager[priorityKeys.size()]; for (int i = 0; i < priorityGroups.length; i++) { // 最大的优先级放到最前面 int priority = priorityKeys.get(priorityGroups.length - 1 - i);// 倒序 List<DataSourceWrapper> dswList = priority2DswList.get(priority); // PriorityDbGroupSelector依赖EquityDbManager抛出的NoMoreDataSourceException来实现, // 所以这里即使只有一个ds也只能仍然用EquityDbManager priorityGroups[i] = createEquityDbManager(dswList, isRead, groupExtraConfig); } return new PriorityDbGroupSelector(priorityGroups); } } private AbstractDBSelector createDBSelector2(List<DataSourceWrapper> dswList, boolean isRead) { AbstractDBSelector dbSelector; if (dswList.size() == 1) { DataSourceWrapper dsw = dswList.get(0); dbSelector = new OneDBSelector(dsw); dbSelector.setDbType(dsw.getDBType()); } else { dbSelector = createEquityDbManager(dswList, isRead, groupExtraConfig); } return dbSelector; } /* * private DBSelector createDBSelector(List<List<DataSourceWrapper>> list, * boolean isRead) { int size = list.size(); //优先级别个数 if (size == 1) { * //只有一个优先级直接使用EquityDbManager return createEquityDbManager(list.get(0), * isRead); } else { EquityDbManager[] priorityGroups = new * EquityDbManager[size]; for (int i = 0; i < size; i++) { priorityGroups[i] * = createEquityDbManager(list.get(i), isRead); } return new * PriorityDbGroupSelector(priorityGroups); } } */ private static EquityDbManager createEquityDbManager(List<DataSourceWrapper> list, boolean isRead, GroupExtraConfig groupExtraConfig) { Map<String, DataSourceWrapper> dataSourceMap = new HashMap<String, DataSourceWrapper>(list.size()); Map<String, Integer> weightMap = new HashMap<String, Integer>(list.size()); DBType dbType = null; for (DataSourceWrapper dsw : list) { String dsKey = dsw.getDataSourceKey(); dataSourceMap.put(dsKey, dsw); weightMap.put(dsKey, isRead ? dsw.getWeight().r : dsw.getWeight().w); if (dbType == null) { dbType = dsw.getDBType(); } } EquityDbManager equityDbManager = new EquityDbManager(dataSourceMap, weightMap, groupExtraConfig); equityDbManager.setDbType(dbType); return equityDbManager; } /** * 因为数据源个数通常在3个左右,所以这里使用了简单的插入排序算法, * 两级List(如:List<List<DataSourceWrapper>>)类似下面这种结构, * 第一级List(纵列)代表优先级,优先级最高的排在List的0号位置处,其次是1号位置,依此类推, * 第二级List(横列)表示相同优先级的多个数据源。 ---- |p9|-->|db0|-->|db2| ---- |p8|-->|db1| * ---- |p7|-->|db3| ---- * * @param priorityList 上一次已排好序的数据源列表,由调用者确保不为null。 * @param dsw 当前需要插入到列表的数据源 * @param isRead 因为优先级分读写优先级,读用p表示,写用q表示,如果isRead为true就使用P,否则用q。 */ /* * public static void insertSort(List<List<DataSourceWrapper>> priorityList, * DataSourceWrapper dsw, boolean isRead) { * //如果读或写的权重为0,那么就表示此数据源对应的数据库不可读或不可写,此时什么都不做,忽略此数据源。 // if ((isRead && * dsw.getWeight().r == 0) || (!isRead && dsw.getWeight().w == 0)) // * return; List<DataSourceWrapper> samePriorityDataSourceWrappers; int * newPriority = isRead ? dsw.getWeight().p : dsw.getWeight().q; int index = * 0; int size = priorityList.size(); while (index < size) { * samePriorityDataSourceWrappers = priorityList.get(index); * //去除priorityList中的无效元素,防止空指针异常和下标越界异常。 if (samePriorityDataSourceWrappers * == null || samePriorityDataSourceWrappers.size() == 0) { * priorityList.remove(index); size--; continue; } Weight oldWeight = * samePriorityDataSourceWrappers.get(0).getWeight(); int oldPriority = * isRead ? oldWeight.p : oldWeight.q; if (newPriority == oldPriority) { * //这里不用按权重排序了 samePriorityDataSourceWrappers.add(dsw); return; } else if * (newPriority > oldPriority) { break; } else { index++; } } * //没有找到相同优先级时新插入一个优先级 (当size=0时也会走到这里) samePriorityDataSourceWrappers = * new ArrayList<DataSourceWrapper>(); * samePriorityDataSourceWrappers.add(dsw); priorityList.add(index, * samePriorityDataSourceWrappers); } */ /* * private DataSourceWrapper createDataSourceWrapper(String dsKey, String * weightStr, int dataSourceIndex) { aliveDataSourceKeys.add(dsKey); * DataSourceWrapper dsw = dataSourceWrapperMap.get(dsKey); if (dsw != null) * { //dsw.setWeightStr(weightStr); * //dsw.setDataSourceIndex(dataSourceIndex); } else { if * (createTAtomDataSource) { TAtomDataSource ads = * createTAtomDataSource(dsKey); dsw = new DataSourceWrapper(dsKey, * weightStr, ads, getDBTypeFrom(ads), dataSourceIndex); * dataSourceWrapperMap.put(dsKey, dsw); } else { throw new * IllegalArgumentException(dsKey + " not exist!"); } } return dsw; } */ /** * 根据当前的读写状态,检查数据源是否可用,数据源分两种:TAtomDataSource和普通的数据源(如DBCP数据源) 新添加一个数据源 * druid * * @param ds 要检查的数据源 * @param isRead 是对数据源进行读操作(isRead=true),还是写操作(isRead=false) * @return 普通的数据源不管当前的读写状态是什么,总是可用的,返回true。 * TAtomDataSource如果当前的状态是NA返回false, 否则根据WR状态以及isRead的值决定 */ public static boolean isDataSourceAvailable(DataSource ds, boolean isRead) { if (ds instanceof DataSourceWrapper) { ds = ((DataSourceWrapper) ds).getWrappedDataSource(); } if (!(ds instanceof TAtomDsStandard)) { return true; } if (ds instanceof TAtomDsStandard) { TAtomDbStatusEnum status = ((TAtomDsStandard) ds).getDbStatus(); if (status.isNaStatus()) { return false; } if (status.isRstatus() && isRead) { return true; } if (status.isWstatus() && !isRead) { return true; } } return false; } /** * 不能在TGroupDataSource或TGroupConnection或其他地方把DBSelector做为一个字段保存下来, * 否则db权重配置变了之后无法使用最新的权重配置 */ private volatile DBSelector readDBSelectorWrapper; private volatile DBSelector writeDBSelectorWrapper; private volatile DBSelector runtimeWritableAtomDBSelectorWrapper; /** * 根据是读还是写来选择对应的DBSelector---add by mazhidan.pt */ public DBSelector getDBSelector(boolean isRead, boolean autoSelectWriteDataSource) { DBSelector dbSelector = isRead ? readDBSelectorWrapper : writeDBSelectorWrapper; if (!isRead && autoSelectWriteDataSource) { // 因为所有dbSelector内部的TAtomDataSource都是指向同一个实例,如果某一个TAtomDataSource的状态改了, // 那么所有包含这个TAtomDataSource的dbSelector都会知道状态改变了, // 所以只要有一个TAtomDataSource的状态变成W, // 那么不管这个dbSelector是专门用于读的,还是专门用于写的,也不管是不是runtimeWritableAtomDBSelector, // 只要调用了hasWritableDataSource()都会返回true // if(!dbSelector.hasWritableDataSource()) dbSelector = runtimeWritableAtomDBSelectorWrapper; } return dbSelector; } private class ConfigReceiver implements ConfigDataListener { private GroupConfigManager configManager; public void setConfigManager(GroupConfigManager configManager) { this.configManager = configManager; } public void onDataRecieved(String dataId, String data) { try { String oldData = this.configManager.tGroupDataSource.getDsKeyAndWeightCommaArray(); logger.warn("group ds data received !dataId:" + dataId + ", new data:" + data + ", old data:" + oldData); parse(data); } catch (Throwable t) { logger.error("动态解析配置信息时出现错误:" + data, t); } } } private class ExtraGroupConfigReceiver implements ConfigDataListener { @Override public void onDataRecieved(String dataId, String data) { logger.info("receive group extra data:" + data); parseExtraConfig(data); } } // 仅用于测试 public void receiveConfigInfo(String configInfo) { configReceiver.onDataRecieved(null, configInfo); } // 仅用于测试 public void resetDbGroup(String configInfo) { try { parse(configInfo); } catch (Throwable t) { logger.error("resetDbGroup failed:" + configInfo, t); } } public void destroyDataSource() throws Exception { // 关闭下层DataSource if (dataSourceWrapperMap != null) { for (DataSourceWrapper dsw : dataSourceWrapperMap.values()) { try { DataSource ds = dsw.getWrappedDataSource(); if (ds instanceof TAtomDsStandard) { TAtomDsStandard tads = (TAtomDsStandard) ds; tads.destroyDataSource(); } else { logger.error("target datasource is not a TAtom Data Source"); } } catch (Exception e) { logger.error("we got exception when close datasource : " + dsw.getDataSourceKey(), e); } } } // 关闭global datasource handler try { if (globalHandler != null) { globalHandler.destory(); } } catch (Exception e) { logger.error("we got exception when close datasource .", e); } // 关闭extraDataSource handler. try { if (extraHandler != null) { extraHandler.destory(); } } catch (Exception e) { logger.error("we got exception when close datasource .", e); } } }