六 、源码分析
6.1 概述
在最新源码 (v20.13.1.1) 中,ClickHouse 官方对 DatabaseMaterializeMySQL 引擎的相关源码进行了重构,并适配了 GTID 同步模式。ClickHouse 整个项目的入口 main 函数在 /ClickHouse/programs/main.cpp 文件中,主程序会根据接收指令将任务分发到 ClickHouse/programs 目录下的子程序中处理。本次分析主要关注 Server 端 MaterializeMySQL 引擎的工作流程。
6.2 源码目录
与 MaterializeMySQL 相关的主要源码路径:
ClickHouse/src/databases/MySQL //MaterializeMySQL存储引擎实现
ClickHouse/src/Storages/ //表引擎实现
ClickHouse/src/core/MySQL* //复制相关代码
ClickHouse/src/Interpreters/ //Interpreters实现,SQL的rewrite也在这里处理
ClickHouse/src/Parsers/MySQL //解析部分实现,DDL解析等相关处理在这里
6.3 服务端主要流程
ClickHouse 使用 POCO 网络库处理网络请求,Client连接的处理逻辑在 ClickHouse/src/Server/*Handler.cpp 的 hander方法里。以TCP为例,除去握手,初始化上下文以及异常处理等相关代码,主要逻辑可以抽象成:
// ClickHouse/src/Server/TCPHandler.cpp
TCPHandler.runImpl()
{
...
while(true) {
...
if (!receivePacket()) //line 184
continue
/// Processing Query //line 260
state.io = executeQuery(state.query, *query_context, ...);
...
}
6.4 数据同步预处理
Client发送的SQL在executeQuery函数处理,主要逻辑简化如下:
// ClickHouse/src/Interpreters/executeQuery.cpp
static std::tuple executeQueryImpl(...)
{
...
// line 354,解析器可配置
ast = parseQuery(...);
...
// line 503, 根据语法树生成interpreter
auto interpreter = InterpreterFactory::get(ast, context, ...);
...
// line 525, 执行器interpreter执行后返回结果
res = interpreter->execute();
...
}
主要有三点:
1、解析SQL语句并生成语法树 AST
2、InterpreterFactory 工厂类根据 AST 生成执行器
3、interpreter->execute()
跟进第三点,看看 InterpreterCreateQuery 的 excute() 做了什么:
// ClickHouse/src/Interpreters/InterpreterCreateQuery.cpp
BlockIO InterpreterCreateQuery::execute()
{
...
// CREATE | ATTACH DATABASE
if (!create.database.empty() && create.table.empty())
// line 1133, 当使用MaterializeMySQL时,会走到这里建库
return createDatabase(create);
}
这里注释很明显,主要执行 CREATE 或 ATTACH DATABASE,继续跟进 createDatabase() 函数:
// ClickHouse/src/Interpreters/InterpreterCreateQuery.cpp
BlockIO InterpreterCreateQuery::createDatabase(ASTCreateQuery & create)
{
..