關於MYSQL 5.7 新連線建立流程原始碼介面(和5.6不同)
原創 水平有限
今天在看運維內參第三章原始碼的時候,發現書上很多程式碼入口函式和我用的5.7.14的原始碼對不上,然後再看了一下5.6的原始碼,
書上寫的基本都是5.6的原始碼(書是2015年開始寫的)5.7.14在連線這一塊做了相當大的改動,加了很多抽象類,變得更加複雜了。
當然這也是軟體模組劃分的更加清晰的必然的結果,順便說一下MYSQL在UNIX上使用的select/poll 這種多路I/O轉接模型來監聽
客戶端的連線,監聽的只是讀操作,當客戶端發起連線的時候select/poll透過監聽LISTEN scoket上的是否有讀取資訊來判斷,是否
有新的連線到來,然後呼叫執行緒回撥函式建立新的執行緒來處理這個新的accpet的socket通道(還會判斷是否有空閒的執行緒佇列而不需要
新建立新的執行緒來處理),執行緒的建立我們說是比程式代價小很多,他沒有獨立的記憶體三區(共享區,程式碼段和堆記憶體),但是他也有PCB
有獨立的棧空間所以能節約一點是一點吧。
關於MYSQL的原始碼各種多型太多了,真是眼花繚亂
下面是我使用到一些斷點。
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000ebd333 in main(int, char**) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
breakpoint already hit 1 time
2 breakpoint keep y 0x00000000016e350d in inline_mysql_socket_accept(char const*, uint, PSI_socket_key, MYSQL_SOCKET, sockaddr*, socklen_t*) at /root/mysql5.7.14/percona-server-5.7.14-7/include/mysql/psi/mysql_socket.h:1110
breakpoint already hit 18 times
6 breakpoint keep y 0x0000000000f1b8d9 in Connection_handler_manager::process_new_connection(Channel_info*) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:289
breakpoint already hit 15 times
8 breakpoint keep y 0x00000000016e197f in handle_connection(void*) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_per_thread.cc:239
breakpoint already hit 6 times
9 breakpoint keep y 0x0000000000f1b1d5 in Connection_handler_manager::check_and_incr_conn_count(bool) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:105
breakpoint already hit 1 time
12 breakpoint keep y 0x00000000016e1f41 in Per_thread_connection_handler::add_connection(Channel_info*) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_per_thread.cc:399
下面按照呼叫流程解釋一下這幾個函式作用,希望幫到在5.7.14下使用GDB除錯MYSQL連線的同學一點幫助
1、不解釋主函式main
2、 inline_mysql_socket_accept
當然也就是sokcet accept返回新的socket檔案描述符的函式,因為找不到多路I/O轉接 select和poll的入口用了這招去找
找到多路I/O轉接介面變為了Channel_info* Mysqld_socket_listener::listen_for_connection_event()
Channel_info就是一個抽象類,這個函式會返回連線socket的相關資訊給 Channel_info這個基類指標。
又有多太發生了擦。
這裡貼出一點和運維內參同樣的程式碼,但是入口函式全部變了,而且除了邏輯相似,很多實現都變了
大量的用多型
棧幀
#0 inline_mysql_socket_accept (src_file=0x21c5f30 "/root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/socket_connection.cc", src_line=928, key=3, socket_listen=..., addr=0x7fffffffdc50, addr_len=0x7fffffffdcdc)
at /root/mysql5.7.14/percona-server-5.7.14-7/include/mysql/psi/mysql_socket.h:1110
#1 0x00000000016e4981 in Mysqld_socket_listener::listen_for_connection_event (this=0x2fca760) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/socket_connection.cc:928
#2 0x0000000000ecf016 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:66
#3 0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4 0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
6、Connection_handler_manager::process_new_connection,透過Channel_info指標指向的SCOKET資訊建立新執行緒
棧幀
#1 0x0000000000f1b9c6 in Connection_handler_manager::process_new_connection (this=0x2e98fc0, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:301
#2 0x0000000000ecf034 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:68
#3 0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4 0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
9、 Connection_handler_manager::check_and_incr_conn_count(bool)
這裡判斷MAX_CONNECTIONS是否合適這裡也和運維內參說的5.6的程式碼有了
很大的不同,但是邏輯一樣如下:
GDB如下:
(gdb) n
106 mysql_mutex_lock(&LOCK_connection_count);
(gdb) n
115 if (extra_port_connection)
(gdb) n
127 else if (connection_count > max_connections)
(gdb) P max_connections
$4 = 6
(gdb) p connection_count
$5 = 7
(gdb) n
129 connection_accepted= false;
(gdb) n
130 m_connection_errors_max_connection++;
(gdb) n
141 mysql_mutex_unlock(&LOCK_connection_count);
(gdb) n
142 return connection_accepted;
棧幀
#0 Connection_handler_manager::check_and_incr_conn_count (this=0x2e98fc0, extra_port_connection=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:105
#1 0x0000000000f1b904 in Connection_handler_manager::process_new_connection (this=0x2e98fc0, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:289
#2 0x0000000000ecf034 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:68
#3 0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4 0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
12、 Per_thread_connection_handler::add_connection(Channel_info*) 這個函式會判斷連線佇列是否有空閒的,如果沒有呼叫mysql_thread_create建立新的執行緒
擷取如下:
棧幀
#0 Per_thread_connection_handler::add_connection (this=0x2f67b10, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_per_thread.cc:399
#1 0x0000000000f1b9c6 in Connection_handler_manager::process_new_connection (this=0x2e98fc0, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:301
#2 0x0000000000ecf034 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:68
#3 0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4 0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
8、 handle_connection(void*) 這裡就是5.7.16真正的回撥函式用於建立執行緒,這裡就不解釋了,因為這裡只是分析流程,以後在詳細研究
這裡終於找到了建立執行緒的回撥函式,除錯有時候不知道入口函式名字也是一種悲劇
作者微信:
今天在看運維內參第三章原始碼的時候,發現書上很多程式碼入口函式和我用的5.7.14的原始碼對不上,然後再看了一下5.6的原始碼,
書上寫的基本都是5.6的原始碼(書是2015年開始寫的)5.7.14在連線這一塊做了相當大的改動,加了很多抽象類,變得更加複雜了。
當然這也是軟體模組劃分的更加清晰的必然的結果,順便說一下MYSQL在UNIX上使用的select/poll 這種多路I/O轉接模型來監聽
客戶端的連線,監聽的只是讀操作,當客戶端發起連線的時候select/poll透過監聽LISTEN scoket上的是否有讀取資訊來判斷,是否
有新的連線到來,然後呼叫執行緒回撥函式建立新的執行緒來處理這個新的accpet的socket通道(還會判斷是否有空閒的執行緒佇列而不需要
新建立新的執行緒來處理),執行緒的建立我們說是比程式代價小很多,他沒有獨立的記憶體三區(共享區,程式碼段和堆記憶體),但是他也有PCB
有獨立的棧空間所以能節約一點是一點吧。
關於MYSQL的原始碼各種多型太多了,真是眼花繚亂
下面是我使用到一些斷點。
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000ebd333 in main(int, char**) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
breakpoint already hit 1 time
2 breakpoint keep y 0x00000000016e350d in inline_mysql_socket_accept(char const*, uint, PSI_socket_key, MYSQL_SOCKET, sockaddr*, socklen_t*) at /root/mysql5.7.14/percona-server-5.7.14-7/include/mysql/psi/mysql_socket.h:1110
breakpoint already hit 18 times
6 breakpoint keep y 0x0000000000f1b8d9 in Connection_handler_manager::process_new_connection(Channel_info*) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:289
breakpoint already hit 15 times
8 breakpoint keep y 0x00000000016e197f in handle_connection(void*) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_per_thread.cc:239
breakpoint already hit 6 times
9 breakpoint keep y 0x0000000000f1b1d5 in Connection_handler_manager::check_and_incr_conn_count(bool) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:105
breakpoint already hit 1 time
12 breakpoint keep y 0x00000000016e1f41 in Per_thread_connection_handler::add_connection(Channel_info*) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_per_thread.cc:399
下面按照呼叫流程解釋一下這幾個函式作用,希望幫到在5.7.14下使用GDB除錯MYSQL連線的同學一點幫助
1、不解釋主函式main
2、 inline_mysql_socket_accept
當然也就是sokcet accept返回新的socket檔案描述符的函式,因為找不到多路I/O轉接 select和poll的入口用了這招去找
找到多路I/O轉接介面變為了Channel_info* Mysqld_socket_listener::listen_for_connection_event()
Channel_info就是一個抽象類,這個函式會返回連線socket的相關資訊給 Channel_info這個基類指標。
又有多太發生了擦。
這裡貼出一點和運維內參同樣的程式碼,但是入口函式全部變了,而且除了邏輯相似,很多實現都變了
大量的用多型
點選(此處)摺疊或開啟
-
#ifdef HAVE_POLL //多路I/O轉接判斷是否有寫連線到來
-
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
點選(此處)摺疊或開啟
-
#ifdef HAVE_POLL //多路I/O轉接判斷是否有寫連線到來
-
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
點選(此處)摺疊或開啟
-
for (uint retry= 0; retry < MAX_ACCEPT_RETRY; retry++) //重試次數MAX_ACCEPT_RETRY好像是10
-
{
-
socket_len_t length= sizeof(struct sockaddr_storage);
-
connect_sock= mysql_socket_accept(key_socket_client_connection, listen_sock,
-
(struct sockaddr *)(&cAddr), &length);//這裡沒什麼好說的返回新的sokcet檔案描述符了
-
if (mysql_socket_getfd(connect_sock) != INVALID_SOCKET ||//返回的新的socket檔案描述符無效(-1)
-
(socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN)) //如果是訊號中斷或者eagain重試沒關係再來
-
break;
- }
點選(此處)摺疊或開啟
-
Channel_info* channel_info= NULL;
- //注意下面有多型發生這裡和5.6很多不同了
-
if (is_unix_socket) //是否是本地UNIX_DOMAIN SOCKET
-
channel_info= new (std::nothrow) Channel_info_local_socket(connect_sock);
-
else//不是就是遠端TCP/IP SCOKET
-
channel_info= new (std::nothrow)
-
Channel_info_tcpip_socket(connect_sock,
-
(mysql_socket_getfd(listen_sock)
-
== m_extra_tcp_port_fd)); //根據connect_scok 建立channel_info
-
if (channel_info == NULL) //分配記憶體是否正常不正常搞下面的。
-
{
-
(void) mysql_socket_shutdown(connect_sock, SHUT_RDWR);
-
(void) mysql_socket_close(connect_sock);
-
connection_errors_internal++;
-
return NULL;
-
}
-
- return channel_info;
棧幀
#0 inline_mysql_socket_accept (src_file=0x21c5f30 "/root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/socket_connection.cc", src_line=928, key=3, socket_listen=..., addr=0x7fffffffdc50, addr_len=0x7fffffffdcdc)
at /root/mysql5.7.14/percona-server-5.7.14-7/include/mysql/psi/mysql_socket.h:1110
#1 0x00000000016e4981 in Mysqld_socket_listener::listen_for_connection_event (this=0x2fca760) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/socket_connection.cc:928
#2 0x0000000000ecf016 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:66
#3 0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4 0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
6、Connection_handler_manager::process_new_connection,透過Channel_info指標指向的SCOKET資訊建立新執行緒
棧幀
#1 0x0000000000f1b9c6 in Connection_handler_manager::process_new_connection (this=0x2e98fc0, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:301
#2 0x0000000000ecf034 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:68
#3 0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4 0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
9、 Connection_handler_manager::check_and_incr_conn_count(bool)
這裡判斷MAX_CONNECTIONS是否合適這裡也和運維內參說的5.6的程式碼有了
很大的不同,但是邏輯一樣如下:
點選(此處)摺疊或開啟
-
if (extra_port_connection)
-
{
-
if (extra_connection_count > extra_max_connections)
-
{
-
connection_accepted= false;
-
m_connection_errors_max_connection++;
-
}
-
else
-
{
-
++extra_connection_count;
-
}
-
}
-
else if (connection_count > max_connections)
-
{
-
connection_accepted= false;
-
m_connection_errors_max_connection++;
- }
(gdb) n
106 mysql_mutex_lock(&LOCK_connection_count);
(gdb) n
115 if (extra_port_connection)
(gdb) n
127 else if (connection_count > max_connections)
(gdb) P max_connections
$4 = 6
(gdb) p connection_count
$5 = 7
(gdb) n
129 connection_accepted= false;
(gdb) n
130 m_connection_errors_max_connection++;
(gdb) n
141 mysql_mutex_unlock(&LOCK_connection_count);
(gdb) n
142 return connection_accepted;
棧幀
#0 Connection_handler_manager::check_and_incr_conn_count (this=0x2e98fc0, extra_port_connection=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:105
#1 0x0000000000f1b904 in Connection_handler_manager::process_new_connection (this=0x2e98fc0, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:289
#2 0x0000000000ecf034 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:68
#3 0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4 0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
12、 Per_thread_connection_handler::add_connection(Channel_info*) 這個函式會判斷連線佇列是否有空閒的,如果沒有呼叫mysql_thread_create建立新的執行緒
擷取如下:
點選(此處)摺疊或開啟
-
if (!check_idle_thread_and_enqueue_connection(channel_info)) //判斷是否有空閒的連線隊裡
-
DBUG_RETURN(false);
-
/*
-
There are no idle threads avaliable to take up the new
-
connection. Create a new thread to handle the connection
-
*/
-
error= mysql_thread_create(key_thread_one_connection, &id, //建立新的執行緒對接
-
&connection_attrib,
-
handle_connection,
- (void*) channel_info);
#0 Per_thread_connection_handler::add_connection (this=0x2f67b10, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_per_thread.cc:399
#1 0x0000000000f1b9c6 in Connection_handler_manager::process_new_connection (this=0x2e98fc0, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:301
#2 0x0000000000ecf034 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:68
#3 0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4 0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
8、 handle_connection(void*) 這裡就是5.7.16真正的回撥函式用於建立執行緒,這裡就不解釋了,因為這裡只是分析流程,以後在詳細研究
這裡終於找到了建立執行緒的回撥函式,除錯有時候不知道入口函式名字也是一種悲劇
作者微信:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-2140043/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL 5.6原始碼編譯安裝流程MySql原始碼編譯
- 【MySQL】Linux下MySQL 5.5、5.6和5.7的RPM、二進位制和原始碼安裝MySqlLinux原始碼
- MySQL 5.7配置SSL連線MySql
- MySQL:5.6 升級 5.7MySql
- mysql5.7 ssl加密連線MySql加密
- CentOS tengine mysql 5.7 php 5.6CentOSMySqlPHP
- 關於Mysql5.7高版本group by新特性報錯MySql
- 關於mysql連線慢的分析.MySql
- 關於mysql連線的問題MySql
- MySQL 5.6, 5.7, 8.0版本的新特性彙總大全MySql
- php 5.6原始碼安裝流程(CentOS 6.5)PHP原始碼CentOS
- WebSocket:從建立連線到關閉的完整流程Web
- 06 建立MySQL連線MySql
- Mysql關於長連線短連線優劣比較MySql
- OkHttp 原始碼剖析系列(四)——連線建立概述HTTP原始碼
- 關於 Homestead 連線 MySQL 問題MySql
- ? 抓包分析 TCP 建立和斷開連線的流程TCP
- MySQL 5.7關於日期和時間的函式整理MySql函式
- centos7 mysql5.6升級5.7CentOSMySql
- MySQL最優配置模板( 5.6&5.7轉)MySql
- Windows下Mysql5.6升級到5.7WindowsMySql
- 關於mysql5.6 的排序問題.MySql排序
- MySQL 5.7新特性MySql
- MySQL 5.6 metadata lock 原始碼解讀MySql原始碼
- MySQL5.6 linux原始碼安裝MySqlLinux原始碼
- 基於Linux的MySQL5.7原始碼編譯安裝LinuxMySql原始碼編譯
- OkHttp 原始碼剖析系列(六)——連線複用機制及連線的建立HTTP原始碼
- [Oracle-> MySQL] Oracle通過dblink連線MySQL--Oracle 19c連線到MySQL 5.7OracleMySql
- MySQL 5.6,5.7的優化器對於count(*)的處理方式MySql優化
- 關於外連線和where條件
- Netty-新連線接入原始碼解讀Netty原始碼
- MySQL 5.7 新特性大全和未來展望MySql
- Linux下MySQL5.6原始碼安裝LinuxMySql原始碼
- 【JDBC】使用OracleDataSource建立連線池用於連線OracleJDBCOracle
- 關於weget “無法建立SSL連線”的解決方法
- 【Android原始碼】View的建立流程Android原始碼View
- netty原始碼分析之新連線接入全解析Netty原始碼
- mysql建立ssl安全連線的配置MySql