mysql write rows_MySQLbinlog日志04binlog日志字节码解析之二Write_Rows事件

本系列博客主要介绍MySQL数据库的binlog日志的相关内容,这个系列的主题包括:

前一篇博客介绍了

本篇博客将接着介绍Write Rows事件的字节码解析。

7.Write rows事件

现在来解析insert语句对应的核心binlog事件:Write rows事件。这个事件用于insert/update语句产生的增加和修改行数据的记录。每个Write rows事件只涉及对一行数据的增加或者修改,尽管这个事件的名字用了复数形式。

cbd71c788420a61036011efa474774f5.png

对应的字节码数据如下所示:

83c6d6528f1c9088d277fef834a5f835.png

common header的内容如下:

时间戳:

73f631acd80e37ef3f1d6627dac51253.png

字段

字节码

时间戳

8191a35b

2018-09-20 20:24:33

事件类型

1e

30

MySQL server-id

65000000

101

本事件的长度

3b000000

59

下一个事件的开始位置

5e140000

5214

标志

0000

0

Write rows事件的事件相关头结构格式还是从源代码注释中找到的,总体结构如下:

97b43e7ede77960b27216ceb6cfcaf18.png

各个条目细分后的具体含义如下:

条目

长度

事件

偏移

备注

表id

6

0

标志

2

6

var_header_len

2

8

附加行数据

取决于var_header_len的值

列的个数

2

8

N:packed integer

列标志

变长

INT((N + 7) / 8,每个列1个bit。

操作前列数据标志

变长

定位行数据用到的列:INSERT/DELETE

操作后列数据标志

变长

修改后的列:UPDATE,本例中没这部分。

行数据

变长

是否为NULL标志+列1的值+列2的值+...

Write rows事件自身的字节码数据如下:

02d66220f2feb7f54325e4ec697a1e02.png

表id占6个字节,值为120。

标志占2个字节,值为1。

var_header_len占2个字节,值为2字节。包含了自身的长度以及附加行数据的长度。因此这个事件中没有附加行数据。

接着是列的个数,这个整数的编码规则比较复杂。下面这个代码用于读取这样的列的个数的字节码。具体代码如下所示:

b81419057a86a2fa295029ca39c509f4.png

这个事件中第1个字节为06,因此列的数量就是6个列,仅仅占用1个字节。

接着是操作前的行记录用到的列的标志。对于INSERT语句而言,不包含这一部分。对于UPDATE/DELETE而言,就是mysqlbinlog输出的WHERE中用到哪些列。因此具体格式在操作后的部分进行描述。

接着是操作后的行记录用到的列的标志。长度是(6+7)/8=1个字节,值为ff,只有6个二进制位有效。可以看到这个6个字段都被使用到了。这1个字节仅仅是标志位,不是实际的列数据。对于INSERT语句而言,就是新增的记录数据中包含哪些列。对于UPDATE而言,就是SET中用到哪些列。

最后是真正的行记录的列数据。因为在common header中已经知道了整个事件的长度,而此时前面这些部分的长度也已经确定了,那么列数据的长度也可以计算出来。实际上就是分析到此时的偏移量开始,到事件结束位置的前1字节为止的这个范围内的字节码。

0f6648b747b0320bf92efbe108085605.png

列数据具体是怎么存储的,稍后介绍。

行数据先经过pack_row()函数进行组装后才写入到binlog文件中。pack_row()函数的代码经过精简后如下所示:

d0cc38b8fcdc847f1648092a9a7b8721.png

先存储NULL标记,即值为NULL的列标记,每个列用一个位来表示其后的值是否为NULL。

t1表只有6个列,因此这里值为NULL的列只可能占用1个字节。当前事件中这个值为0xc0。

最后6位全部是0,这6个列当前的值全部不为NULL。

3b7ca2af7c2a309fe6121c43ae538e87.png

接着依次存储每个值不是NULL的列的具体数据。

每一种类型的列都有对应的pack()函数。前面已经知道了t1表的6个列中,第2列(name)是varchar之外,其它列都是int。int类型的列在MySQL源代码中定义为Field_long类。

7dc73f4a7289d49f6d36209d09f9c026.png

功能主要就是这个32位整数存储为Big endian格式的字节码,占用4个字节。

varchar类型的列对应的类是Field_varstring。

86f117c539b11912f51ef73a1453a7f7.png

对于varstring,先存储字符串的长度,再存储实际的字符串。整数类型的列的存储方式和前面介绍的各种长度的存储方式是类似的,都可以认为是big-endian格式,而这里的字符串长度,是按照little-endian格式存储的。小于255字节,存储为1个字节,否则存储为2个字节。

现在来解析这个Write rows事件中包含的列的值,即行记录的具体数据。

472361d35acafd0d3f1d37c0894d7d85.png

字节码

NULL标记

c0

(11000000).6列的值均不为NULL

第1列

0200 0000

INT:2

第2列

024132

VARSTRING:A2

第3列

1500 0000

INT:21

第4列

1600 0000

INT:22

第5列

1700 0000

INT:23

第6列

1800 0000

INT:24

这个结果与使用mysqlbinlog提取的结果是一致的:

990847bf094383322f26fe53a6df1dd9.png

最后面4个字节是这个binlog事件的校验码。

至此,INSERT语句对应的Write row事件的字节码解析完毕。UPDATE和DELETE语句对应的binlog事件的字节码解析方式跟这个非常类似,就不再赘述了。

MySQL数据库binlog系列博客就是这些内容了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值