MySQL Binary Log

来源:互联网 发布:windows驱动开发培训 编辑:程序博客网 时间:2024/04/27 07:23

本文为自己学习时所写,翻译自https://dev.mysql.com/doc/internals/en/binary-log.html

Binary Log

  • Binary Log overview

MySQL binary log记录了MySQL server的数据修改操作。

大部分binary log的介绍都适用于replication server中relay log(中继日志),因为replay log的format和binary log一致。

Binary Log overview

Binary Log 是记录MySQL server数据修改记录的文件集合。可以通过–log-bin配置项启动server打开binlog功能。

Binary Log是在MySQL3.23.14中引入的,其包含了所有更新数据的statements。除非设置了基于行模式,否则同时会记录可能更新数据的statements(例如没有匹配到行的DELETE语句)。statements记录在描述更改操作的events中。同时记录了每条语句更新数据用了多长时间。

Binary Log同时记录了其他的metadata,包含有:

  • 用于保证正确复制statements的server状态记录。

  • Error Codes

  • 用于维护binary log自身的metatdata。(例如rotate events,切换日志文件的记录)。

Binary Log记录server工作期间整体的状态变化。其包含的events描述了这些状态改变。更准确的说,binary log events描述了用于复制在server上发生的变化。

Binary Log有两个重要的目的:

  • 用于复制。Binary Log用于记录master replication statements,然后发送到slave server。很多binary log格式和处理都是为了这个目的。master发送包含events的binary log到它的slaves,slaves会执行这些evenets做到和master上同样的数据变化。一个slave保存从master上拿到的events在它的replay log中直到这些被执行。replay log拥有和binary log相同的格式。

  • 数据恢复可以使用binary log。在backup保存后,恢复时在生成backup后的events被执行。这些events可以使database从backup点到最新状态。

有两种binary log的type。

  • 基于语句的。events包含了产生数据变化的SQL语句。(inserts,updates,deletes)。

  • 基于行的。events描述了独立行上的变化。

混合模式默认使用语句的,但在部分场景下自动切换到行模式。

基于行的(和混合模式)是从MySQL5.1引入。

mysqlbinlog工具可以用来以可读方式打印binary log和replay log。

High-Level Binary Log Structure and Contents

Binary Log 是记录MySQL server数据修改记录的文件集合。

  • 包含了binary log文件集合和index文件。

  • 每个文件包含了一个4字节的magic number,接着是描述数据改变的events集合。

  • 每个event包含了header bytes + data bytes:

    Header bytes提供了event的类型,什么时候产生,哪个server产生等等。

    Data bytes提供了对应类型event的细节,例如特定的数据变化。

    第一个event是一个描述性event,用来描述当前文件的格式版本(记录events的版本)。

    剩余的events是使用第一个event描述的版本解释。

    最后一个event是一个log-rotation event用来指定下一个binary log的文件名。

  • Index文件是一个描述当前binary log。

event的结构有发生变化,导致有不同版本的binary log格式。目前,有三种binary log的格式版本。

log文件用.NNNNNN后缀命名。index文件有.index的后缀。所有的文件都共享一个共同的basename。默认的binary log文件basename是‘HOSTNAME-bin’。binary log文件名如下:

...HOSTNAME-bin.0000101HOSTNAME-bin.0000102HOSTNAME-bin.0000103...HOSTNAME-bin.index

Relay log文件命名和binary log文件类似。默认的relay log文件名是‘HOSTNAME-relay’。relay log文件名如下:

...HOSTNAME-relay.0000101HOSTNAME-relay.0000102HOSTNAME-relay.0000103...HOSTNAME-relay.index

本章节描述了和binary log处理相关的MySQL 源码。

sql 目录。

  • log.h/log.cc:上层bianry log机制,用来管理events到一个队列形成binary log。用于创建、写、删binary log。

  • log_event.h/log_event.cc:底层binary log机制,用来序列化值到记录中。Log_event类和子类,用来创建、写、读取、打印、应用各种类型的events。该文件读取和写功能是底层的序列化工作。

  • rpl_constants.h :INCIDENT_EVENT 的事件类型。

  • slave.cc :包含了在replication slave中处理binary log的逻辑。

  • rpl_injector.h /rpl_injector.cc:包含了injector 类用来允许外部插入写到binary log。用在cluster replication binary记录。

  • rpl_record.h /rpl_record.cc:用来编解码表的行写入或读取row event的格式。

  • rpl_tblmap.h /rpl_tblmap.cc: 包含了数字到table的映射。这个映射用来行记录时标识tables。

  • rpl_utility.h /rpl_utility.cc:包含用于Table_map_events的辅助类和函数,同时有用于smart pointer的辅助类

  • sql_binlog.cc : 用来执行BINLOG的statements(msyqlbinlog在解析row events时候打印的base64-encoded值)。

  • sql_base.cc :函数 decide_logging_format()用来决定statements使用row-based或者statment-based格式写入binary log。

client directory:

  • mysqlbinlog.cc:mysqlbinlog工具用于读取binary log文件同时用文本格式展示。它和server共享了部分event解析代码。

Source File Archaeological Notes

log_event_old.h/log_event_old.cc(在MySQL 5.1.18及以上版本):用来读取和执行老版本的row log events:

  • Write_rows_log_event_old

  • Update_rows_log_event_old

  • Delete_rows_log_event_old

在5.1.17前,这些类为:

  • Write_rows_log_event

  • Update_rows_log_event

  • Delete_rows_log_event

Generating Browsable Binary Log Information

可以使用doxygen生成代码文档。

Event Classes and Types

server使用c++类来表示binary log events。原型在log_event.h中,这些类的方法在log_event.cc中。

Log_event是基类。其他更多特定event的子类是从Log_event继承。类型的代码是和子类关联在一起,因为类的实例是写到binary log、relay log或者从master发送到slave。在这些场景中,event只是一个字节序列,不是一个类结构,因此类型代码需要能够从字节序列中识别出event type。

Event的字节序列有头部分和数据部分。类型的代码出现在每一个event的头部分。

在Log_event_type枚举中可能的event type代码有:

enum Log_event_type {  UNKNOWN_EVENT= 0,  START_EVENT_V3= 1,  QUERY_EVENT= 2,  STOP_EVENT= 3,  ROTATE_EVENT= 4,  INTVAR_EVENT= 5,  LOAD_EVENT= 6,  SLAVE_EVENT= 7,  CREATE_FILE_EVENT= 8,  APPEND_BLOCK_EVENT= 9,  EXEC_LOAD_EVENT= 10,  DELETE_FILE_EVENT= 11,  NEW_LOAD_EVENT= 12,  RAND_EVENT= 13,  USER_VAR_EVENT= 14,  FORMAT_DESCRIPTION_EVENT= 15,  XID_EVENT= 16,  BEGIN_LOAD_QUERY_EVENT= 17,  EXECUTE_LOAD_QUERY_EVENT= 18,  TABLE_MAP_EVENT = 19,  PRE_GA_WRITE_ROWS_EVENT = 20,  PRE_GA_UPDATE_ROWS_EVENT = 21,  PRE_GA_DELETE_ROWS_EVENT = 22,  WRITE_ROWS_EVENT = 23,  UPDATE_ROWS_EVENT = 24,  DELETE_ROWS_EVENT = 25,  INCIDENT_EVENT= 26,  HEARTBEAT_LOG_EVENT= 27,  IGNORABLE_LOG_EVENT= 28,  ROWS_QUERY_LOG_EVENT= 29,  WRITE_ROWS_EVENT = 30,  UPDATE_ROWS_EVENT = 31,  DELETE_ROWS_EVENT = 32,  GTID_LOG_EVENT= 33,  ANONYMOUS_GTID_LOG_EVENT= 34,  PREVIOUS_GTIDS_LOG_EVENT= 35,  ENUM_END_EVENT  /* end marker */};

INTVAR_EVENT 类型有’subtypes’,在Int_event_type中枚举:

enum Int_event_type {  INVALID_INT_EVENT = LAST_INSERT_ID_EVENT = INSERT_ID_EVENT = 2};

下表总结了event类和类型。每一个类都继承自Log_event。从下面可以看到,大部分event都是只关联一个type:

  • 部分类没有关联任何type,因为他们只用作基类来派生子类,或者他们从不写到binary或relay log中,也不会从master发送到slave。例如:Log_event没有类型因为它仅用作基类。

  • 一个类可能关联多个type:Load_log_event 可能包含LOAD_EVENT 或者NEW_LOAD_EVENT。

https://dev.mysql.com/doc/internals/en/event-classes-and-types.html

