MYSQL源码分析(二)--主要代码流程
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
我们从MySQL启动开始,看一下MySQL业务流程。
★首先入口函数在目录sql/中:
int main(int argc, char **argv)
{
return mysqld_main(argc, argv);
}
调用了mysqld_main(argc, argv)函数,这个函数在sql/中
接着开始初始化:
★MY_INIT(argv[0]); 函数位于sql/my_,用于初始化mysql内部的系统库,MYSQL定义了大量的全局变量用于系统的状态值,这样省去很多函数之间的交互参数,这些全局变量定义在my_中。
★接着初始化变量sys_var_init();
★初始化审计接口(这部分用的不多,暂时不深入)mysql_audit_initialize();
★初始化日志功能logger.init_base();日志是系统的一个重要地方,mysql定义了一个logger 类,在文件sql/Logger.hpp中,里面定义了一系列的成员函数,具体可以参照logger.hpp 中的注释,很详细。(后续会专门针对日志模块做一次分析)
★接着就初始化配置信息了,
开始之后,又是一大堆全局变量初始化。
init_thread_environment()初始化线程环境。(这个就是线程池了)
mysql_init_variables()初始化配置变量,
这边给我最大的感悟就是,MYSQL在获取或者修改一些变量时,一定会先与之相关的系统变量都读出来确认一遍,全部没问题后才修改,有问题都会有相应的日志(所以日志模块必须最先初始化)
如果初始化失败,会调用mysql_server_end() ,而mysql_server_end()实际上是一个宏定义
#define mysql_server_end() mysql_client_plugin_deinit()宏定义也可以这样用
mysql_client_plugin_deinit()用于终止mysql server的线程。
★初始化server的模块init_server_components()
table_def_init() || hostname_cache_init(),初始化table cache
query_cache_init();初始化查询cache
#ifdef HAVE_REPLICATION
init_slave_list();如果有复制,还要初始化备机的状态list
#endif
后面还有一些cache初始化如
★network_init();//初始化网络模块,创建socket监听
这个流程和传统的tcp服务端代码基本一样,单独开启一个线程用于监听,set_ports();
函数用于初始化端口,默认为3306。
ip_sock= create_socket(ai, AF_INET, &a);
if (ip_sock == INVALID_SOCKET)
ip_sock= create_socket(ai, AF_INET6, &a);
// Report user-error if we failed to create a socket.
if (ip_sock == INVALID_SOCKET)
{
sql_perror(ER_DEFAULT(ER_IPSOCK_ERROR)); /* purecov: tested */
unireg_abort(1); /* purecov: tested */ }
现在IPV4上创建侦听,如果失败了,再在ipv6上创建侦听。
有时候,mysql所用的端口不会及时释放(重启,关闭的时候),这里有个算法for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
{
if (((ret= bind(ip_sock, a->ai_addr, a->ai_addrlen)) >= 0 ) ||
(socket_errno != SOCKET_EADDRINUSE) ||
(waited >= mysqld_port_timeout))
break;
sql_print_information("Retrying bind on TCP/IP port %u", mysqld_port);
this_wait= retry * retry / 3 + 1;
sleep(this_wait);
}
他会按照
Sleep intervals: 1, 2, 4, 6, 9, 13, 17, 22, ...
Retry at second: 1, 3, 7, 13, 22, 35, 52, 74, ...
来省资源。
接着就是三种系统的侦听代码,原理都是一样的。
★start_signal_handler();// 创建pid文件
调用create_pid_file(),调用了自己封装的mysql_file_write()把内容写到了文件,mysql_file_write()也是个宏定义。
★if (mysql_rm_tmp_tables() || acl_init(opt_noacl) ||
my_tz_init((THD *)0, default_tz_name, opt_bootstrap))
删除tmp_table并初始化数据库级别的权限。
★init_status_vars(); 初始化mysql中的status变量
inlog_unsafe_map_init();
initialize_information_schema_acl();
execute_ddl_log_recovery();
create_shutdown_thread();
未启动先保护,这样异常出现时,系统不会直接崩掉,同时会尽可能的多保留下信息。
★start_handle_manager(); 创建manager线程
mysql_thread_create(key_thread_handle_manager,
&hThread, &connection_attrib, handle_manager, 0)
★handle_connections_sockets();
主要处理函数,
一系列异常保护之后,如果系统收到新的连接,就创建新的线程处理之