InnoDB之Undo log写入和恢复

news2025/7/17 0:37:11

1. 前言

为了实现事务的回滚和MVCC,InnoDB设计了Undo log模块,简单来说就是在修改记录前先记下日志,以便之后能将记录恢复成修改前的样子。针对insert、delete、update这三种不同的操作,InnoDB设计了不同类型的undo log,每个类型的undo log都有自己的格式,里面记录了撤销记录修改所必须的数据,InnoDB可以根据undo log将记录进行恢复。
和redo log一样,undo log也是要持久化到磁盘的,来看看InnoDB是如何存储undo log的吧。

2. FIL_PAGE_UNDO_LOG页

undo log和用户记录一样存在一个个页中,存储undo log的页面的类型是FIL_PAGE_UNDO_LOG,简称undo log页。
image.png
File Header和File Trailer是通用页结构了,不再赘述,重点关注Undo Page Header:
image.png

  • TRX_UNDO_PAGE_TYPE :页面存储的undo log种类。

undo log分为两大类,分别是TRX_UNDO_INSERTTRX_UNDO_UPDATE,前者代表记录的插入,后者代表记录的删除和更新。InnoDB规定两个大类的undo log不能混着存储在同一个页面。

insert类型的undo log事务提交后就没用了,可以直接释放。而update类型的undo log即使事务提交了,也不能立即释放,因为还要服务于MVCC。处理方式不同,自然分开存储要好一些。

  • TRX_UNDO_PAGE_START:第一条undo log在页面中的偏移量。
  • TRX_UNDO_PAGE_FREE:最后一条undo log结束时偏移量
  • TRX_UNDO_PAGE_NODE:List Node节点,用于将undo log页串联起来。

3. Undo log页链表

每对一条记录进行一次修改,都会对应1到2条undo log,一个事务可能会修改很多记录,也就会生成大量的undo log,如果一个undo log页装不下,就必须申请多个undo log页面,这些页面会串联成一条双向链表。
image.png
链表头节点页面被称为first undo page,其它页面称为normal undo page,它俩的区别是,first undo page除了存储undo log,还需要存储一些管理信息。

因为不同大类的undo log不能混着存储,所以一个事务必须有两条Undo log链表:insert undo链表和update undo链表。InnoDB又规定,对更新普通表产生的undo log与更新临时表产生的undo log也要分开存储,所以一个事务最多会分配4条undo log链表。
image.png
Undo log链表的分配策略是「按需分配」,为了节省资源,只有在用到时才会分配。如果一个事务没有对任何记录做修改,那么就不会分配Undo log链表。

4. Undo log写入

undo log是如何存储的?

4.1 Undo Log Segment Header

InnoDB规定每个 Undo页面链表都对应一个段 ,称之为Undo Log Segment,链表中的页面都是从段中申请的,所以链表里的first undo page存储了Undo Log Segment Header部分:
image.png

  • TRX_UNDO_STATE:链表状态。
    • TRX_UNDO_ACTIVE:活跃,有事务正在往里写undo log。
    • TRX_UNDO_CACHED:被缓存,链表等待被重用。
    • TRX_UNDO_TO_FREE:空闲,insert undo log事务提交后就处于这种状态。
    • TRX_UNDO_TO_PURGE:update undo log事务提交后不能被重用时处于这种状态。
    • TRX_UNDO_PREPARED:包含处于PREPARE阶段的事务产生的 undo log。
  • TRX_UNDO_LAST_LOG:链表中最后一个Undo Log Header的位置。
  • TRX_UNDO_FSEG_HEADER:链表所属段的Segment Header信息。
  • TRX_UNDO_PAGE_LIST:链表基节点。

4.2 Undo Log Header

事务往Undo log页面写日志的过程就是直接往里追加,页面写完了就再申请一个新的页面继续写。InnoDB规定,一个事务向一条Undo log链表写入的日志为一组,由于Undo log链表会被重用,所以可能存在一条链表里有多组Undo log,为了区隔开,InnoDB规定事务在写入一组undo log前,必须先写入一个Undo Log Header
image.png

  • TRX_UNDO_TRX_ID:生成本组undo log的事务id。
  • TRX_UNDO_TRX_NO:事务提交后的序号。
  • TRX_UNDO_DEL_MARKS:是否包含由于Delete mark 操作产生的undo log。
  • TRX_UNDO_LOG_START:第一条undo log的起始偏移量。
  • TRX_UNDO_XID_EXISTS:是否包含XID信息。
  • TRX_UNDO_DICT_TRANS:是否由DDL语句产生。
  • TRX_UNDO_TABLE_ID:DDL对应的表id。
  • TRX_UNDO_NEXT_LOG:下一组undo log的偏移量。
  • TRX_UNDO_PREV_LOG:上一组undo log的偏移量。
  • TRX_UNDO_HISTORY_NODE:History链表基节点。