Value Type Code Class Log_event
Base class for most other classes(基类) Muted_query_log_event
Added in 5.0.23
Removed in 6.0.4 Rows_log_event
Added in 5.1.5
Base class for Write_rows_log_event, Update_rows_log_event, Delete_rows_log_event(write/update/delete row event的基类) Old_rows_log_event
Added in 5.1.22
Base class for Write_rows_log_event_old, Update_rows_log_event_old, Delete_rows_log_event_old(write/update/delete row event的基类) 0 UNKNOWN_EVENT Unknown_log_event 1 START_EVENT_V3 Start_log_event_v3
Renamed from START_EVENT/Start_log_event in 5.0.0(在5.0.0中从START_EVENT/Start_log_event 重命名)
Base class for Format_description_log_event(Format_description_log_event基类) 2 QUERY_EVENT Query_log_event
Base class for Execute_load_query_log_event(Execute_load_query_log_event的基类) 3 STOP_EVENT Stop_log_event 4 ROTATE_EVENT Rotate_log_event 5 INTVAR_EVENT Intvar_log_event 6 LOAD_EVENT Load_log_event
Base class for Create_file_log_event(Create_file_log_event的基类) 7 SLAVE_EVENT Slave_log_event
Added in 4.0.0 8 CREATE_FILE_EVENT Create_file_log_event
Added in 4.0.0
Derived from Load_log_event(继承自Load_log_event) 9 APPEND_BLOCK_EVENT Append_block_log_event
Added in 4.0.0
Base class for Begin_load_query_log_event(Begin_load_query_log_event基类) 10 EXEC_LOAD_EVENT Execute_load_log_event
Added in 4.0.0 11 DELETE_FILE_EVENT Delete_file_log_event
Added in 4.0.0 12 NEW_LOAD_EVENT Load_log_event (same with LOG_EVENT type code)
Added in 4.0.0 13 RAND_EVENT Rand_log_event
Added in 4.0.5 14 USER_VAR_EVENT User_var_log_event
Added in 4.1.0 15 FORMAT_DESCRIPTION_EVENT Format_description_log_event
Added in 5.0.0
Derived from Start_log_event_v3(继承自Start_log_event_v3) 16 XID_EVENT Xid_log_event
Added in 5.0.3 17 BEGIN_LOAD_QUERY_EVENT Begin_load_query_log_event
Added in 5.0.3
Derived from Append_block_log_event(继承自Append_block_log_event) 18 EXECUTE_LOAD_QUERY_EVENT Table_map_log_event
Added in 5.1.5 19 TABLE_MAP_EVENT Table_map_log_event
Added in 5.1.5 20 PRE_GA_WRITE_ROWS_EVENT Write_rows_log_event_old
Added in 5.1.5 as WRITE_ROWS_EVENT/Write_rows_log_event and derived from Rows_log_event(5.1.5作为WRITE_ROWS_EVENT添加,继承自Rows_log_event) 21 PRE_GA_UPDATE_ROWS_EVENT Update_rows_log_event_old
Added in 5.1.5 as UPDATE_ROWS_EVENT/Update_rows_log_event and derived from Rows_log_event(5.1.5作为UPDATE_ROWS_EVENT/Update_rows_log_event添加,继承自Rows_log_event) 22 PRE_GA_DELETE_ROWS_EVENT Delete_rows_log_event_old
Added in 5.1.5 as DELETE_ROWS_EVENT/Delete_rows_log_event and derived from Rows_log_event (5.1.5作为DELETE_ROWS_EVENT/Delete_rows_log_event,继承自Rows_log_event)
Renamed in 5.1.18 to PRE_GA_DELETE_ROWS_EVENT/Delete_rows_log_event_old and derived from Delete_rows_log_event(在5.1.18更名为PRE_GA_DELETE_ROWS_EVENT/Delete_rows_log_event_old,继承自Delete_rows_log_event)
As of 5.1.22, derived from Old_rows_log_event(自5.1.22,继承自Old_rows_log_event) 23 WRITE_ROWS_EVENT Write_rows_log_event
Derived from Rows_log_event(继承自Rows_log_event)
Renumbered in 5.1.18 from 20 to 23 (在5.1.18,value从20改为23) 24 UPDATE_ROWS_EVENT Update_rows_log_event
Derived from Rows_log_event(继承自Rows_log_event)
Renumbered in 5.1.18 from 21 to 24(在5.1.18,value从21改为24) 25 DELETE_ROWS_EVENT Delete_rows_log_event
Derived from Rows_log_event(继承自Rows_log_event)
Renumbered in 5.1.18 from 22 to 25(在5.1.18 value从22改为25) 26 INCIDENT_EVENT Incident_log_event
Added in 5.1.18 27 HEARTBEAT_LOG_EVENT Heartbeat_log_event
Added in 6.0.5

Event Class Archaeological Notes

START_EVENT_V3尽管名字中有“V3”,但是type code不仅代表“V3”,同时代表“V1”的start events。原本type code 1是START_EVENT表示“V1”。但后来,“V3”发展处后,type code 1被重用,标识重命名为START_EVENT_V3。start event V1和V3都用type code 1,尽管两个event的数据结构不同,也需要区分他们的内容。

一直到MySQL 5.1.17,event type codes从20到22关联的符号表和类如下所示:

Value Type Code Class 20 WRITE_ROWS_EVENT Write_rows_log_event 21 UPDATE_ROWS_EVENT Update_rows_log_event 22 DELETE_ROWS_EVENT Delete_rows_log_event

在5.1.18中,符号表和类重命名为:

Value Type Code Class 20 PRE_GA_WRITE_ROWS_EVENT Write_rows_log_event_old 21 PRE_GA_UPDATE_ROWS_EVENT Update_rows_log_event_old 22 PRE_GA_DELETE_ROWS_EVENT Delete_rows_log_event_old

同时在5.1.18中,原有的符号表使用不同的value,原有的类使用原来的命名重新实现:

Value Type Code Class 23 WRITE_ROWS_EVENT Write_rows_log_event 24 UPDATE_ROWS_EVENT Update_rows_log_event 25 DELETE_ROWS_EVENT Delete_rows_log_event

20到22的type code现在就被抛弃了,仅仅用在MySQL 5.1.5 to 5.1.17创建的binary log中。

EVENT MEANINGS

下面的描述总结了每一种event type的意义:

  • UNKNOWN_EVENT

    这种event type不应该出现。它从不会被写入到binary log中。如果一个从binary log中读取到的event不能被识别出来,那么它会被认为是UNKNOWN_EVENT。

  • START_EVENT_V3

    一个写在每一个binary log开头的描述性event。(在MySQL 4.0 到 4.1,这个event只写在server启动后写的第一个binary log文件中。)这个event用在MySQL3.23到4.1中,在MySQL5.0中被FORMAT_DESCRIPTION_EVENT取代。

  • QUERY_EVENT

    当更新语句结束时写入。

  • STOP_EVENT

    当mysqld stop时写入。

  • ROTATE_EVENT

    当mysqld切换到一个新的binray log文件时写入。这个发生在触发FLUSH LOGS语句或者当前的binary log非常大的时候。binary log的最大大小取决于max_binlog_size。

  • INTVAR_EVENT

    每次一个statement使用AUTO_INCREMENT列或者LAST_INSERT_ID函数的时候写入,先于该statement的其他events写入。这个只用在QUERY_EVENT前,不会用在基于行的日志写入。一个INTVAR_EVENT在event数据部分会写入subtype:

    • INSERT_ID_EVENT 表示用于在下一个statement中AUTO_INCREMENT列的。

    • LAST_INSERT_ID_EVENT 用于表示在下一个statement中有LAST_INSERT_ID函数的。

  • LOAD_EVENT

    用于LOAD DATA INFILE statment在MySQL 3.23中。

  • SLAVE_EVENT

    没有使用

  • CREATE_FILE_EVENT

    在MySQL 4.0和4.1中用于LOG DATA INFILE statement。

  • APPEND_BLOCK_EVENT

    在MySQL 4.0中用于LOG DATA INFILE statement。

  • EXEC_LOAD_EVENT

    在MySQL 4.0和4.1中用于LOG DATA INFILE statement。

  • NEW_LOAD_EVENT

    在MySQL 4.0和4.1中用于LOG DATA INFILE statement。

  • RAND_EVENT

    当一个statement使用 RAND()函数时候使用,在一个statement其他events前。标识下一个statement中用于RAND()产生一个随机数的随机种子。这个只用在QUERY_EVENT前,不会用在基于行的日志写入。

  • USER_VAR_EVENT

    当statement使用用户变量的时候写入,在一个statement其他events前。表示下一个statement使用用户变量的值。这个只用在QUERY_EVENT前,不会用在基于行的日志写入。

  • FORMAT_DESCRIPTION_EVENT

    在每一个binary log文件头写入的描述性event。这个是MySQL5.0开始使用,替换START_EVENT_V3。

  • XID_EVENT

    当一个事务对支持XA事务存储引擎的表做修改的时候用在事务commit时。普通的事务实现都是通过发送QUERY_EVENT包含BEGIN语句,同时发送QUERY_EVENT包含commit语句(或者ROLLBACK语句,如果事务回滚掉)。

  • BEGIN_LOAD_QUERY_EVENT

    从MySQL5.0开始用于LOG DATA INFILE statement。

  • EXECUTE_LOAD_QUERY_EVENT

    从MySQL5.0开始用于LOG DATA INFILE statement。

  • TABLE_MAP_EVENT

    在基于行的binary log中使用。这个event用在每个行操作event前。它将一个表定义映射到一个number,表的定义包含了database、table name和column定义。这个event的目的是当一个表在master和slave拥有不同定义的时候保证复制。属于同一个事务的行操作events可能分组到队列中,在这种情况下每个events分组都带有一个TABLE_MAP_EVENT作为开始:记录每一个在这个队列中用到的表。

  • PRE_GA_WRITE_ROWS_EVENT

    WRITE_ROWS_EVENT的废弃版本。

  • PRE_GA_UPDATE_ROWS_EVENT

    UPDATE_ROWS_EVENT的废弃版本。

  • PRE_GA_DELETE_ROWS_EVENT

    DELETE_ROWS_EVENT的废弃版本。

  • WRITE_ROWS_EVENT

    基于行的binary log中使用。用来记录单表行的插入。

  • UPDATE_ROWS_EVENT

    基于行的binary log使用。用来记录单表行的更新。

  • DELETE_ROWS_EVENT

    基于行的binary log使用。用来记录单表行的删除。

  • INCIDENT_EVENT

    用来记录发生在master上的非普通event。它可以通知slave在master上发生了可能会导致数据变为不一致状态的事情。

  • HEARTBEAT_LOG_EVENT

    master发送给slave用来让slave知道master保持alive。不写入到log文件中。

