前面几节介绍了mysqld的初始化,接下来介绍连接的监听和处理。重点掌握TCP、Unix域套接字和poll模型,进一步可自行了解epoll模型。本文重在代码脉络的梳理和知识点的提取,相关技术细节可自行加餐。
select/poll模型;TCP;Unix域套接字
从Mysqld_socket_listener::listen_for_connection_event()可以看出,MySQL网络IO采用了select/poll模型,如下:
#ifdef HAVE_POLL
int retval= poll(&m_poll_info.m_fds[0], m_socket_map.size(), -1);
#else
m_select_info.m_read_fds= m_select_info.m_client_fds;
int retval= select((int) m_select_info.m_max_used_connection,
&m_select_info.m_read_fds, 0, 0, 0);
#endif
poll模型主要解决了select的最大文件描述符限制,但不具备移植性,在Linux上有实现,Windows没有。MySQL在Linux上默认用的是poll,而Windows上则是select。
if (network_init())
unireg_abort(MYSQLD_ABORT_EXIT);
network_init()里重点关注下面语句:
mysqld_socket_acceptor->init_connection_acceptor()
这里初始化连接器,进一步跟踪:
TCP_socket tcp_socket(m_bind_addr_str, m_tcp_port,
m_backlog, m_port_timeout);
Unix_socket unix_socket(&m_unix_sockname, m_backlog);
可以看出,MySQL监听了Unix Socket和TCP连接,分别用于处理本机和远程客户端的连接。
在mysqld.cc主函数中,有个循环负责监听客户端连接,并创建线程处理。
mysqld_socket_acceptor->connection_event_loop();
connection_event_loop()核心部分如下:
while (!abort_loop)
{
Channel_info *channel_info= m_listener->listen_for_connection_event();
if (channel_info != NULL)
mgr->process_new_connection(channel_info);
}
listen_for_connection_event()监听连接事件,用poll监听客户端连接,有客户端请求时,用accept创建新socket。
int retval= poll(&m_poll_info.m_fds[0], m_socket_map.size(), -1);
connect_sock= mysql_socket_accept(key_socket_client_connection, listen_sock,
(struct sockaddr *)(&cAddr), &length);
process_new_connection里核心代码如下:
m_connection_handler->add_connection(channel_info)
继续跟踪进去,实际工作的是:
error= mysql_thread_create(key_thread_one_connection, &id,
&connection_attrib,
handle_connection,
(void*) channel_info);
其中handle_connection参数为线程处理函数,主要工作为初始化线程、构造THD对象、认证用户、循环处理命令、销毁连接。该函数里重点是循环处理命令:
while (thd_connection_alive(thd))
{
if (do_command(thd))
break;
}
do_command里需要分发命令,如下:
return_value= dispatch_command(thd, &com_data, command);
其中command参数是枚举类型,其取值范围如下:
enum enum_server_command
{
COM_SLEEP,
COM_QUIT,
COM_INIT_DB,
COM_QUERY,
COM_FIELD_LIST,
COM_CREATE_DB,
COM_DROP_DB,
COM_REFRESH,
COM_SHUTDOWN,
COM_STATISTICS,
COM_PROCESS_INFO,
COM_CONNECT,
COM_PROCESS_KILL,
COM_DEBUG,
COM_PING,
COM_TIME,
COM_DELAYED_INSERT,
COM_CHANGE_USER,
COM_BINLOG_DUMP,
COM_TABLE_DUMP,
COM_CONNECT_OUT,
COM_REGISTER_SLAVE,
COM_STMT_PREPARE,
COM_STMT_EXECUTE,
COM_STMT_SEND_LONG_DATA,
COM_STMT_CLOSE,
COM_STMT_RESET,
COM_SET_OPTION,
COM_STMT_FETCH,
COM_DAEMON,
COM_BINLOG_DUMP_GTID,
COM_RESET_CONNECTION,
COM_END
};
如果执行的是SELECT语句,则command为COM_QUERY。switch语句里走对应分支:
mysql_parse(thd, &parser_state);
到这里就将进入解析器模块,下一节再介绍。