引言
前面幾節介紹了mysqld的初始化,接下來介紹連接的監聽和處理。重點掌握TCP、Unix域套接字和poll模型,進一步可自行了解epoll模型。本文重在代碼脈絡的梳理和知識點的提取,相關技術細節可自行加餐。
知識點
select/poll模型;TCP;Unix域套接字
源碼分析
網絡IO模型
從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);
到這裏就將進入解析器模塊,下一節再介紹。