综上所述,一条完整的的Undo log链表应该长这样:
image.png

4.3 重用Undo log页

一个事务只要修改了数据,最少会分配1条Undo log链表,每条链表最少包含一个Undo log页面,实际上大量的小事务仅仅修改了很少的数据,每开启一个事务就分配一条链表实在是有点浪费,所以InnoDB会尝试重用Undo log链表。
InnoDB规定,一条Undo log链表可以被重用,必须满足2个条件:

  • 链表中只包含一个Undo log页面。

如果链表有很多页面,那么重用的事务即使只写入少量日志,也得维护这些页面,这带来了另一种浪费。

  • 页面使用的空间小于3/4。

如果页面剩余空间不多,那么即使重用也意义不大。

对于insert undo链表和update undo链表,两者重用的策略也是不一样的。

  • insert undo log只要事务被提交,undo log就没用了,因此insert undo链表重用时可以直接重头开始写,把旧的undo log直接覆盖掉。
  • 而对于update undo链表,由于还需要服务于MVCC,因此不能直接覆盖,而是追加写入,这就会导致一个Undo log页面包含多组undo log。

image.png

5. 回滚段

一个事务最多分配4条Undo log链表,同一时刻可能有大量事务在并发执行,也就是会存在大量的Undo log链表,为了更好的管理这些链表,InnoDB设计了一个叫Rollback Segment Header的页面,这个页面有1024个Undo slot,用来存放每条Undo log链表的first undo page的页号。每个Rollback Segment Header页面都对应一个段,称为「回滚段」。
image.png

  • TRX_RSEG_MAX_SIZE:回滚段管理的最大Undo log页数量,默认0xFFFFFFFE
  • TRX_RSEG_HISTORY_SIZE:History链表占用的页面数量。
  • TRX_RSEG_HISTORY:History链表基节点。
  • TRX_RSEG_FSEG_HEADER:回滚段对应的Segment Header
  • TRX_RSEG_UNDO_SLOTS:1024个undo slot。

5.1 申请Undo log链表

一开始,回滚段中的1024个Undo slot都没有被分配,此时Undo slot被设置成一个特殊值FIL_NULL,十六进制是0xFFFFFFFF,代表Undo slot不指向任何Undo log页面。
此时开启一个事务更新数据,需要分配Undo log链表,从回滚段的第1个Undo slot开始遍历,如果不是FIL_NULL,则分配给当前事务,反之代表已经被其它事务占用,则往后继续寻找。
将Undo slot分配给当前事务后,需要在表空间新建一个Undo Log Segment,然后从中申请一个Undo log页面作为链表的first undo page,将该页面的页号写入到Undo slot,就算分配完成了。
如果回滚段里1024个Undo slot都名花有主了,MySQL就会报错:

Too many active concurrent transactions

事务提交后,Undo slot的处理方式:

  • 如果Undo slot指向的链表可以被重用,Undo slot会被加入到cached链表中,不同大类的Undo slot会被加入到不同的cached链表。一个回滚段会有两条cached链表,分别是insert undo cached链表和update undo cached链表。新事务分配Undo slot,优先从对应的cached链表中分配。
  • 如果Undo slot指向的链表不可以被重用
    • 如果指向的是insert undo链表,则链表的TRX_UNDO_STATE属性会被设为TRX_UNDO_TO_FREE,之后链表对应的段会被释放掉,Undo slot会被设为FIL_NULL
    • 如果指向的是update undo链表,则链表的TRX_UNDO_STATE属性会被设为TRX_UNDO_TO_PRUGE,并将Undo slot设为FIL_NULL,然后将本组undo log写入History链表。

5.2 多个回滚段

一个事务最多分配4条Undo log链表,一个回滚段只有1024个Undo slot,也就是说一个回滚段支持的并发事务数的范围是256~1024,这个数量未免有点太小了,所以InnoDB最多支持配置128个回滚段,也就是最多131072个Undo slot,最少支持32768个并发事务,是完全够用的。

128个回滚段,意味着128个Rollback Segment Header页面,为了管理这些页面,InnoDB在系统表空间的第5号页面使用了128个8字节大小的格子来存储这写页面的Space ID和页号。
image.png

5.3 回滚段分类