Event Structure

这部分描述了写入到binary或replay log文件中events的通用属性。

所有的events有公用的通用的数据结构包含了event header,然后是event data。

+===================+| event header      |+===================+| event data        |+===================+

随着时间变化header和data部分的发展细节如下,这些衍生出了binary log的不同版本格式:

  • v1 :在MySQL 3.23中使用

  • v3 :在MySQL 4.0.2 到4.1使用

  • v4 :在MySQL 5.0及以上使用。

v2版本只有短暂的使用,在MySQL 4.0.x版本中,它被放弃同时不再支持。

在不同的binary log版本中一些event数据结构的细节是没有变化的,还有一些细节依赖版本。在任意版本中,不同event类型是data部分变化。

log文件中的第一个event比较特殊。它是一个描述性event提供binary log的版本和server 版本信息。描述性event的信息允许程序决定这个文件中binary log格式的版本,这样文件中剩余的events能够准确读取和解释。

对于最初的这个描述性event的细节和如何通过它来确定binary log格式,参考 Binary Log Versions。对于其他类型的event,参考Event Data for Specific Event Types。

下面的event图包含了使用下面这些约束的字段描述:

  • 一个字段有用来描述字段内容的名字。

  • 名字后面跟着的是两个数字 offset : length。offset是0开始的偏移位置,表示字段在event中的偏移。length表示字段长度。两个值都以字节方式给出。

整个event的结构在不同的版本中如下所示。后面的章节会对header和data做更详细的描述。

v1 event structrue:

+=====================================+| event  | timestamp         0 : 4    || header +----------------------------+|        | type_code         4 : 1    ||        +----------------------------+|        | server_id         5 : 4    ||        +----------------------------+|        | event_length      9 : 4    |+=====================================+| event  | fixed part       13 : y    || data   +----------------------------+|        | variable part              |+=====================================+

header length = 13 bytes

data length = (event_length - 13) bytes

y是和event type相关的。

v3 event structure:

+=====================================+| event  | timestamp         0 : 4    || header +----------------------------+|        | type_code         4 : 1    ||        +----------------------------+|        | server_id         5 : 4    ||        +----------------------------+|        | event_length      9 : 4    ||        +----------------------------+|        | next_position    13 : 4    ||        +----------------------------+|        | flags            17 : 2    |+=====================================+| event  | fixed part       19 : y    || data   +----------------------------+|        | variable part              |+=====================================+

header length = 19 bytes

data length = (event_length - 19) bytes

y是和event type相关的。

v4 event structure:

+=====================================+| event  | timestamp         0 : 4    || header +----------------------------+|        | type_code         4 : 1    ||        +----------------------------+|        | server_id         5 : 4    ||        +----------------------------+|        | event_length      9 : 4    ||        +----------------------------+|        | next_position    13 : 4    ||        +----------------------------+|        | flags            17 : 2    ||        +----------------------------+|        | extra_headers    19 : x-19 |+=====================================+| event  | fixed part        x : y    || data   +----------------------------+|        | variable part              |+=====================================+

header length = x bytes

data length = (event_length - x) bytes

fixed data length = y bytes variable data length = (event_length - (x + y)) bytes

x是通过格式描述event( format description event - FDE)中的header length字段来给定的。当前,x是19,因此extra_headers是空的。

y是和event type相关的,是通过FDE来给定。对于给定event type的event,fixed-part长度是相同的,但是不同event type可能会不同。

fixed part部分有时候称为’post-header’ part。variable part有时候称为’payload’或者说’body’。

对于如何利用FDE来解释v4的events,可以参考Binary Log Formats。

Event Content-Writing Conventions

Event contents是基于下面约束:

  • Number是使用小端模式写入(小的有效字节在前),除非指明了是其他方式。

  • 表示position或者length的值是用二进制字节方式给定,应该认为是无符号数。

  • 一些Number是用packed整数方式给定。稍后章节会描述一下这个格式。

  • Strings会用变化的format来写:

    • String有可能写入到一个fixed-length字段,然后再右端补充null(0x00)。

    • 一个变化长度的string可能会在前面放一个长度字段来指明string的长度。

    • 一些长度变化的string是以null结尾,但一些不是。对于独立string字段的描述会指明使用是哪种的情况。

    • 对于以NULL结尾前置length字段的string,length不包含结尾的NULL字节,除非特殊指明。

    • 如果一个长度变化的string在event结尾,同时没有length字段前置。那么它的长度可能是用event length减去其他字段的长度。

一些event使用 Packed Integer,一个对无符号数有效表示的特殊格式。一个Packed Integer可以存储8字节整数,但小的整数用1,3或4字节来存储。第一个字节的值决定了如何去读取这个数字,可以参考下面的这个表格:

Fisrt byte Format 0-250 第一个字节就是真实的值(0-250的范围)。没有额外的字节使用 252 还有两个字节要使用。number的范围是(251-0xffff) 253 还有三个字节要使用。number的范围是(0xffff-0xffffff) 254 还有8个字节要使用。值得范围是是(0xffffff-0xffffffffffffffff)

Packed Integer格式是继承自用在MySQL client/server网络协议中的”Length Coded Binary”表示方法(二进制协议)。这种表示方法允许第一个字节的251值用来表示SQL中的NULL值,但251在binary log中的Packed Integer没有使用。

Event Header Fields

Event flags

每一个event都从LOG_EVENT_HEADER_LEN大小的header开始。这个值在MySQL3.23中是13(v1),在MySQL4.0中是19(v3)。因为4.0把next position和flags字段添加到header,所以这个值变大。

  • v1: 13 bytes: timestamp + type code + server ID + event length

  • v3: 19 bytes: v1 fields + next position + flags

  • v4: 19 bytes or more: v3 fields + possibly other information

任何版本都是所有前面版本的超集:

  • v3和v4的前13个字节是和v1的前13个字节相同的。

  • v4的前19个字节是和v3相同的。

因为新的bianry log格式的event header是旧格式,因此不同版本的header是向后兼容的。

v1 event header:

+============================+| timestamp         0 : 4    |+----------------------------+| type_code         4 : 1    |+----------------------------+| server_id         5 : 4    |+----------------------------+| event_length      9 : 4    |+============================+

v1 header的13字节同时在后续的哥哥binary log版本中。

v3 event header:

+============================+| timestamp         0 : 4    |+----------------------------+| type_code         4 : 1    |+----------------------------+| server_id         5 : 4    |+----------------------------+| event_length      9 : 4    |+----------------------------+| next_position    13 : 4    |+----------------------------+| flags            17 : 2    |+============================+

与v1相比,v3添加了两个额外的字段,一共19个字节。

v4 event header:

+============================+| timestamp         0 : 4    |+----------------------------+| type_code         4 : 1    |+----------------------------+| server_id         5 : 4    |+----------------------------+| event_length      9 : 4    |+----------------------------+| next_position    13 : 4    |+----------------------------+| flags            17 : 2    |+----------------------------+| extra_headers    19 : x-19 |+============================+

v4的格式办好了一个extra_headers字段,用来添加额外的字段到header,而不需要破坏原有的格式。这个扩展的机制是通过FDE(FORMAT_DESCRIPTION_EVENT)来实现。当前x=19,因此extra_headers是空的。v4和v3相同。

NOTE: extra_headers字段并不出现在FORMAT_DESCRIPTION_EVENT或者ROTATE_EVENT header中。

在event header中的几个字段偏移在log_event.h中都是常量:

  • EVENT_TYPE_OFFSET = 4

  • SERVER_ID_OFFSET = 5

  • EVENT_LEN_OFFSET = 9

  • LOG_POS_OFFSET = 13

  • FLAGS_OFFSET = 17

头字段包含了一下信息:

  • timestamp

