🗒️InnoDB 的 Redo Log

2023-3-9|2026-2-4
麦兜
麦兜
type
Post
status
Published
date
Mar 9, 2023
slug
summary
tags
数据库
InnoDB
category
学习思考
password
icon
mini-transaction 是内部更低级的概念,简称mtr,修改Page、新增Page等都需要写入Rodo log,用于Crash之后恢复。在全局有一个log_sys 对象,作为redo log元配置对应的结构是log0sys.hlog_tlog_sys 作为redo log的物理和逻辑(redo buffer)枢纽。
 
LSN(Log Sequeue Number):日志序号,初始值8704 按照实际写入的日志量加上占用的log block headerlog block trailer来计算。
SN(Sequeue Number):log buffer 写入位置。
LSN和SN之间的换算关系:

日志结构

notion image

事务流程

mini-transaction start

mini-transaction 结构
mtr.start() 方法初始化会把 m_log 初始化 new (&m_impl.m_memo) mtr_buf_t();

mini-transaction 数据插入

操作之前会获取各种锁。

mlog_open

首先标记 buf 数据已被修改 mtr m_impl.m_modifications = true;
获取 mtr_t.Impl.m_log 的指针。有可能会扩容。

mlog_write_initial_log_record_fast

m_log中写入typespace idpage no,并增加m_n_log_recs的数量。

mach_write_compressed

根据数字的具体大小,选择从1到4个字节记录整数,写入m_log

mlog_close

mini-transaction commit

 
commit 实际上是间接调用 Command.execute 方法,首先执行prepare_write(); 做写日志的准备,如果只生成一条redo log 会把Flag 设置 MLOG_SINGLE_REC_FLAG ,如果是多条会在尾部添加 MLOG_MULTI_REC_END 标志。MLOG_MULTI_REC_END 用于多条日志原子恢复。prepare_write();这个方法会返回redo log的大小。
 
  1. 如果prepare_write(); 返回的的长度大于0接下来调用log_buffer_reserve() 获取handle
    1. log_buffer_reserve() 首先提前计算插入redo bufferstart_snend_lsn 。(这是从MySQL 8.0开始,设计了一套无锁的写log机制。)
      算完start_snend_lsn 判断是否比buffer的limit大
      等待之前日志写入回收空间
      对于整个日志长度大于当前整个 redo log bufferredo log 需要Resize 设置 redo log buffer
  1. m_impl->m_log.for_each_block(write_log); 按块写入buffer
    1. 对m_log中的每一个 512 字节的 Block 调用mtr_write_log_t()(需要注意的是mtr_write_log_t()是运算符()的重载)
      • log_buffer_write() 调用 std::memcpy(ptr, str, len) 进行写入redo buffer 。
      • log_buffer_write_completed()更新log_t中的recent_written,即(start_lsnend_lsn)组成的list
      • add_dirty_blocks_to_flush_list() 假如产生了 redo log,则将数据页的newest_modification修改为end_lsn
      • 假如该 Block 是第一次被修改,就需要插入 Buffer Pool 的flush_list将涉及修改的数据页添加到 Buffer Pool 的flush_list(buf_flush_insert_into_flush_list()).(利用block->page.oldest_modification来判断是否为第一次修改)
       

log_flusher

通知log_flusher线程,log_flusher 线程会调fsync 将REDO刷盘,至此完成了REDO完整的写入过程。
默认情况下innodb_flush_log_at_trx_commit = 1,线程会block 等待需要等REDO完成刷盘。innodb_flush_log_at_trx_commit = 2,只REDO只写入系统Page Cache
 
[译] 去掉云计算和k8s —— 把应用迁移回本地InnoDB 的索引页结构
Loading...