MySQL redo log 格式解析

本文简单介绍MySQL redo log 文件格式,本文涉及的MySQL 版本为8.0.20。

一、基础知识

1.1 字节序

在具体介绍redo log文件格式之前,先了解一下 InnoDB 数值类型的字节序,InnoDB采用大端字节序存储数值,这个与Binlog使用的小端字节序不同,举个例子,数值0x12345678,占用4个字节,不同的字节序其存储方式如下:

  • 大端字节序:12 34 56 78
  • 小端字节序:78 56 34 12

显然大端字节序更符合人的阅读习惯,然而目前使用广泛的x86架构CPU,比如Intel、AMD,都是小端字节序。

1.2 redo log 相关参数
  • innodb_log_files_in_group,redo log文件个数,默认值2,取值范围2~100。
  • innodb_log_file_size,单个redo log文件大小,默认值为48M,最小值4M,最大值为512G/innodb_log_files_in_group
  • innodb_log_buffer_size,redo log 内存缓存大小,默认值16M。
  • innodb_log_write_ahead_size,定义了预写入的大小,默认值8KB,最小值512B,最大值与页大小相同。
  • innodb_log_checksums,是否为redo log启用checksum校验。

二、redo log格式

2.1 redo log 整体格式

MySQL redo log,默认配置下有两个文件,分别是ib_logfile0和ib_logfile1,这两个文件有完全相同的格式。redo log 文件最小单位是512字节的一个块,每个块的最后4个字节,存储这个块的checksum校验值。redo log 文件前4个块,也就是前2048个字节为文件头,文件头存储了redo log文件元数据信息和checkpoint信息。整体来看redo log文件格式如下:

   0 --------------------------------
            log file header block
512 ---------------------------------
            checkpoint block1
1024--------------------------------
            5.7保留,8.0用于加密
1536--------------------------------
            checkpoint block2
2048--------------------------------
            redo log record ...
xxxxx--------------------------------

块大小及文件头大小在源码中定义为:

#define OS_FILE_LOG_BLOCK_SIZE 512
constexpr uint32_t LOG_FILE_HDR_SIZE = 4 * OS_FILE_LOG_BLOCK_SIZE;

2.2 log file header block

log file header block,是redo log文件的第一个块,其结构如下:

0--------------------------------
            log_head_format
4---------------------------------
            未使用
8--------------------------------
            start_lsn
16--------------------------------
            log_head_creator
48--------------------------------
            未使用
508--------------------------------
            checksum
512--------------------------------
  • log_head_format,占用4个字节,redo log 格式版本号,当前最新版本号为4,如下:

    LOG_HEADER_FORMAT_5_7_9 = 1,
    LOG_HEADER_FORMAT_8_0_1 = 2,
    LOG_HEADER_FORMAT_8_0_3 = 3,
    LOG_HEADER_FORMAT_8_0_19 = 4,
    LOG_HEADER_FORMAT_CURRENT = LOG_HEADER_FORMAT_8_0_19

  • start_lsn,初始值为16*512,这个值在初始化及切换redo log 文件时写入
  • log_head_creator,占用32个字节,值为MySQL 8.0.20
  • checksum,该block块的checksum值

关于 log file header block 结构填充见源码函数:log_files_header_fill(),log0chkp.cc

2.3 checkpoint block

redo log 前4个块中,有两个checkpoint块,这两个checkpoint块有完全相同的结构,如下:

0--------------------------------
            checkpoint_no
8---------------------------------
            checkpoint_lsn
16--------------------------------
            lsn_offset
24--------------------------------
            innodb_log_buffer_size
32--------------------------------
            未使用
508--------------------------------
            checksum
512--------------------------------
  • checkpoint_no ,每次checkpoint完成后,递增1。
  • checkpoint_lsn,lsn值,崩溃恢复从这个位置开始。
  • lsn_offset,lsn在redo log文件内的偏移,通过函数log_files_real_offset_for_lsn()计算获得。
  • innodb_log_buffer_size,参数innodb_log_buffer_size的大小,官方文档也没有说明该字段有什么用。
  • checksum值,该block块的checksum值。

checkpoint 块相关函数:

  • log_create_first_checkpoint()
  • log_files_write_checkpoint()

注意:
虽然每个redo log文件都有相同的文件头结构(起始4个块),但是checkpoint的两个块,只有第一个redo log file(ib_logfile0)有效,其他redo log file 的checkpoint块填充0。在崩溃恢复时,也只读ib_logfile0文件的checkpoint信息。

2.4 redo log data block

redo log 文件前4个块以外的数据块,都是用于存储redo log 记录用的,称之为redo log data block,它们有相同的格式,如下:

0--------------------------------
            hdr_no
4---------------------------------
            data_len
6--------------------------------
            first_rec_group
8--------------------------------
            checkpoint_no
12--------------------------------
            data part
508--------------------------------
            checksum
512--------------------------------
  • hdr_no,占用4个字节,表示块号,值必须大于0,其最高位是flush标志位,设置为1,表示这个块已经刷到磁盘。最大允许的块号为:LOG_BLOCK_MAX_NO = 0x3FFFFFFFUL + 1;
  • data_len,占用2个字节,表示当前块写入的字节数,包括块头的12个字节。这2个字节的最高位用来存储当前块是否加密。
  • first_rec_group,占用2个字节,用来存储mtr log 第一个记录开始的偏移。如果这个值不为0,recover可以从这个偏移点开始解析日志。
  • checkpoint_no,占用4字节,当最新的log block被写入时的log_sys->next_checkpoint_no的低4字节。

发表评论