4字节。statement开始执行的时间。用从19070(UTC)的秒数表示,像SQL的TIMESTAMP类型。

  • type_code

1字节。event的type。1表示START_EVENT_V3,2表示QUERY_EVENT,等等。这些数字定义在log_event.h的enum Log_event_type枚举中。

  • server_id

4字节。最初创建event的mysqld server的ID。这个ID是来自server配置文件中用于replication的配置选项。Server ID可以避免circular replication使用时候死循环(使用选项–log-slave-updates)。假设M1, M2,M3的server ID值分别是1,2,3。它们是环状复制。M1是M2的master,M2是M3的master,M3是M1的master。master/server关系图如下:

M1---->M2 ^      | |      | +--M3<-+

拓展阅读:Circular Replication in MySQL

一个客户端发送INSERT到M1,它会在M1执行,写到它的binary log中,带有server ID为1的event。这个event会被发送到M2,在M2被执行并写入到它的binary log中。这个event依然是server ID为1。因为ID是最初创建event的server的。这个event被发送到M3,也会执行写入到binary log,依然是使用server ID 1。最终,event还会被发送到M1,M1看到server ID为1,就可以知道这个event是从自己发起的,因此这个event会被忽略。

  • event_length

4个字节。表示event的全部size,包含了header和data两部分。大部分event小于1000字节,除了使用LOAD DATA INFILE(event会包含loaded文件,因此他们可能会很大)。

  • next_position(没有在v1中)

4字节。表示在master binary log中下一个event的位置。这个格式在binlog和relay log中是不同的,依赖于server的版本(对于relay log,依赖于master的版本)。

  • 在master v3上的binlog:是到event开始的偏移量,从binlog开头开始数。换句话说,等价于在写入event前的tell()。因此binlog的第一个event的next_position = 4,对于events n和n+1,它保持了 next_position(n+1) = next_position(n) + event_length(n)。

  • 当master使用v1,v3 server上的replay log可能是0。

  • master使用v3,v3 server上的relay log:依然是在master上binlog文件到开始event的偏移量。

    slave的replay log可能会和master上的binlog不同,因此next_position可能和replay log开始的偏移量不同。但是如果event n和event n+1都是从一个master获取,那么它保持了next_position(n+1) = next_position(n) + event_length(n)。

  • 在v4 server上的binlog,是到event end的偏移量。换句话说,在写入event后,tell()函数的值。

    因此第一个event的nex_position= 4 + event_length,同时events n和n+1,保持 next_position(n+1) = next_position(n) + event_length(n+1)。

  • 在v4 server上的replay log;是在master binlog上到event结尾的偏移量。

    slave的replay log可能会和master binlog不同,因此next_position可能和replay log开始的偏移量不同。但是如果event n和event n+1都是从一个master获取,那么它保持了next_position(n+1) = next_position(n) + event_length(n+1)。

next_position在slave上用在两种情况:

  • 用于SHOW SLAVE STATUS,可以展示上一次执行event在master坐标系中的坐标。

  • 用于START SLAVE UNTIL MASTER_LOG_FILE=x, MASTER_LOG_POS=y,这样master坐标系可以使用。

在5.0及以上,next_position在mysqlbinglog和SHOW BINLOG EVENTS中被称为’end_log_pos’。在4.1中,next_position在mysqlbinlog中被称为“log_pos”,在SHOW BINLOG EVENTS被称为“orig_log_pos”。

  • flags(没有出现在v1格式中)

2个字节。在Event Flags中会描述可能的flag值。

  • extra_headers(在v1,v3的格式中没有出现)

可变大小。这个字段的大小取决于在binlog文件第一个event,FDE(FORMAT_DESCRIPTION_EVENT)。当前大小是0,因此这个字段还没有出现在任何event中。即使这个字段大小不再是0,这个字段也依然不会出现在FDE或者ROTATE_EVENT中。

Event Flags

Event Header在V3及以上版本中,包含了两个在位置FLAGS_OFFSET = 17的flag字节。除了本节的描述,在log_event.h中有这些flags的描述。

当前的event flags:

  • LOG_EVENT_BINLOG_IN_USE_F = 0x1(在5.0.3中新加)

    用来标识一个binary log文件是否被正确close。这个flag只有在FORMAT_DESCRIPTION_EVENT才有意义。这个标识在这个event写入到binary log文件中时候设置。当log文件关闭的时候,这个flag被清除(这是唯一一个,MySQL会修改已经写入到binary log中数据的情况)。

  • LOG_EVENT_THREAD_SPECIFIC_F = 0x4 (New in 4.1.0)

    只有被mysqlbinlog用到(不是被replication的代码),用来可以正确处理临时表的情况。mysqlbinlog用可读的方式展示binary log,因此用户可以反馈这些输出到mysql中(用命令行解释器),用来获得增量式备份恢复。但是如果bianry log是如下方式,有两个同时发生的线程使用同一个名字的临时表(因为临时表是创建线程可见,因此这种行为是允许的):

<thread id 1>CREATE TEMPORARY TABLE t (a INT);<thread id 2>CREATE TEMPORARY TABLE t (a INT);

在这种情况下,简单的传递到mysql将会导致’table t already exists’的报错。这就是使用到临时表的event需要记录这个flag的原因。这样mysqlbinlog就知道它需要先设置pseudo_thread_id 系统变量,如下:

SET PSEUDO_THREAD_ID=1;CREATE TEMPORARY TABLE t (a INT);SET PSEUDO_THREAD_ID=2;CREATE TEMPORARY TABLE t (a INT);

这样server在接收到这些statements后不会有语义混乱的情况。总打印SET PSEUDO_THREAD_ID,即使么有使用临时表,不会导致bug,但会使速度下降。

  • LOG_EVENT_SUPPRESS_USE_F = 0x8 (New in 4.1.7)

    在实际语句记录前不用产生USE语句。这个flag应该给不需要设置默认database来使执行正确的event,例如CREATE DATABASE或者DROP DATABASE。这个flag只能用在特殊情况,因为它引入一个对复制逻辑的行为有意义的变化,当有–binlog-do-db和–replicate-do-db配置项的时候。

  • LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F = 0x10 (New in 5.1.4)

    在这个event写入到binary log后,log中的table map版本会增加。

放弃的flags:

  • LOG_EVENT_TIME_F (自4.1.1放弃)。这个flag从没有用。

  • LOG_EVENT_FORCED_ROTATE_F (自4.1.1放弃)。这个flag在master的ROTATE_EVENT中设置,但是再没有使用。

这些在log_event.h中被注释掉,同时他们的值可以重用或者已经被重用。(可以看log_event.h中的相关注释得到更多注意事项)。

Event Data Fields (Event-Specific Information)

Event Data Field Notational Caveat(字段符号警告)

event数据部分依赖于event type:

  • 在v1和v3中,event type完全决定了数据格式

  • 在v4中,数据部分的解释依赖于event type和FDE(FORMAT_DESCRIPTION_EVENT)的信息。这是因为v4允许一个额外的字段定义在FDE中。在实际中这个额外的字段当前是空的。

event的数据部分包含了定长部分和可变长度的部分。这两个部分都有可能是空的,取决于event type。(例如:一个STOP_EVENT只包含了header部分,fixed和可变部分都是empty。)

event data部分的size是event size(该字段在header中)减去header size。fixed data部分是event type的一个映射。variable data部分是event size减去header size,再减去fixed data部分。

以下准则在binary log中的所有event都适用:

  • event data的fixed部分对于同一个给定event type的events是相同的。

  • event data的variable部分是可以在给定event type的events间是不同的。

对于不同events的event data fixed和variable部分的具体细节,可以参考Event Data for Specific Event Types。

event data的fixed部分在不同代码文件,工作日志,bug记录中使用不同的名字,你可以读到

  • 有时候称为’fixed data’ part

  • 有时候被称为’post-headers’ part。

  • 为了使符号有趣,有时候fixed data部分被引用为’event-specific headers’,作为data part的一部分使用header。一个体现这一符号的情况出现在log_event.h中,你可以发现LOG_EVENT_MINIMAL_HEADER_LEN被定义为19,然后以XXX_HEADER_LEN的格式添加其他符号用于不同event type。前面是event header的大小(总是19)。后者定义了指定event类型data part中固定的大小。例如,ROTATE_HEADER_LEN是8,因为ROTATE_HEADER_LEN有8个字节在fixed data part,用来指示下一个log文件中first event的位置。

event data部分的variable part也是有不同名字,例如’payload’或者’body’。

Binary Log Versions

Binary log文件格式有几个版本:

  • v1: Used in MySQL 3.23

  • v3: Used in MySQL 4.0.2 though 4.1

  • v4: Used in MySQL 5.0 and up

V2版本仅被短暂使用,在MySQL4.0.x早起版本,但它被放弃而且不再支持。

处理binary log的程序必须能够解释支持的binary log格式。这部分描述了server如何识别每一种格式用来表示binary log用的哪一种。mysqlbinlog使用相同的规则。

