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)寫入。