slave IO流程之二:注册slave请求和dump请求

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

posted @ 2016-08-29 14:54  Breeze0806  阅读(1018)  评论(0编辑  收藏  举报