重要的常量:

  • START_EVENT_V3 = 1

  • FORMAT_DESCRIPTION_EVENT = 15

  • EVENT_TYPE_OFFSET = 4

  • EVENT_LEN_OFFSET = 9

  • ST_SERVER_VER_LEN = 50

一个binary log文件使用4字节magic number开始,跟着一个初始的描述event用来表示file格式。

  • 在v1和v3中,这个event称为’start event’。

  • 在v4中,它被称为’format description event’。

在其他地方你可能会看到两个types event用通用方式来引用。这里使用’descriptor event’作为通用称呼。

每一个binary log格式中descriptor event的header和data部分展示如下。这些使用event structure中同样的约束。

  • v1 start event (size = 69 bytes):
+=====================================+| event  | timestamp         0 : 4    || header +----------------------------+|        | type_code         4 : 1    | = START_EVENT_V3 = 1|        +----------------------------+|        | server_id         5 : 4    ||        +----------------------------+|        | event_length      9 : 4    | = 69+=====================================+| event  | binlog_version   13 : 2    | = 1| data   +----------------------------+|        | server_version   15 : 50   ||        +----------------------------+|        | create_timestamp 65 : 4    |+=====================================+
  • v3 start event (size = 75 bytes):
+=====================================+| event  | timestamp         0 : 4    || header +----------------------------+|        | type_code         4 : 1    | = START_EVENT_V3 = 1|        +----------------------------+|        | server_id         5 : 4    ||        +----------------------------+|        | event_length      9 : 4    | = 75|        +----------------------------+|        | next_position    13 : 4    ||        +----------------------------+|        | flags            17 : 2    |+=====================================+| event  | binlog_version   19 : 2    | = 3| data   +----------------------------+|        | server_version   21 : 50   ||        +----------------------------+|        | create_timestamp 71 : 4    |+=====================================+
  • v4 format description event (size ≥ 91 bytes; the size is 76 + the number of event types):
+=====================================+| event  | timestamp         0 : 4    || header +----------------------------+|        | type_code         4 : 1    | = FORMAT_DESCRIPTION_EVENT = 15|        +----------------------------+|        | server_id         5 : 4    ||        +----------------------------+|        | event_length      9 : 4    | >= 91|        +----------------------------+|        | next_position    13 : 4    ||        +----------------------------+|        | flags            17 : 2    |+=====================================+| event  | binlog_version   19 : 2    | = 4| data   +----------------------------+|        | server_version   21 : 50   ||        +----------------------------+|        | create_timestamp 71 : 4    ||        +----------------------------+|        | header_length    75 : 1    ||        +----------------------------+|        | post-header      76 : n    | = array of n bytes, one byte per event|        | lengths for all            |   type that the server knows about|        | event types                |+=====================================+

在所有的binary log版本中,descriptor event的event data部分都是用同样的字段开始。

  • binlog_version

    binary log版本号。

  • server_version

    string描述的server版本。

  • create_timestamp

    creation timestamp如果不知0,那么就是用秒表示的event创建时间。它表示binary log创建的时间。这个字段实际没有意义,如果非0,它是多余的,因为它和header的timestamp有同样的值。

    Note:在实际使用中,creation timestamp字段应该被考虑为将来使用的保留字段,程序不应该依赖这个值。这个字段可能在未来被用作其他用途。

v4 format descriptor event数据部分包含了两个额外的字段,可以来解释其他type的event。

  • header length

    event header的长度。这个值包含了extra header字段,因此这个header length - 19就是extra header字段的长度。

    目前在v4中,header length在offset 75的位置是19,意味着在其他events中没有extra header跟在flags字段后面。如果未来header length是一个大于19的值,那么x - 19 extra header字节的extra_headers字段就会出现在其他的events中。

    Note: FORMAT_DESCRIPTION_EVENT自身不会包含extra_headers字段。假设FDE有header_length字段在flags字段后,那么将会出现下面的问题:

    • value x是header_length 字段的值,在extra_headers字段后面。

    • 直到知道x的值,无法知道header_length字段的偏移量。

    换句话说用户需要知道x来找到header_length字段,但是用户无法知道x知道读取header_length字段(循环依赖)。这意味着由FDE提供的event扩展机制不能应用在FDE上,FDE不是可扩展的。

    • post-header lengths

    每一个event中fixed data部分的长度。这是一个为所有从START_EVENT_V3(type code 1)开始的event提供一个post-header长度数组。这个数组没有包含UNKNOWN_EVENT(type code 0)的长度。

Determining the Binary Log Version

对于给定的binary log文件,这部分内容描述了如何决定它写入的格式。

部分描述event格式的重要点有:

  • v1 header字段在所有版本中都存在。(v3和v4 header是从v1的header字段开始,添加了next_position和flags字段)

  • v3和v4 header包含了同样的fiels,数据部分v3和v4不同,v4 data部分能够扩展格式而不用修改header。

  • 可以通过读取两个字节的binlog版本来确定binary log版本,这两个字节的位置v1和v3/v4有所不同,分别是17和19。因此,需要决定第一个event是否代表v1格式的start event。

为了判断一个binary log文件的版本,使用下面的步骤:

(1)文件使用4字节magic number开始。跳过这4个自己获得这个文件的first event(在大部分时候是start event或者FORMAT_DESCRIPTION_EVENT)。

(2)从第一个event,读取两个值

  • event中EVENT_TYPE_OFFSET (4) 第一个字节 type code。

  • event中 EVENT_LEN_OFFSET (9)位置的4字节event length。

(3)如果type code不是START_EVENT_V3 或者FORMAT_DESCRIPTION_EVENT,那么这个文件版本是v3.(例外的情况本节后续描述)

(4)如果type code是START_EVENT_V3,检查event length,如果Length超过75,那么这个版本是v1,否则是v3。为什么是75,因为v3的start event有:

  • header (19 bytes)

  • binlog version (2 bytes)

  • server version (ST_SERVER_VER_LEN = 50 bytes)

  • timestamp (4 bytes)

计算这些字段得到19 + 2 + 50 + 4 = 75。

因此,如果一个event长度小于75,那么它一定是v1版本的文件,因为v1会有比v3短的first event。

(5)如果type code是FORMAT_DESCRIPTION_EVENT (15),那么这个版本是v4。

前面的步骤描述了通用的binary log版本识别准则。但是,一些例外情况需要做如下说明:

Exceptional Condition 1:在MySQL4.0和4.1中,在binary log文件中的初始event可能不是start event。这是因为server仅写了start event到第一个binary log文件中,server启动时候创建的。在随后的文件中,server写event type为ROTATE_EVENT的event到当前binary log文件的尾部,然后关闭,再开始写下一个文件,而不需要再次写入START EVENT。如果一个log file的其实不是START_EVENT_V3 或者FORMAT_DESCRIPTION_EVENT,那么可以假设这是一个v3文件,因为这个行为只发生在MySQL4.0和MySQL4.1中,而且所有的server版本都是使用v3格式。

Exceptional Condition 2:在MySQL5.1和5.2中,几个早期版本使用v4格式写binary log,但是和当前v4使用不同的event number。因此当FDE读取发现是v4版本后,仍然需要读取在position 21的string server version。如果version是上面有影响的version,那么event 重编号,把从这个文件中读取到的file重新编号到当前v4的event编号。

Ensuring Compatibility of Future Binary Log Versions

为了能够保证任何未来的binary log版本都能够被正确的理解,下面的准则必须遵守:

(a)binary log文件必须以descriptor event开始。

(b)descriptor event必须用v3 header(19个字节)。

(c)在header后的两个字节(在位置19)必须包含binary log版本的数值。

v1只保持了(a)。但是就像之前标识的,v1格式可以在文件的初始event中识别出来,通过START_EVENT_V3的type code和event length小于75。

v4的FORMAT_DESCRIPTION_EVENT设置的可以处理未来格式的升级。如有v4有一个同样分布的新的格式,但带有额外的字段在heaer和post-header中,可以使用FORMAT_DESCRIPTION_EVENT来正确的描述。实际上,v4理论上可以用不同格式的v4,都有不同(更大的)header length,甚至有不同数目的events。

当前的代码可以处理这些。即任意解析binary log,发现是要处理v4版本的代码,都是使用FDE中的header length(不同于在server代码中固定的那些length)。

Note:尽管v4版本events的header可能回大于19字节,FDE是个例外。它的头部会一直是19字节,满足向后兼容的需求。即,FDE(FORMAT_DESCRIPTION_EVENT)并不包含extra_headers字段。

Event Data for Specific Event Types

LOAD DATA INFILE Events

接下来的章节提供了每个event type中fixed和variable部分的细节。

LOAD DATA INFILE语句已经和几个不同的events关联。event内容在这个章节做了详细说明,同时LOAD DATA INFILE Events提供了过去那些events在什么时候被使用。

Start_log_event_v3/START_EVENT_V3

这个event在v1或者v3版本binary log文件的开头使用,可以参考Binary Log Versions来看它是如何使用的。