这128个回滚段分为两大类:

  • 第0号、33~127号属于一类,用于存放更新普通表时所产生的undo log。
  • 第1~32号属于一类,用于存放更新临时表时所产生的undo log。

为什么普通表和临时表产生的undo log要分开存储?
Undo log页面也是一个普普通通的页面,在对Undo log页写入数据时,也要记录对应的redo log,用于系统崩溃时的数据恢复。而对于临时表的更新,只在系统运行时有效,崩溃恢复是不用恢复临时表的,也就是说针对临时表的Undo log页的变更,是不用记录redo log的,于是InnoDB才通过不同的回滚段来区分。

6. Undo log恢复

事务执行过程中会不断写入redo log,用于系统崩溃时恢复数据。但是,如果事务执行到一半发生崩溃,且redo log已经刷盘了,那么MySQL重启后还是会根据redo log将数据恢复到事务执行一半的状态,这违背了事务的原子性。此时,必须将这个执行到一半的事务给回滚掉,这个工作就落到了undo log的头上。
MySQL重启后,会加载系统表空间第5号页面,定位到128个回滚段,检查每一个回滚段里的Undo slot对应的Undo log链表的状态,如果状态是TRX_UNDO_ACTIVE就代表崩溃前有活跃的事务在向链表写入undo log,MySQL会在Undo Segment Header中通过TRX_UNDO_LAST_LOG属性找到最后一个Undo Log Header,里面有事务id以及一些其它信息,再通过undo log将该事务回滚掉。

7. 配置

  • 回滚段

启动参数innodb_rollback_segments用来配置回滚段的数量,可选范围是1~128,该配置不会影响临时表的回滚段数量始终是32。

  • undo表空间

默认情况下,普通表的回滚段都会分配到系统表空间,其实第33~127号回滚段是支持配置到自定义的undo表空间的,但是只能在系统初始化时配置,后续不再支持修改。
innodb_undo_directory配置指定了undo表空间目录,innodb_undo_tablespaces配置指定了undo表空间的数量,默认是0。

设立undo表空间的一个好处就是在undo表空间中的文件大到一定程度时,可以自动的将该undo表空间截断成一个小文件。而系统表空间的大小只能不断的增大,却不能截断。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/17935.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis 常见问题

一、 什么是Redis? Redis 是一个使用 C 语言写成的,开源的高性能key-value非关系缓存数据库;Redis的数据都基于缓存的,所以很快,每秒可以处理超过 10万次读写操作;Redis也可以实现数据写入磁盘中&#xff…

Spring源码里开天辟地的五个Bean,再介绍一个学习方法

准备工作 首先咱们还是来写一个最简单的例子: 用的还是 https://github.com/xiexiaojing/yuna 里的代码,只是标签和引用都换成了Spring原生的。 配置类就是配置了扫描路径: 在可以被扫描的包路径下定义了一个Bean对象。用了Component注解这…

Java#16(包装类和集合练习)

目录 基本数据类型对应的包装类: 一.添加学生对象并遍历 二.添加用户对象并判断是否存在 三.添加手机对象并返回要求的数据 基本数据类型对应的包装类: byte------>Byte short------->Short char------->Character int------->Integer long------->Long flo…

MRT(MODIS Reprojection Tool) 下载及安装教程

大家下载MODIS数据的时候,大多是hdf的格式数据。HDF数据包括11个波段的数据(如下图),假如想要其中一个波段数据,我们需要批量提取,这时就要用到NASA提供的MODIS Reprojection Tool,此工具虽不能…

c++ 指针,new运算符

1、指针相关基础知识: 1.1、指针一般指向变量的地址,等同于变量名前加&,如下: int a 3; int* p; p &a; 1.2、 * 符号被称为间接值运算符或解除引用运算符,将其运用于指针,可以获取指针指向的值…

【Java八股文总结】之IO流

文章目录Java IO流一、IO基础知识1、字节流2、字符流3、字节缓冲流4、打印流5、随机访问流6、字节流和字符流的区别?二、IO设计模式1、装饰器模式2、适配器模式Q:适配器模式和装饰器模式的区别?3、工厂模式4、观察者模式三、IO模型详解&#…

柯桥留学日语培训机构有吗日本人平时都喝什么酒?

日本葡萄酒侍酒大师高野丰先生,带来一瓶在北海道发现的陈年白兰地。 那是2014年的事,高野先生去北海道十胜地区的一家葡萄酒厂考察,在一个多年未开启的葡萄酒储存库的角落里,发现了一只陈旧的酒桶,他很好奇地问酒厂的…

Javaweb filter过滤器 跟 listener监听器

