数据库路由中间件MyCat - 源代码篇(11)
此文已由作者张镐薪授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
4.配置模块
每个MyCatServer初始化时,会初始化: MyCatServer.java:
public static final String NAME = "MyCat";private static final long LOG_WATCH_DELAY = 60000L;private static final long TIME_UPDATE_PERIOD = 20L;private static final MycatServer INSTANCE = new MycatServer();private static final Logger LOGGER = LoggerFactory.getLogger("MycatServer");private final RouteService routerService;private final CacheService cacheService;private Properties dnIndexProperties;//AIO连接群组private AsynchronousChannelGroup[] asyncChannelGroups;private volatile int channelIndex = 0;//全局序列号private final MyCATSequnceProcessor sequnceProcessor = new MyCATSequnceProcessor();private final DynaClassLoader catletClassLoader;private final SQLInterceptor sqlInterceptor;private volatile int nextProcessor;private BufferPool bufferPool;private boolean aio = false;//XA事务全局ID生成private final AtomicLong xaIDInc = new AtomicLong();private MycatServer() { //读取文件配置
this.config = new MycatConfig(); //定时线程池,单线程线程池
scheduler = Executors.newSingleThreadScheduledExecutor(); //SQL记录器
this.sqlRecorder = new SQLRecorder(config.getSystem()
.getSqlRecordCount()); /**
* 是否在线,MyCat manager中有命令控制
* | offline | Change MyCat status to OFF |
* | online | Change MyCat status to ON |
*/
this.isOnline = new AtomicBoolean(true); //缓存服务初始化
cacheService = new CacheService(); //路由计算初始化
routerService = new RouteService(cacheService); // load datanode active index from properties
dnIndexProperties = loadDnIndexProps(); try { //SQL解析器
sqlInterceptor = (SQLInterceptor) Class.forName(
config.getSystem().getSqlInterceptor()).newInstance();
} catch (Exception e) { throw new RuntimeException(e);
} //catlet加载器
catletClassLoader = new DynaClassLoader(SystemConfig.getHomePath()
+ File.separator + "catlet", config.getSystem()
.getCatletClassCheckSeconds()); //记录启动时间
this.startupTime = TimeUtil.currentTimeMillis();
}
第一步是读取文件配置,主要是三个文件:schema.xml,rule.xml和server.xml. 读取后的配置会加载到MyCatConfig中。 MyCatConfig.java:
public MycatConfig() {//读取schema.xml,rule.xml和server.xmlConfigInitializer confInit = new ConfigInitializer(true);this.system = confInit.getSystem();this.users = confInit.getUsers();this.schemas = confInit.getSchemas();this.dataHosts = confInit.getDataHosts();this.dataNodes = confInit.getDataNodes();for (PhysicalDBPool dbPool : dataHosts.values()) {
dbPool.setSchemas(getDataNodeSchemasOfDataHost(dbPool.getHostName()));
}this.quarantine = confInit.getQuarantine();this.cluster = confInit.getCluster();//初始化重加载配置时间this.reloadTime = TimeUtil.currentTimeMillis();this.rollbackTime = -1L;this.status = RELOAD;//配置加载锁this.lock = new ReentrantLock();
}
它们都通过ConfigInitializer读取:
public ConfigInitializer(boolean loadDataHost) { //读取schema.xml
SchemaLoader schemaLoader = new XMLSchemaLoader(); //读取server.xml
XMLConfigLoader configLoader = new XMLConfigLoader(schemaLoader);
schemaLoader = null; //加载配置
this.system = configLoader.getSystemConfig(); this.users = configLoader.getUserConfigs(); this.schemas = configLoader.getSchemaConfigs(); //是否重新加载DataHost和对应的DataNode
if (loadDataHost) { this.dataHosts = initDataHosts(configLoader); this.dataNodes = initDataNodes(configLoader);
} //权限管理
this.quarantine = configLoader.getQuarantineConfig(); this.cluster = initCobarCluster(configLoader); //不同类型的全局序列处理器的配置加载
if (system.getSequnceHandlerType() == SystemConfig.SEQUENCEHANDLER_MYSQLDB) {
IncrSequenceMySQLHandler.getInstance().load();
} if (system.getSequnceHandlerType() == SystemConfig.SEQUENCEHANDLER_LOCAL_TIME) {
IncrSequenceTimeHandler.getInstance().load();
} //检查user与schema配置对应以及schema配置不为空
this.checkConfig();
}
4.1 rule.xml
读取schema之前会先读取rule.xml。 XmlSchemaLoader.java:
public XMLSchemaLoader(String schemaFile, String ruleFile) { //先读取rule.xml
XMLRuleLoader ruleLoader = new XMLRuleLoader(ruleFile); this.tableRules = ruleLoader.getTableRules();
ruleLoader = null; this.dataHosts = new HashMap<String, DataHostConfig>(); this.dataNodes = new HashMap<String, DataNodeConfig>(); this.schemas = new HashMap<String, SchemaConfig>(); //读取加载schema配置
this.load(DEFAULT_DTD, schemaFile == null ? DEFAULT_XML : schemaFile);
}public XMLSchemaLoader() { this(null, null);
}
XMLRuleLoader.java:
public XMLRuleLoader(String ruleFile) { // this.rules = new HashSet<RuleConfig>();
//rule名 -> rule
this.tableRules = new HashMap<String, TableRuleConfig>(); //function名 -> 具体分片算法
this.functions = new HashMap<String, AbstractPartitionAlgorithm>(); //默认为:/rule.dtd和/rule.xml
load(DEFAULT_DTD, ruleFile == null ? DEFAULT_XML : ruleFile);
}public XMLRuleLoader() { this(null);
}
private void load(String dtdFile, String xmlFile) {
InputStream dtd = null;
InputStream xml = null; try {
dtd = XMLRuleLoader.class.getResourceAsStream(dtdFile);
xml = XMLRuleLoader.class.getResourceAsStream(xmlFile); //读取出语意树
Element root = ConfigUtil.getDocument(dtd, xml)
.getDocumentElement(); //加载Function
loadFunctions(root); //加载TableRule
loadTableRules(root);
} catch (ConfigException e) { throw e;
} catch (Exception e) { throw new ConfigException(e);
} finally { if (dtd != null) { try {
dtd.close();
} catch (IOException e) {
}
} if (xml != null) { try {
xml.close();
} catch (IOException e) {
}
}
}
}
ConfigUtil.java解析语意树:
public static Document getDocument(final InputStream dtd, InputStream xml) throws ParserConfigurationException,
SAXException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
factory.setNamespaceAware(false);
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver(new EntityResolver() { @Override
public InputSource resolveEntity(String publicId, String systemId) { return new InputSource(dtd);
}
});
builder.setErrorHandler(new ErrorHandler() { @Override
public void warning(SAXParseException e) {
} @Override
public void error(SAXParseException e) throws SAXException { throw e;
} @Override
public void fatalError(SAXParseException e) throws SAXException { throw e;
}
}); return builder.parse(xml);
}
加载functions,XmlRuleLoader.java
private void loadFunctions(Element root) throws ClassNotFoundException,
InstantiationException, IllegalAccessException,
InvocationTargetException {
NodeList list = root.getElementsByTagName("function"); for (int i = 0, n = list.getLength(); i < n; ++i) {
Node node = list.item(i); if (node instanceof Element) {
Element e = (Element) node; //获取name标签
String name = e.getAttribute("name"); //如果Map已有,则function重复
if (functions.containsKey(name)) { throw new ConfigException("rule function " + name
+ " duplicated!");
} //获取class标签
String clazz = e.getAttribute("class"); //根据class利用反射新建分片算法
AbstractPartitionAlgorithm function = createFunction(name, clazz); ParameterMapping.mapping(function, ConfigUtil.loadElements(e)); //每个AbstractPartitionAlgorithm可能会实现init来初始化
function.init(); //放入functions map
functions.put(name, function);
}
}
}private AbstractPartitionAlgorithm createFunction(String name, String clazz)
throws ClassNotFoundException, InstantiationException,
IllegalAccessException, InvocationTargetException {
Class<?> clz = Class.forName(clazz); //判断是否继承AbstractPartitionAlgorithm
if (!AbstractPartitionAlgorithm.class.isAssignableFrom(clz)) { throw new IllegalArgumentException("rule function must implements "
+ AbstractPartitionAlgorithm.class.getName() + ", name=" + name);
}
return (AbstractPartitionAlgorithm) clz.newInstance();
}
加载所有的function的node,每一个node就是一个AbstractPartitionAlgorithm,并放入functions这个map中;
private final Map<String, TableRuleConfig> tableRules;
对于每一个node,通过反射新建对应参数的AbstractPartitionAlgorithm。这样,所有的function就加载到了functions这个map中。
同理,加载TableRule,就加上了function是否存在的判断:
/**
* tableRule标签结构:
* <tableRule name="sharding-by-month">
* <rule>
* <columns>create_date</columns>
* <algorithm>partbymonth</algorithm>
* </rule>
* </tableRule>
* @param root
* @throws SQLSyntaxErrorException
*/private void loadTableRules(Element root) throws SQLSyntaxErrorException { //获取每个tableRule标签
NodeList list = root.getElementsByTagName("tableRule"); for (int i = 0, n = list.getLength(); i < n; ++i) {
Node node = list.item(i); if (node instanceof Element) {
Element e = (Element) node; //先判断是否重复
String name = e.getAttribute("name"); if (tableRules.containsKey(name)) { throw new ConfigException("table rule " + name
+ " duplicated!");
} //获取rule标签
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 JAVA异常的最佳工程学实践探索
【推荐】 深入解析SQL Server高可用镜像实现原理
数据库路由中间件MyCat - 源代码篇(11)的更多相关文章
- 数据库路由中间件MyCat - 源代码篇(1)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 进入了源代码篇,我们先从整体入手,之后拿一个简单流程前端连接建立与认证作为例子,理清代码思路和设计模式.然后 ...
- 数据库路由中间件MyCat - 源代码篇(13)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 4.配置模块 4.2 schema.xml 接上一篇,接下来载入每个schema的配置(也就是每个MyCat ...
- 数据库路由中间件MyCat - 源代码篇(7)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 3. 连接模块 3.4 FrontendConnection前端连接 构造方法: public Fronte ...
- 数据库路由中间件MyCat - 源代码篇(15)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. public static void handle(String stmt, ServerConnectio ...
- 数据库路由中间件MyCat - 源代码篇(17)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 调用processInsert(sc,schema,sqlType,origSQL,tableName,pr ...
- 数据库路由中间件MyCat - 源代码篇(14)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 对于表的dataNode对应关系,有个特殊配置即类似dataNode="distributed(d ...
- 数据库路由中间件MyCat - 源代码篇(4)
此文已由作者易国强授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2. 前端连接建立与认证 Title:MySql连接建立以及认证过程client->MySql:1.T ...
- 数据库路由中间件MyCat - 源代码篇(2)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2. 前端连接建立与认证 Title:MySql连接建立以及认证过程client->MySql:1.T ...
- 数据库路由中间件MyCat - 源代码篇(16)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 5. 路由模块 真正取得RouteResultset的步骤:AbstractRouteStrategy的ro ...
随机推荐
- 【题解】POJ1934 Trip (DP+记录方案)
[题解]POJ1934 Trip (DP+记录方案) 题意: 传送门 刚开始我是这么设状态的(谁叫我DP没学好) \(dp(i,j)\)表示钦定选择\(i\)和\(j\)的LCS,然而你会发现这样钦定 ...
- 【题解】[CJOI2019Chebnear]
[题解][CJOI2019Chebnear] 题目描述 给定平面上有\(n\)个仇人,\((x,y) ,x,y \in R^+\) ,\(n\)个人都是仇人关系,而有仇人关系的一对人的切比雪夫距离若\ ...
- react-navigation遇到的坑
关于goBack返回指定页面 react-navigation是提供了goBack()到指定页面的方法的,那就是在goBack()中添加一个参数,但当你使用goBack('Main')的时候,你会发现 ...
- 剑指Offer:字符串排列【38】
剑指Offer:字符串排列[38] 题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bc ...
- ActiveMQ持久化机制
用户注册成功后发短信提醒 同步http 异步mq JMS中两种通讯模式: 发布订阅 一对多 topic 去过消费者集群的话 都会消费 消息队列 点对点 queue 去过消费者集群的话 ...
- JMS消息可靠机制
ActiveMQ消息签收机制: 客戶端成功接收一条消息的标志是一条消息被签收,成功应答. 消息的签收情形分两种: 1.带事务的session 如果session带有事务,并且事务成功提交,则消息被自动 ...
- Android6.0 旋转屏幕(五)WMS启动应用流程(屏幕方向相关)
一.强制设置方向 1.Activity 如果要强制设置一个Activity的横竖屏可以通过Manifest去设置,跟Activity相关的信息都会保存在ActivityInfo当中. android: ...
- Eclipse中导入github上的项目
Eclipse中导入github上的项目 转载至: http://blog.csdn.net/hil2000/article/details/8566456 1.首先在github.com上申请一个账 ...
- ffmpeg拼接mp4视频
首先需要把mp4格式的文件转成ts格式.拼接好之后,再将ts封装格式转换回mp4. ffmpeg -i 1.mp4 -vcodec copy -acodec copy -vbsf h264_mp4to ...
- Java丨springMVC + Ajax 来进行分页
javaweb 分页技术 实现的方式有很多种,但是小编在网上问了度娘也问了谷老师,得到的答案让小编我不是很满意,so,还是自己写吧! 在小编的博文中,小编不会上传源码,只会把重要的代码和思路供大家参考 ...