在MySQL4.0和4.1中,该类型event只卸载mysqld启动时候创建的第一个binary log文件中。后续创建的log文件(当用户发出FLUSH LOGS语句或者当前binary log文件变得太大的时候)是不包含这个event的。在MySQL5.0及以后,所有的binary log文件都会以FORMAT_DESCRIPTION_EVENT开始。

Fixed数据部分:

  • 2字节。Binary log版本。在MySQL3.23中是1,MySQL4.0、4.1中是3,(在MySQL5.0及以上,FORMAT_DESCRIPTION_EVENT用来替换START_EVENT_V3)。

  • 50字节。MySQL server的版本(例如:4.0.14-debug-log),在右侧会补上0x00字节。

  • 4字节。event创建时候的timestamp(是binary log创建的时间)。这个值是多余的,这个值是和timestamp字段中国的值一样的。

variable data部分:

  • empty

Query_log_event/QUERY_EVENT

Fixed data part:

  • 4字节。发起语句的thread ID。临时表的时候需要。这个也可以用来让DBA知道是哪个用户在master操作了什么。

  • 4字节。语句执行过程的耗时。只用来让DBA检查。

  • 1字节。语句执行时候默认database名字的长度。名字在后面展示,在variable data部分,这个在像 INSERT INTO t VALUES(1)这种没有写明database语句中是必须的,同时依赖使用USE语句选择的默认database。

  • 2字节。在master上执行语句产生的错误码。在include/mysqld_error.h中定义的Error code这里不意外着错误。什么样的语句会在binary log中有一个非0的错误码呢?这主要取决于在事务中使用非事务型的表。例如,一个语句INSERT … SELECT在插入1000行到MyISAM表中后失败(比如说有Key冲突),我们需要把这条语句写入到binary log中,因为它的确改变了MyISAM表。对于事务型的表,因为不会出现非0的error code(尽管可能会出现错误,例如链接被Ctrl-C中断)。slave会检查error code:在slave执行完语句后,它会比较自己的error code和log中的error code,如果它们不同,slave就会停止复制(除非设置了–slave-skip-errors 来忽略错误)。

  • 2字节(在v1,v3中没有)。status variable block的长度。

Variable part:

  • 0个或多个status variables(v1、v3中不存在)。每一个status variable包含了一个字节来标识存储的variable,然后跟着variable的值。值的格式取决于具体的variable,后面会描述。

  • 默认的database name(以null结尾)。

  • SQL statement。slave知道在variable part(长度在fixed data部分给出)中其他字段的长度,通过减法就可以知道statement的长度。

每一个在status variable block中的entry都有一个code和value,value的格式就像下面列表的描述。这个列表提供了每一个variable的基础信息,对于更多细节,参考log_event.h。

  • Q_FLAGS2_CODE = 0。一个4字节bit字段的值。这个变量只有在MySQL5.0中写入。

  • Q_SQL_MODE_CODE = 1。一个有8字节SQL mode的值。

  • Q_CATALOG_CODE = 2。元数据name的值:一个length字节,然后跟随多个字节,加上一个Null结尾字节。这个变量只有在MySQL5.0.0到5.0.3中有。在MySQL5.0.4中被Q_CATALOG_NZ_CODE替换,因为结尾的NULL是不需要的。

  • Q_AUTO_INCREMENT = 3。value有两个unsigned整数字节,代表auto_increment_increment和auto_increment_offset 两个系统变量。这个变量只有在auto_increment 大于1的时候才出现。

  • Q_CHARSET_CODE = 4。两个unsigned整数代表character_set_client,collation_connection和collation_server系统变量。

  • Q_TIME_ZONE_CODE = 5。time zone名字的值:一个长度字节跟着多个字节。这个variable只有在time zone string不是空的时候才会出现。

  • Q_CATALOG_NZ_CODE = 6。catalog name的值:一个length字节跟着多个字节。这个变量只有catalog name不是empty的时候会出现。

  • Q_LC_TIME_NAMES_CODE = 7。值是2个unsigned整数字节表示lc_time_names数字。这个variable只有在值不为0的时候出现(即不是en_US的时候)。

  • Q_CHARSET_DATABASE_CODE = 8。值是一个2字节unsigned整数代表collation_database系统变量。

  • Q_TABLE_MAP_FOR_UPDATE_CODE = 9。8字节表示table map需要通过multiple-table update语句更新的值。value的每一个bit表示一个table,如果一个table会被语句更新那么对应bit就会设置为1。

Table_map_for_update用来评估–replicate-do-table / –replicate-ignore-table过滤规则。

Stop_log_event/STOP_EVENT

Stop_log_event在以下场景中使用:

  • 当master shut down时候写该event到binary log。

  • slaveshut down的时候会写该event到replay log或者在执行RESET SLAVE语句时。

Fixed data part:

  • Empty

Variable data part:

  • Empty

Rotate_log_event/ROTATE_EVENT

当binary log文件超过size limit,ROTATE_EVENT会写入到文件末尾,指向下一个文件。这个event是用来使slave知道下一个要接收的binary log名。

ROTATE_EVENT由本地产生,然后在master上写入到binary log。它会在slave中当发生FLUSH LOGS和从master上接收到ROTATE_EVENT时候写入到relay log。对于后面的一种情况,将会有两个rotate events在不同server上产生。

部分情况下会存在结尾的log-rotation event没有发生。例如server crash。

Fixed data part:

  • 8字节。下一个log文件的第一个event位置。总是number 4(表示下一个event开始位置是在下一个binary log中的偏移量4字节的位置。)这个字段在v1版本中没有,可以假设值是4。

Variable data part:

  • 下一个binary log文件的名字。这个文件名不是null结尾的。它的长度是event size减去fixed parts size。

Intvar log event/INTVAR EVENT

Fixed data part:

  • Empty

Variable data part:

  • 1字节。表示变量类型的的值。LAST_INSERT_ID_EVENT = 1 or INSERT_ID_EVENT = 2。

  • 8字节。一个无符号整形数用来表示用于LAST_INSERT_ID()请求或者AUTO_INCREMENT列的值。

Load_log_event/LOAD_EVENT

这个event用于表示LOAD DATA INFILE语句,同时可以参考 LOAD DATA INFILE Events。LOAD_EVENT与NEW_LOAD_EVENT共享Load_log_event类型。主要的不同是LOAD_EVENT只允许单字符字段和行结束选项值,但NEW_LOAD_EVENT允许多字符值。

LOAD_EVENT没有文件ID或者data block在这个event中,因为slave会请求master传输data文件在event执行的时候。

这个event的格式相比其他event会更复杂,因为它包含了许多LOAD DATA INFILE语句信息。

Fixed data part:

  • 4字节。发出LOAD DATA INFILE语句的master线程ID。在临时表中会需要。这个同时让DBA知道哪个用户在master做了哪些事情。

  • 4字节。LOAD DATA INFILE执行使用的时间,单位是s。只用来帮助DBA得到信息。

  • 4字节。在文件beginning需要跳过的行。(取决于LOAD DATA INFILE中的IGNORE N LINES语句)

  • 1字节。要导入表名字的长度。

  • 1字节。包含该表的数据库名字的长度。

  • 4字节。需要导入的column数目。当要导入的column明确的在statement中指出的时候,值为非0。

variable data part:

  • 1字节。字段终止字符。(FIELDS TEMINATED BY 选项)。

  • 1字节。字段封闭字符。(FIELDS ENCLOSED BY 选项)。

  • 1字节。行结束字符。 (LINES TERMINATED BY option)

  • 1字节。行开始字符(LINES STARTING BY option)

  • 1字节。转义字符(FIELDS ESCAPED BY option)

  • 1字节。标识否个关键字是否在当前语句中。

    • DUMPFILE_FLAG = 0X1(unused;这个标识是一个笨拙的修补,因为它是用在SELECT … INTO OUTFILE,不是LOAD DATA INFILE)

    • OPT_ENCLOSED_FLAG = 0x2(FIELD OPTIONALLY ENCLOSED BY option)

    • REPLACE_FLAG = 0x4(LOAD DATA INFILE REPLACE)

    • IGNORE_FLAG = 0x8(LOAD DATA INFILE IGNORE)

  • 1字节。标识每一个field和line option是否为空。低5位是1标识着一个空option(长度为0)或者0以为这存在option(长度为1)。

    • FIELD_TERM_EMPTY = 0X1

    • ENCLOSED_EMPTY = 0x2

    • LINE_TERM_EMPTY = 0x4

    • LINE_START_EMPTY = 0x8

    • ESCAPED_EMPTY = 0x10

  • 1字节。要load的第一个column name的长度。

  • 1字节。要load的最后一个column name的长度。

  • 变化长度。要load的第一个column的name(null-terminated)。

  • 变化长度。要load的最后一个column的name(null-terminated)。

  • 变化长度。要load的table的name(null-terminated)。

  • 变化长度。包含表的database name的长度。(null-terminated)。

  • 变化长度。要load文件的名字。(master上的原始name,而不是在slave上创建的临时文件的name)。 data文件名的长度是event size减去所有其他部分的长度。

Note:因为该event仅允许单字符字段和行可选项的值,由此可以推测LOAD DATA INFILE语句如果任何option包含了多字符选项都不会正确的复制。