Filter 权限控制:登录才能进数据库等 统一编码:统一各种编码 Filter快速入门 放行前,我们对request里的数据进行处理 处理完,然后放行,携带到对应的资源里去 放行后,对response的数据进行处理 //将re…

C/C++问题:一个指针的大小是多少?怎么理解指针变量的存在

目录 举例 一、 int a; int (*(*v)[])(); 二、 int func(); int (*func)(); 三、 const; int const a; const int a; int const*r; int *const r; 四、一个指针的大小是多少?(补充) 举例 一、 int a; 可以看到上面声明了一个变…

【MySQL基础】SQL语言的概述、组成及特点

目录 一、SQL的概述 二、SQL语言的组成 三、SQL语言的特点 语法特点: 💟 创作不易,不妨点赞💚评论❤️收藏💙一下 一、SQL的概述 SQL全称: Structured Query Language,是结构化查询语言&am…

数据结构先序序列创建二叉树

2022.11.19连发两回。 先序序列创建二叉树任务描述相关知识编程要求测试说明C/C代码任务描述 本关任务:利用先序遍历创建二叉树,并给出相应二叉树的中序遍历结果。 相关知识 为了完成本关任务,你需要掌握:1.二叉树的前序遍历&a…

win11系统下,迅雷启动后闪退的问题

win11系统,迅雷最新版本。 之前用迅雷一直好好的,某天要下东西突然发现点击就闪退,进程管理器里一点痕迹都没有。 启动就闪退,没有一点点痕迹。 因为之前是win10系统,一直用的好好的,考虑是不是win11系统…

创建自己数据集全套流程

目录 1、准备自己具有的数据集 2、标注数据----json格式 3、标注数据转为分割图----voc格式 4、增广数据集 5、分训练集以及验证集 1、准备自己具有的数据集 注意:数据集必须是统一的后缀格式,jpg或者png 2、标注数据----json格式 采用labelme标注…

前后端分离项目(vue+springboot)集成pageoffice实现在线编辑office文件

前后端分离项目下使用PageOffice原理图 集成步骤 前端 vue 项目 在您Vue项目的根目录下index.html中引用后端项目根目录下pageoffice.js文件。例如&#xff1a; <script type"text/javascript" src"http://localhost:8081/samples-springboot-back/pageof…

gom传奇引擎无限蜂功能插件安装图文教程

无限蜂功能插件安装教程 1. 百度搜索无限蜂官网,下载功能插件程序&#xff0c;请下载最新版&#xff01;2. 下载无限蜂功能插件&#xff0c;到桌面&#xff0c;并进行解压&#xff0c;如下图所示。 3. 打开无限蜂功能插件控制台(?.?.?)&#xff0c;进行账号注册。 4. 注册成…

InnoDB之Undo log格式

1. 前言 InnoDB有两大日志模块&#xff0c;分别是redo log和undo log。为了避免磁盘随机写&#xff0c;InnoDB设计了redo log&#xff0c;数据写入时只写缓冲页和redo log&#xff0c;脏页由后台线程异步刷盘&#xff0c;哪怕系统崩溃也能根据redo log恢复数据。但是我们漏了一…

STC51单片机32——液晶1602显示

//用LCD循环右移显示字符 //开发板上的跳帽连接Vcc #include<reg51.h> //包含单片机寄存器的头文件 #include<intrins.h> //包含_nop_()函数定义的头文件 sbit EP2^7; //使能信号位&#xff0c;将E位定义为P2.7引脚 sbit RSP2^6; //寄存器选择位&#…

Js逆向教程-09常见的加密方式

作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; Js逆向教程-09常见的加密方式 常见的加密方式 一、js逆向流程 抓包调试扣去js改写本地运行 二、常见的加密方式 2.1取盐校验 不可…

【考研复试】计算机相关专业面试英语自我介绍范文(一)

文章目录前言&#xff1a;1.第一段&#xff1a;打招呼寒暄2.第二段&#xff1a;自我介绍3.第三段&#xff1a;为什么要读研4.第四段&#xff1a;个人优势5.第五段&#xff1a;立flag前言&#xff1a; 英语面试第一件事情就是让考生做自我介绍&#xff0c;考官可以借此机会了解…

图片编辑软件怎样加文字内容?图片添加文字方法大分享

大家平时在分享自己拍摄的照片时&#xff0c;有些时候会不会觉得照片有点单调&#xff0c;想在上面添加一些文字来装饰图片呢&#xff1f;又或者是在日常生活中&#xff0c;不小心拍到朋友的搞怪表情&#xff0c;这时候要是加上一些有趣的文字&#xff0c;就可以免费获得一个表…