slave IO流程之二:注冊slave請求和dump請求,ioslave
slave IO流程已經在http://www.cnblogs.com/onlyac/p/5815566.html中有介紹
這次我們要探索注冊slave請求和dump請求的報文格式和主要流程。
一、注冊slave請求
在slave IO連接完數據庫後,slave IO接著在主庫裡注冊自己,以便後續不需要提供slave IO登陸的信息如用戶名密碼等。
1.注冊slave請求的報文格式

![]()
1 1 [15] COM_REGISTER_SLAVE
2 4 server-id
3 1 slaves hostname length
4 string[$len] slaves hostname
5 1 slaves user len
6 string[$len] slaves user
7 1 slaves password len
8 string[$len] slaves password
9 2 slaves mysql-port
10 4 replication rank
11 4 master-id
View Code
(1)報文的類型COM_REGISTER_SLAVE
(2)slave服務器的id,該id唯一並且只能通過my.cnf配置文件改變
(3)slave主機名長度
(4)slave主機名
(5)slave在主庫登陸用戶名長度
(6)slave在主庫登陸用戶名
(7)slave在主庫登陸的密碼長度
(8)slave在主庫登陸的密碼
(9)slave的mysql端口
(10)(11)這兩個都是0,不用去關注
2.在register_slave_on_master中

![]()
1 int4store(pos, server_id); pos+= 4;
2 pos= net_store_data(pos, (uchar*) report_host, report_host_len);
3 pos= net_store_data(pos, (uchar*) report_user, report_user_len);
4 pos= net_store_data(pos, (uchar*) report_password, report_password_len);
5 int2store(pos, (uint16) report_port); pos+= 2;
6 /*
7 Fake rpl_recovery_rank, which was removed in BUG#13963,
8 so that this server can register itself on old servers,
9 see BUG#49259.
10 */
11 int4store(pos, /* rpl_recovery_rank */ 0); pos+= 4;
12 /* The master will fill in master_id */
13 int4store(pos, 0); pos+= 4;
View Code
這是除了第一個沒有的在1中的報文格式,然後通過simple_command發送出去。

![]()
1 #define simple_command(mysql, command, arg, length, skip_check) \
2 ((mysql)->methods \
3 ? (*(mysql)->methods->advanced_command)(mysql, command, 0, \
4 0, arg, length, skip_check, NULL) \
5 : (set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate), 1))
View Code
該函數指向cli_advanced_command。
(1)在li_advanced_command中
在通過函數net_write_command寫該報文

![]()
1 if (net_write_command(net,(uchar) command, header, header_length,
2 arg, arg_length))
3 {
4 DBUG_PRINT("error",("Can't send command to server. Error: %d",
5 socket_errno));
6 if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
7 {
8 set_mysql_error(mysql, CR_NET_PACKET_TOO_LARGE, unknown_sqlstate);
9 goto end;
10 }
11 end_server(mysql);
12 if (mysql_reconnect(mysql) || stmt_skip)
13 goto end;
14
15 MYSQL_TRACE(SEND_COMMAND, mysql, (command, header_length, arg_length, header, arg));
16 if (net_write_command(net,(uchar) command, header, header_length,
17 arg, arg_length))
18 {
19 set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
20 goto end;
21 }
22 }
View Code
(2)在net_write_command中

![]()
1 buff[4]=command; /* For first packet */
View Code
這個寫了該報文的類型,

![]()
1 if (length >= MAX_PACKET_LENGTH)
2 {
3 /* Take into account that we have the command in the first header */
4 len= MAX_PACKET_LENGTH - 1 - head_len;
5 do
6 {
7 int3store(buff, MAX_PACKET_LENGTH);
8 buff[3]= (uchar) net->pkt_nr++;
9 if (net_write_buff(net, buff, header_size) ||
10 net_write_buff(net, header, head_len) ||
11 net_write_buff(net, packet, len))
12 {
13 MYSQL_NET_WRITE_DONE(1);
14 DBUG_RETURN(1);
15 }
16 packet+= len;
17 length-= MAX_PACKET_LENGTH;
18 len= MAX_PACKET_LENGTH;
19 head_len= 0;
20 header_size= NET_HEADER_SIZE;
21 } while (length >= MAX_PACKET_LENGTH);
22 len=length; /* Data left to be written */
23 }
24 int3store(buff, static_cast<uint>(length));
25 buff[3]= (uchar) net->pkt_nr++;
26 rc= MY_TEST(net_write_buff(net, buff, header_size) ||
27 (head_len && net_write_buff(net, header, head_len)) ||
28 net_write_buff(net, packet, len) || net_flush(net));
View Code
這所以這樣寫是因為每個報文有個這樣頭

![]()
1 if (!skip_check)
2 {
3 result= ((mysql->packet_length= cli_safe_read_with_ok(mysql, 1, NULL)) ==
4 packet_error ? 1 : 0);
View Code
(3)mysql協議的公共報文頭部
每個報文都有一個這樣的頭,這是忘記在上一章講的

View Code
第一個是這個報文的長度(以字節為單位),第二個是這個報文的系列號,當然發送的內容原來就是一個報文,但是太長分成多個,第三個就是報文本身
對於超過16M的報文會這樣發送

View Code
二、dump請求
1.dump請求的報文格式
dump有兩種格式:COM_BINLOG_DUMP_GTID和COM_BINLOG_DUMP
在slave IO的情形下,一般會使用COM_BINLOG_DUMP
為此,在此僅僅介紹COM_BINLOG_DUMP的格式

![]()
1 1 [12] COM_BINLOG_DUMP
2 4 binlog-pos
3 2 flags
4 4 server-id
5 string[EOF] binlog-filename
View Code
(1)報文的類型COM_BINLOG_DUMP
(2)請求binlog的寫的位置
(3)一般為COM_BINLOG_DUMP_NO_BLOCK類型
(4)slave IO的所在服務器的服務器編號,和slave注冊協議中的那個一致
(5)當前需要讀的binlog文件名
2.在函數request_dump中

![]()
1 int4store(ptr_buffer, DBUG_EVALUATE_IF("request_master_log_pos_3", 3,
2 static_cast<uint32>(mi->get_master_log_pos())));
3 ptr_buffer+= ::BINLOG_POS_OLD_INFO_SIZE;
4 // See comment regarding binlog_flags above.
5 int2store(ptr_buffer, binlog_flags);
6 ptr_buffer+= ::BINLOG_FLAGS_INFO_SIZE;
7 int4store(ptr_buffer, server_id);
8 ptr_buffer+= ::BINLOG_SERVER_ID_INFO_SIZE;
9 memcpy(ptr_buffer, mi->get_master_log_name(), BINLOG_NAME_INFO_SIZE);
10 ptr_buffer+= BINLOG_NAME_INFO_SIZE;
11
12 command_size= ptr_buffer - command_buffer;
13 DBUG_ASSERT(command_size == (allocation_size - 1));
View Code
同樣地是COM_BINLOG_DUMP的格式。
這邊也使用simple_command(mysql, command, command_buffer, command_size, 1)寫入。