Slave_log_event/SLAVE_event

这个event永远不会写入,因此它不能存在binary log文件中。它用来做失效保护复制,一直没有被实现。

Create_file_log_event/CREATE_FILE_EVENT

这个event用来做LOAD DATA INFILE语句。可以参考LOAD DATA INFILE EVENTS。

这个event告诉slave创建临时文件,同时用第一个data blok填写。随后会有0个、1个或者多个APPEND_BLOCK_EVENT events添加block到这个临时文件。 EVEC_LOAD_EVENT告诉slave load临时表到table中,或者DELETE_FILE_EVENT 不要load,同时删除临时表。DELETE_FILE_EVENT发生在LOAD DATA到master失败的情况。在master上,我们在语句之前就开始写loaded blocks到binary log。如果因为一些原因有错误,必须要告诉slave放弃load。

这个event的格式对比其他的会更加复杂,因为它包含了LOAD DATA INFILE子语句。

Fixed data part:

  • 4字节。在master上发出LOAD DATA INFILE语句的线程ID。被临时表需要。这个同样对DBA知道谁在master上做了什么有效。

Variable data part:

  • 4字节。LOAD DATA INFILE执行使用的时间。给DBA监控使用。

  • 4字节。在文件头要跳过的行数(对应着LOAD DATA INFILE的IGNORE N LINES语句)。

  • 1字节。要load的table name的长度。

  • 1字节。包含table的database name的长度。

  • 4字节。要Load的column的数目(col_name,…)。只有当column在语句中是显示写出的才会是非0。

  • 4字节。data文件的ID。当在Master上同时有多个LOAD DATA INFILE语句并行发生时,这个ID是必须的。在并发场景下,binary log可能会混淆语句的events。ID解析了每个APPEND_BLOCK_EVENT中必须添加的文件,同时EXEC_LOAD_EVENT必须导入的文件和DELETE_FILE_EVENT要删除的。

  • 1字节。字段结束string的长度(FIELDS TERMINATED BY 选项)。

  • 变化长度。字段结束string。

  • 1字节。行结束string的长度(LINES TERMINATED BY选项)。

  • 变化长度。行结束string。

  • 1字节。行开始string的长度。

  • 变化长度。行开始string。

  • 1字节。转义string的长度(FIELDS ESCAPED BY选项)。

  • 变化长度。转义string。

  • 1字节。标识是否某个关键词在语句中展示。

    • DUMPFILE_FLAG = 0X1(unused;这个标识是一个笨拙的修补,因为它是用在SELECT … INTO OUTFILE,不是LOAD DATA INFILE)

    • OPT_ENCLOSED_FLAG = 0x2(FIELD OPTIONALLY ENCLOSED BY option)

    • REPLACE_FLAG = 0x4(LOAD DATA INFILE REPLACE)

    • IGNORE_FLAG = 0x8(LOAD DATA INFILE IGNORE)

  • 1字节。要load的第一个column name的长度。

  • 1字节。要load的最后一个column name的长度。

  • 变化长度。要load的第一个column的name(null-terminated)。

  • 变化长度。要load的最后一个column的name(null-terminated)。

  • 变化长度。要load的table的name(null-terminated)。

  • 变化长度。包含表的database name的长度。(null-terminated)。

  • 变化长度。要load文件的名字。(master上的原始name,而不是在slave上创建的临时文件的name)(null-terminated)。数据文件名的长度不是显示在这个event中的。但它是null-terminated,因此可以通过读取到null字节来获取长度信息。

  • 变化长度。要Load的原始数据块。如果文件大小超过一定阈值,就会有额外的APPEND_BLOCK_EVENT实例,每一个都包含data block。原始数据的大小是event的大小减去其他部分的大小。

APPEND_BLOCK_LOG_EVENT/APPEND_BLOCK_EVENT

这个event用在LOAD DATA INFILE语句。同时可以参考LOAD DATA INFILE EVENTS。包含了用LOAD DATA INFILE语句写入到data file的数据。

Fixed data part:

  • 4字节。该block要添加到的文件ID。

variable data part:

  • 要Load的原始数据。原始数据大小是这个event大小减去所有fixed event部分的大小。

Execute_log_event/EXEC_LOAD_EVENT

这个event用在LOAD DATA INFILE语句。同时见LOAD DATA INFILE Events。

标识一个成功执行的LOAD DATA INFILE语句的结尾,和要load的data文件。

Fixed data part:

  • 4字节。要load的文件ID。

variable data part:

  • empty.

Delete_file_log_event/DELETE_FILE_EVENT

用在LOAD DATA INFILE语句的event。同时见LOAD DATA INFILE events。

标识没有成功执行的LOAD DATA INFILE语句的结束,同时data文件不应该被loaded。

Fixed data part:

  • 4字节。要删除文件的ID。

Variable data part:

  • empty。

Load_log_event/NEW_LOAD_event

这个event用于LOAD DATA INFILE 语句。同时参考LOAD DATA INFILE Events。

这个event的格式对比其他的会更加复杂,因为它包含了LOAD DATA INFILE子语句。

LOAD_EVENT与NEW_LOAD_EVENT共享Load_log_event类型。主要的不同是LOAD_EVENT只允许单字符字段和行结束选项值,但NEW_LOAD_EVENT允许多字符值。每一个都是length加上一个string,而不是进一个字符。因此,NEW_LOAD_DATA不需要标识每个选项是否empty的flag。

Fixed data part:

  • 4字节。发出LOAD DATA INFILE语句的master线程ID。在临时表中会需要。这个同时让DBA知道哪个用户在master做了哪些事情。

  • 4字节。LOAD DATA INFILE执行使用的时间,单位是s。只用来帮助DBA得到信息。

  • 4字节。在文件beginning需要跳过的行。(取决于LOAD DATA INFILE中的IGNORE N LINES语句)

  • 1字节。要导入表名字的长度。

  • 1字节。包含该表的数据库名字的长度。

  • 4字节。需要导入的column数目。当要导入的column明确的在statement中指出的时候,值为非0。

variable data part:

  • 1字节。字段终止字符。(FIELDS TEMINATED BY 选项)。

  • 1字节。字段封闭字符。(FIELDS ENCLOSED BY 选项)。

  • 1字节。行结束字符。 (LINES TERMINATED BY option)

  • 1字节。行开始字符(LINES STARTING BY option)

  • 1字节。转义字符(FIELDS ESCAPED BY option)

  • 1字节。标识否个关键字是否在当前语句中。

    • DUMPFILE_FLAG = 0X1(unused;这个标识是一个笨拙的修补,因为它是用在SELECT … INTO OUTFILE,不是LOAD DATA INFILE)

    • OPT_ENCLOSED_FLAG = 0x2(FIELD OPTIONALLY ENCLOSED BY option)

    • REPLACE_FLAG = 0x4(LOAD DATA INFILE REPLACE)

    • IGNORE_FLAG = 0x8(LOAD DATA INFILE IGNORE)

  • 1字节。要load的第一个column name的长度。

  • 1字节。要load的最后一个column name的长度。

  • 变化长度。要load的第一个column的name(null-terminated)。

  • 变化长度。要load的最后一个column的name(null-terminated)。

  • 变化长度。要load的table的name(null-terminated)。

  • 变化长度。包含表的database name的长度。(null-terminated)。

  • 变化长度。要load文件的名字。(master上的原始name,而不是在slave上创建的临时文件的name)。 data文件名的长度是event size减去所有其他部分的长度。

没有文件ID或者data block在variable data part。slave被假定为通过单独的链接从master拖取文件。

RANGE_LOG_EVENT/RAND_EVENT

RAND()在MySQL中产生一个随机数。一个RAND_EVENT包含了两个随机种子值,用来设置用来产生随机数的rand_seed1和rand_seed2系统变量。

Fixed data part:

  • Empty

variable data part:

  • 8字节。第一个随机种子值。

  • 8字节。第二个随机种子值。

User_var_log_event/USER_VAR_EVENT

Fixed data part:

  • Empty

variable data part:

  • 4字节。用户变量名的长度。

  • 用户变量名。

  • 1字节。如果变量值是SQL NULL值,就是非0。0的话,在该event中存在接下里的部分。

  • 1字节。用户变量类型。对应在include/mysql_com.h定义的enum Item_result元素值(STRING_RESULT=0, REAL_RESULT=1, INT_RESULT=2, ROW_RESULT=3, DECIMAL_RESULT=4)。

  • 4字节。用于用户变量的字符集数目(string变量需要),这个字符集数目是一个collation 数目用来表示字符集或者collation对。

  • 4字节。用户变量值的长度(对应着Item_string类的成员val_len)。

  • 变化长度。用于string变量时,即string。对于float或者integer变量,这里是8字节表示的值。对于decimal,这个是一个封装值:1字节用于精度,1个字节用于scale,同时$size -2个字节用于真实的值。可以参考strings/decimal.c中的decimal2bin函数来看封装值格式。

Format_description_log_event/FORMAT_DESCRIPTION_EVENT

