mysqld 的启动流程
mysqld 是一个 c++ 程序,入口函数当时是 main,而这个 main 呢,就是直接调用 mysqld_main 函数。
// sql/main.cc 文件
extern int mysqld_main(int argc, char **argv);
int main(int argc, char **argv) { return mysqld_main(argc, argv); }
mysqld_main
// sql/mysqld_main.cc
static Connection_acceptor<Mysqld_socket_listener> *mysqld_socket_acceptor = nullptr;
static bool network_init(void) {
mysqld_socket_acceptor = new (std::nothrow)
if(mysqld_socket_acceptor->init_connection_acceptor()) {
...
}
}
int mysqld_main(int argc, char **argv)
{
// 计算一下堆栈的生长方向,linux 操作系统的话向下长; 影响的话就是会把 stack_direction 设置成 -1 。
initialize_stack_direction();
// 这里是一堆的初始化操作
// 命令行参数解析、初始化网络和套接字、初始化引擎、初始化查询系统、初始化日志、初始化权限
// 初始化复制、初始化插件、启动tcp服务器
...
// 进入事件循环
mysqld_socket_acceptor->connection_event_loop();
// 执行到这里说明是要退出了
// join 前面创建的线程
clean_up(true);
mysqld_exit(signal_hand_thr_exit_code);
}
connection_event_loop
connection_event_loop 函数的实例如下
// sql/sql/conn_handler/connection_acceptor.h
void connection_event_loop() {
Connection_handler_manager *mgr =
Connection_handler_manager::get_instance();
while (!connection_events_loop_aborted()) {
Channel_info *channel_info = m_listener->listen_for_connection_event();
// 也就是说,一个新的连接真正开始执行是从 process_new_connection 开始的
if (channel_info != nullptr) mgr->process_new_connection(channel_info);
}
}
Channel_info
从上面的代码可以看到在收到连后,新的连接会被包装成一个 Channel_info 对象,下面我们来看一下这个对象里面有些什么属性。
Channel_info *Mysqld_socket_listener::listen_for_connection_event() {
// 连接时的一些其它的处理与检查
// ...
// 可以看到 Channel_info 就是对 socket 对象的包装
Channel_info *channel_info = nullptr;
if (listen_socket->m_socket_type == Socket_type::UNIX_SOCKET)
channel_info = new (std::nothrow) Channel_info_local_socket(connect_sock);
else
channel_info = new (std::nothrow) Channel_info_tcpip_socket(
connect_sock, (listen_socket->m_socket_interface ==
Socket_interface_type::ADMIN_INTERFACE));
if (channel_info == nullptr) {
(void)mysql_socket_shutdown(connect_sock, SHUT_RDWR);
(void)mysql_socket_close(connect_sock);
connection_errors_internal++;
return nullptr;
}
return channel_info;
}
Connection_handler_manager
void Connection_handler_manager::process_new_connection(
Channel_info *channel_info) {
if (connection_events_loop_aborted() ||
!check_and_incr_conn_count(channel_info->is_admin_connection())) {
channel_info->send_error_and_close_channel(ER_CON_COUNT_ERROR, 0, true);
delete channel_info;
return;
}
if (m_connection_handler->add_connection(channel_info)) {
inc_aborted_connects();
delete channel_info;
}
}