C++项目在启动时都是从main()方法开始执行的。今天来分析一下ClickHouse源码的main.cpp。
先找到main()方法:
int main(int argc_, char **argv_) {
/// Reset new handler to default (that throws std::bad_alloc)
/// It is needed because LLVM library clobbers it.
std::set_new_handler(nullptr);
#if USE_EMBEDDED_COMPILER
if (argc_ >= 2 && 0 == strcmp(argv_[1], "-cc1"))
return mainEntryClickHouseClang(argc_, argv_);
#endif
#if USE_TCMALLOC
/** Without this option, tcmalloc returns memory to OS too frequently for medium-sized memory allocations
* (like IO buffers, column vectors, hash tables, etc.),
* that lead to page faults and significantly hurts performance.
*/
MallocExtension::instance()->SetNumericProperty("tcmalloc.aggressive_memory_decommit", false);
#endif
std::vector<char *> argv(argv_, argv_ + argc_);
/// Print a basic help if nothing was matched
MainFunc main_func = printHelp;
for (auto &application : clickhouse_applications) {
if (isClickhouseApp(application.first, argv)) {
main_func = application.second;
break;
}
}
return main_func(static_cast<int>(argv.size()), argv.data());
}
主要步骤包括:(重点在4、5步)
1、重置handler;
2、条件编译命令 USE_EMBEDDED_COMPILER;
3、条件编译命令 USE_TCMALLOC;
4、遍历已经定义好的clickhouse_applications[]数组,根据输入参数判断需要启动哪个application;
5、进入application对应的主函数,并执行。
如输入为clickhouse server .....,则启动server这个应用,执行mainEntryClickHouseServer这个方法:
int mainEntryClickHouseServer(int argc, char **argv) {
DB::Server app;
try {
return app.run(argc, argv);
}
catch (...) {
std::cerr << DB::getCurrentExceptionMessage(true) << "\n";
auto code = DB::getCurrentExceptionCode();
return code ? code : 1;
}
}
如输入为clickhouse client .....,则启动client这个应用,执行mainEntryClickHouseClient这个方法:
int mainEntryClickHouseClient(int argc, char **argv) {
try {
DB::Client client;
client.init(argc, argv);//注意客户端需要先执行这里的client.init()方法
return client.run();
}
catch (const boost::program_options::error &e) {
std::cerr << "Bad arguments: " << e.what() << std::endl;
return 1;
}
catch (...) {
std::cerr << DB::getCurrentExceptionMessage(true) << std::endl;
return 1;
}
}
不同应用的具体的启动过程在后面的文章中进行分析。