这个event出现在v4 binary log文件的开头。可以看Binary Log Version来看它是如何使用的。

在MySQL5.0及以上,所有的binary log文件是通过FORMAT_DESCRIPTOIN_EVENT开始,但是有方法可以区分mysqld startup创建的FORMAT_DESCRIPTOIN_EVENT和其他FORMAT_DESCRIPTOIN_EVENT实例。这个区分是需要的,因为第一种FORMAT_DESCRIPTOIN_EVENT(意味着master已经started)回触发一些slave上的cleaning task(假设master 已经died然后重启,slave应该删除旧的复制到的临时表)。

Fixed data part:

  • 2字节。Binary log格式版本。在MySQL5.0及以上是4。

  • 50字节。MySQL server的版本,(例如5.0.14-debug-log),在尾部添加0x00字节。

  • 4字节。event创建的时间(单位s),这个时间是binary log创建的时间。这个值是多余的,和header字段timestamp是同一个值。

  • 1字节。header length。这个长度-19就是给定extra header字段的大小,在其他events的header中。

  • 变化长度。一个数组表示其他event类型的post-header长度。每一个event类型都有1个字节。

variable data part。

  • Empty。

Xid_log_event/XID_EVENT

一个XID event在修改了一个或多个支持XA事务存储引擎的transaction的commit时候产生。严格的讲,Xid_log_event是用来thd>transaction.xid_state.xid.get_my_xid()返回非空。

下面给出一个产生XID event(它放生在是否打开innodb_support_xa)。

CREATE TABLE t1 (a INT) ENGINE = INNODB;START TRANSACTION;INSERT INTO t1 VALUES (1);COMMIT;

Fixed data part:

  • Empty

Variable data part:

  • 8字节。XID事务编号。

Note:相比其他数字字段,XID事务编号不总是用小端格式来写的。这些字节是从内存到disk直接copy的,因此格式取决于机器。因此当replicationg从一个小端到一个大端机器(或者反过来)的时候,transaction number数字值会不同。这样mysqlbinlog输出不同。这不会导致replication不一致,因为主要的属性是不同transaction对应不同的transaction number就可以(相对顺序没有影响)。

Begin_load_query_log_event/BEGIN_LOAD_QUERY_EVENT

这个event用在LOAD DATA INFILE语句。

Fixed data part:

  • 4字节。data文件的ID。当在Master上同时有多个LOAD DATA INFILE语句并行发生时,这个ID是必须的。在并发场景下,binary log可能会混淆语句的events。ID解析了每个APPEND_BLOCK_EVENT中必须添加的文件,同时EXEC_LOAD_EVENT必须导入的文件和DELETE_FILE_EVENT要删除的。

Variable data part:

  • 变化长度。要Load的一个data块。这个大小是event size减去event中其他所有字段的大小。如果这个文件大小超出阈值,会有额外的APPEND_BLOCK_EVENT实例,每一个包含一个数据块。

Execute_load_query_log_event/EXECUTE_LOAD_QUERY_EVENT

这个event用在LOAD DATA INFILE语句中。见LOAD DATA INFILE Events。

表示LOAD DATA INFILE语句执行成功,同时data文件需要Load。它类似QUERY_EVENT,但是在执行的statement前,它使用slave端的临时文件名替换了语句中原本的文件名。Fixed data part中的前13个字节和QUERY_EVENT是类似的,是初始的状态变量在variable data part中。见event type的描述获得其他信息。

Fixed data part:

  • 4字节。发出语句线程的ID。

  • 4字节。语句执行使用的时间(单位s)。

  • 1字节。statement执行时候默认database name的长度。

  • 2字节。在master上执行语句的错误码。

  • 2字节。状态变量block的长度。

  • 4字节。要Load的文件的ID。

  • 4字节。语句中用于文件名替换的开始位置。

  • 4字节。语句中用于文件名替换的结束为止。

  • 1字节。如果处理冲突。LOAD_DUP_ERROR = 0, LOAD_DUP_IGNORE = 1, LOAD_DUP_REPLACE = 2

variable data part:

  • 0或者更多状态变量。每个状态变量包含一个字节标识存储的变量,跟着的是变量的值。

  • 变化的长度。数据库的名字(null-terminated)。

  • LOAD DATA INFILE语句。长度是event size减去所有其他字段的size。

Table_map_log_event/TABLE_MAP_EVENT

从MySQL5.1.5开始用于基于行的binary logging。

fixed data part:

  • 6字节。表ID。

  • 2字节。保留以后使用。

variable data part:

  • 1字节。database name的长度。

  • 变化长度。database name(null-terminated)。

  • 1字节。table name的长度。

  • 变化长度。table name(null-terminated)。

  • 封装的整数。表中的column数目。

  • 变化长度。column类型的数组,每个column一个字节。为了找到这些值的意义,可以见mysql_com.h头文件中的enum_field_types。

  • 封装的整数。mtadata block的长度。

  • 变化长度。meatadata block。见log_event.h见内容和格式。

  • 变化长度。位字段标识是否每个column可以为NULL,每一个bit代表一个column。对于这个字段,要存储N个columns总共要INT((N+7)/8)字节。

Write_rows_log_event_old/PRE_GA_WRITE_ROWS_EVENT

从MySQL5.1.5到5.1.17用于行模式,使用Write_rows_log_event/WRITE_ROWS_EVENT的之前实现方法。这个数据结构与新的event近似。

Update_rows_log_event_old/PRE_GA_UPDATE_ROWS_EVENT

从MySQL5.1.5到5.1.17用于行模式,使用Update_rows_log_event/UPDATE_ROWS_EVENT的之前实现方法。这个数据结构与新的event近似。

Delete_rows_log_event_old/PRE_GA_DELETE_ROWS_EVENT

从MySQL5.1.5到5.1.17用于行模式,使用Delete_rows_log_event/DELETE_ROWS_EVENT的之前实现方法。这个数据结构与新的event近似。

Write_rows_log_event/WRITE_ROWS_EVENT

从MySQL5.1.18开始使用。

[TODO:接下里的需要验证。当前属于猜测]

Fixed data part:

  • 6字节。Table ID。

  • 2字节。保留供未来使用。

variable data part:

  • 封装的整数。表中colums的数目。

  • 变化的长度。位字段用来标识每一个column是否被使用,每个column对应1位。对于这个字段,要存储N个columns总共要的INT((N+7)/8)字节。

  • 变化长度(只用于 UPDATE_ROWS_LOG_EVENT)。用位来表示每个column是否用在UPDATE_ROWS_LOG_EVENT之后;每个column对应一个位。对这个字段, 要存储N个columns总共要INT((N+7)/8)字节。

  • 变化长度。一个0或者多行的序列。结尾取决于event size。每一行有如下格式:

    • 变化长度。位字段表示行里面的每个field是否为NULL。只有columns在第二个字段中用到才会在这里列出。如果variable datea part第二个字段有N个bit,那么这个字段需要 INT((N+7)/8) bytes。

    • 变化长度。行镜像,包含所有表字段的值。这个只展示使用到的table lists(参考第二字段)同时非NULL(参考前一字段)。换句话说,在这里展示的值的数目等于在前一字段中等于0的位的数目(不包含Padding的字节)。

    每一个值是在log_event.cc中的 log_event_print_value() 函数描述。

    • 对于(UPDATE_ROWS_EVENT)前面两个字段是重复的,代表第二个table行数据。

对于每一行,下面的:

  • 对于WRITE_ROWS_LOG_EVENT,row-image描述插入行。

  • 对于DELETE_ROWS_LOG_EVENT,给定row-image的行是删除行。

  • 对于UPDATE_ROWS_LOG_EVENT,第一个row-image是移除行,第二个row-image是插入行。

Update_rows_log_event/UPDATE_ROWS_EVENT

从MySQL5.1.18开始使用,参考WRITE_ROW_EVENT的描述。

Delete_rows_log_event/DELETE_ROWS_EVENT

从MySQL5.1.18开始使用,参考WRITE_ROW_EVENT的描述。

Incident_log_event/INCIDENT_EVENT

Fixed data part:

  • 1字节。事件number.

  • 1字节。信息长度。

variable data part:

  • 事件信息,如果存在。

事件number在rpl_constant.h中展示。当前唯一被使用的是INCIDENT_LOST_EVENTS,哪个表示可能存在丢失events在复制流中,需要database做再同步。

Heartbeat_log_event/HEARTBEAT_LOG_EVENT

Heartbeat_log_event 是Master发给slave,使slave知道master的alive状态。这个类型的event不会出现在binary或者relay log中。他们是在master server上产生通过dump events线程,然后直接发送到slave不需要写入到binary log。slave检查event内容,然后不用写入到replay log。

Fixed data part:

  • empty

variable data part:

  • empty

Muted_query_log_event

这是QUERY_LOG_EVENT的子类不需要写入到log中。它用来刷事务而不用记录event。

这个event 类是在MySQL 5.0.23中加入,在6.0.4中移除。它是用来解决Bug#16206,但随着Bug#29020的解决而无意义。

0 0
原创粉丝点击