MySQLbinlog日志04binlog日志字节码解析之二Write_Rows事件

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

MySQLbinlog日志01binlog日志基本操作

MySQLbinlog日志02binlog日志用于数据恢复

MySQLbinlog日志03binlog日志字节码解析

MySQLbinlog日志04binlog日志字节码解析之二Write_Rows事件

前一篇博客介绍了

MySQLbinlog日志03binlog日志字节码解析

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

7.Write rows事件

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

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

common header的内容如下:

时间戳:


字段


字节码



时间戳


8191a35b


2018-09-20 20:24:33


事件类型


1e


30


MySQL server-id


65000000


101


本事件的长度


3b000000


59


下一个事件的开始位置


5e140000


5214


标志


0000


0

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

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


条目


长度


事件

偏移


备注


表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事件自身的字节码数据如下:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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



字节码



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提取的结果是一致的:

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

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

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

原文地址:https://www.cnblogs.com/coe2coe/p/9690708.html

时间: 2024-10-09 05:28:27

MySQLbinlog日志04binlog日志字节码解析之二Write_Rows事件的相关文章

MySQLbinlog日志03binlog日志字节码解析

本系列博客主要介绍MySQL数据库的binlog日志的相关内容,这个系列的主题包括: MySQLbinlog日志01binlog日志基本操作 MySQLbinlog日志02binlog日志用于数据恢复 MySQLbinlog日志03binlog日志字节码解析 MySQLbinlog日志04binlog日志字节码解析之二Write_Rows事件 本博客主要内容包括: binlog事件类型 binlog事件头部结构 binlog字节码分析的准备工作 binlog日志文件MAGIC代码 Format 

Log4Qt快速入门——Log4Qt日志输出重定向源码解析

Log4Qt快速入门--Log4Qt日志输出重定向源码解析 一.Appender简介 1.Appender简介 Appender是所有Appender的抽象类,是对记录日志形式的抽象.Log4Qt(Qt4版本)中Appender继承体系如下: 2.Appender接口 virtual Filter *filter() const = 0; virtual QString name() const = 0; virtual Layout *layout() const = 0; virtual b

Spring事务源码解析(二)获取增强

在上一篇文章@EnableTransactionManagement注解解析中,我们搭建了源码阅读的环境,以及解析了开启Spring事务功能的注解@EnableTransactionManagement的实现逻辑 在进行接下来的源码解析之前我想大家应该知道,当我们使用传统的jdbc应用事务的时候是不是做了如下操作: 开启事务 save.update.delete等操作 出现异常进行回滚 正常情况提交事务 而在Spring中我们好像只需要关心第三步,也就是我们的业务,而其他的操作都不需要关心.那么

JAVA字节码解析

Java字节码指令 Java 字节码指令及javap 使用说明 ### java字节码指令列表 字节码 助记符 指令含义 0x00 nop 什么都不做 0x01 aconst_null 将null推送至栈顶 0x02 iconst_m1 将int型-1推送至栈顶 0x03 iconst_0 将int型0推送至栈顶 0x04 iconst_1 将int型1推送至栈顶 0x05 iconst_2 将int型2推送至栈顶 0x06 iconst_3 将int型3推送至栈顶 0x07 iconst_4

SDWebImage源码解析(二)

源码来源: https://github.com/rs/SDWebImage 版本: 3.7 SDWebImage是一个开源的第三方库,它提供了UIImageView的一个分类,以支持从远程服务器下载并缓存图片的功能.它具有以下功能: 提供UIImageView的一个分类,以支持网络图片的加载与缓存管理 一个异步的图片加载器 一个异步的内存+磁盘图片缓存 支持GIF图片 支持WebP图片 后台图片解压缩处理 确保同一个URL的图片不被下载多次 确保虚假的URL不会被反复加载 确保下载及缓存时,主

RxJava2 源码解析(二)

转载请标明出处: http://blog.csdn.net/zxt0601/article/details/61637439 本文出自:[张旭童的博客](http://blog.csdn.net/zxt0601) 概述 承接上一篇RxJava2 源码解析(一), 本系列我们的目的: 知道源头(Observable)是如何将数据发送出去的. 知道终点(Observer)是如何接收到数据的. 何时将源头和终点关联起来的 知道线程调度是怎么实现的 知道操作符是怎么实现的 本篇计划讲解一下4,5. Rx

underscore.js源码解析(二)

前几天我对underscore.js的整体结构做了分析,今天我将针对underscore封装的方法进行具体的分析,代码的一些解释都写在了注释里,那么废话不多说进入今天的正文. 没看过上一篇的可以猛戳这里:underscore.js源码解析(一) underscore.js源码GitHub地址: https://github.com/jashkenas/underscore/blob/master/underscore.js 本文解析的underscore.js版本是1.8.3 _.each 1

OpenStack Neutron LoadBalance源码解析(二)

声明: 本博客欢迎转载,但请保留原作者信息,并请注明出处:http://write.blog.csdn.net/! 作者:林凯 团队:华为杭州OpenStack团队 在Neutron LoadBalance源码解析(一)中,我们已经了解租户在创建pool.member.healthmonitor和vip的时候,代码会调用HaproxyNSDriver中的create_xxx函数,那么当租户使用pool创建vip时,即代码调用HaproxyNSDriver中的create_vip函数时,Neutr

BroadcastReceiver源码解析(二)

广播注册部分见BroadcastReceiver源码解析(一) 4,BroadcastReceiver之源码分析 4.1,动态注册过程源码分析 在Activity中动态注册广播时,在注册方法之前其实省略了Context,也就是实际上调用的是Context. registerReceiver().Context是一个抽象类,它是Client端和AMS,WMS等系统服务进行通信的接口,Activity.Service和Application都是继承它的子类.Context的实现类是ContextIm