mysql源码:关于innodb中两次写的探索
两次写可以说是在Innodb中很独特的一个功能点,而关于它的说明或者解释非常少,至于它存在的原因更没有多少文章来说,所以我打算专门对它做一次说明。
首先说明一下为什么会有两次写这个东西:
因为innodb中的日志是逻辑的,所谓逻辑就是比如当插入一条记录时,它可能会导致在某一个页面(这条记录最终被插入的位置)的多个偏移位置写入某个长度的值,比如页头的记录数,槽数,页尾槽数据,页中的记录值等等,这些本是一些物理操作,而innodb为了节约日志量及其它一些原因,设计为逻辑处理的方式,那就是它会在一个页面的基础上,把一条记录插入,那么在日志记录中记录的内容为表空间号、页面号、记录的各个列的值等等,在内部转换为上面的物理操作。
但这里的一个问题是,如果那个页面本身是错误的,这种错误有可能是因为写断裂(1个页面为16K,分多次写入,后面的有可能没有写成功,导致这个页面不完整)引起的,那么这个逻辑操作就没办法完成了,因为它的前提是这个页面还是正确的,完整的,因为如果这个页面不正确的话,这个页面里的数据是无效的,有可能产生各种不可预料的问题。
那么正是因为这个问题,所以必须要首先保证这个页面是正确的,方法就是两次写,它的思想最终是一种备份思想,也就是一种镜像。
下面就它的实现方式说明一下:
首先是它的创建,在初始化一个库的时候,系统会在系统页面5号页面的尾部(大约是16K-200字节的位置)初始化所有关于两次写的信息,这些信息包括:
----------------------------------------------------------------
#define TRX_SYS_DOUBLEWRITE_FSEG 0 /*这里存储的是两次写页面所在的段的地址信息 */
#define TRX_SYS_DOUBLEWRITE_MAGIC FSEG_HEADER_SIZE
/*!< 用来判断是不是已经初始化过两次写页面 */
#define TRX_SYS_DOUBLEWRITE_BLOCK1 (4 + FSEG_HEADER_SIZE)
/*!两次写页面的第一个簇的首地址,两次写页面总共有2个簇,一个簇为64个页面*/
#define TRX_SYS_DOUBLEWRITE_BLOCK2 (8 + FSEG_HEADER_SIZE)
/*!第二个簇的首地址*/
#define TRX_SYS_DOUBLEWRITE_REPEAT 12 /*!< 将上面的MAGCI、BLOCK1与BLOCK2重复存储,防止自己的不完整*/
----------------------------------------------------------------
两次写总共包括2M(默认值)的数据,有2个BLOCK,那么每一个BLOCK是1M,每个页面是16K,那么一个BLOCK包括64个页面,正是一个簇的大小。,所以其实两次写页面的空间是2个簇的空间。
那么初始化所要做的工作就是将上面的信息补充完整,BLOCK1与BLOCK2分别对应2个簇的首地址,同时还要申请2个簇的内存空间,用来缓存这些数据。
除上面的信息之外,还会有一个空间用来存储这128个页面的页面信息,是用来在刷两次写页面之后,要做对应的页面刷盘操作,这是一个长度为128的数组。
有了上面的信息之后,则两次写初始化完成。
下面说明一下它的使用过程:
在做页面刷盘的时候,如果开启了两次写的功能,则innodb要做的不是简单的直接将数据做io操作写入到硬盘,而是先将当前要写的页面按照顺序拷贝到两次写内存缓存空间中去,上面已经说了它的大小为128个页面的大小,同时要在页面数组中对应的将页面的地址记录下来,然后就算刷盘完成了,但实际上,此时要写出的页面都在两次写的内存缓存空间中的。
当缓存空间满了的时候,上面的操作会触发真正的刷盘操作,两次写的写入是,首先判断当前缓存中有多少个簇,也就是说判断BLOCK1中有没有数据,如果没有数据则直接不写了,如果有则写入,以这个簇实际大小写入,然后再判断BLOCK2中有没有数据,然后做同样的处理。
在写完两次写缓存中的数据之后,然后再将页面数组中的每一个页面按照顺序从前到后再一个一个的将其刷入到文件中,此时,才真正的将这些页面刷盘完成。
当然两次写缓存写出硬盘不只是上面一个机会,其它刷盘的操作也会触发这个操作,那时可能缓存中的页面数还没有达到128个。
上面已经说完了两次写的写入及初始化,最后说一下它是如何起作用的:
在数据库启动时(异常关闭的情况下),都会做数据库恢复(redo)操作,恢复的过程中,数据库都会检查页面是不是合法(校验等等),如果发现一个页面校验结果不一致,则此时会用到两次写这个功能,这个特点也正是为了处理这样的错误而设计的。
此时的操作很明白了,将两次写的2个BLOCK(簇)都读出来,然后将所有这些页面写回到对应的页面中去,那么这时可以保证这些页面是正确的,并且是在写入前已经更新过的(最新数据)。
在写回对应页面中去之后,那么就可以在这基础上继续做数据库恢复了,之后则不会再遇到这样的问题了,因为已经将最后有可能产生写断裂的数据页面都恢复了。
问题:
上面说的都是数据页面有问题的情况下可以通过两次写页面来恢复,但是如果2次写页面本身发生写断裂怎么办?
对于这个问题,其实是不用担心的,因为如果两次写有问题,则本身数据页面就没有做写操作,此时系统挂了,发生错误的是两次写页面,而数据页面在挂之前都是在buffer里面,文件中还是当前事务操作前的值,它自己没有变,还是一致状态,所以两次写页面压根就不会被使用到。
总结:
1. 两次写在任何时候记录的都是数据库最后发生改变的若干页面(最多128个),在数据库不断工作的过程中,它会不断的被覆盖,它始终是最新的数据,记录的是修改之后的页面数据,而不是修改之前的数据,它的作用不是还原数据,而是保证不会丢失修改。
2. 至于性能问题,表面看上去,它是每一个页面都写了2遍,则会非常影响性能,但实际上,由于将所写的页面都先缓存到内存中,到达128个之后才真正写入,那么对于磁盘而言,连续写与分散写(每个页面自己写)的性能相差很大的,而两次写正是将一个簇数量的页面组合起来形成2个连续的空间写入到两次写空间中,有效的利用这了这特点,所以性能是不会相差1倍的。实际上经过测试,可能两次写使得性能降低了10%。
3. 有其它一些数据库完全没有类似2次写的问题,比如达梦等,这个主要是由于它们采用了全物理的REDO,将一个页面的写操作都拆成一个个的小的物理写入,这种情况下就不会存在写断裂的情况,因为不管怎么写,日志都是对一个页面操作的重演,在REDO做完之后,页面的状态肯定是正确的。
mysql源码:关于innodb中两次写的探索的更多相关文章
- Mysql 源码:关于innodb中两次写的探索
转载自:http://www.cnblogs.com/bamboos/p/3553703.html?utm_source=tuicool&utm_medium=referral 两次写可以说是 ...
- Netty源码之解码中两种数据积累器(Cumulator)的区别
上一篇随笔中已经介绍了解码核心工作流程,里面有个数据积累器的存在(Cumulator),其实解码中有两种Cumulator,那他们的区别是什么呢? 还是先打开ByteToMessageDecoder的 ...
- ubuntu中Eclipse-cpp编译MySQL源码
1.下载eclipse-cpp-mars-2-linux-gtk-x86_64.tar.gz压缩包,在Ubuntu中解压,运行. 此处有可能会出现jdk错误,只要原因是因为jdk没安装或者jdk版本太 ...
- MySQL源码分析以及目录结构 2
原文地址:MySQL源码分析以及目录结构作者:jacky民工 主要模块及数据流经过多年的发展,mysql的主要模块已经稳定,基本不会有大的修改.本文将对MySQL的整体架构及重要目录进行讲述. 源码结 ...
- MySQL源码分析以及目录结构
原文地址:MySQL源码分析以及目录结构作者:jacky民工 主要模块及数据流经过多年的发展,mysql的主要模块已经稳定,基本不会有大的修改.本文将对MySQL的整体架构及重要目录进行讲述. 源码结 ...
- 深入MySQL源码 学习方法 何登成专家
MYSQL 技术圈 有哪些做得好,又注重分享的公司: Oracle MySQL, MariaDB, Percona,Google, FB, Twitter, Taobao, NetEase… 有哪些值 ...
- [转]MySQL源码:Range和Ref优化的成本评估
MySQL源码:Range和Ref优化的成本评估 原文链接:http://www.orczhou.com/index.php/2012/12/mysql-source-code-optimizer-r ...
- Dubbo入门到精通学习笔记(十九):MySQL源码编译安装、MySQL主从复制的配置
文章目录 MySQL 源码编译安装(CentOS-6.6+MySQL-5.6) 一.服务器配置: 二.源码安装 MySQL5.6.26: MySQL主从复制的配置 环境 依赖课程 MySQL 主从复制 ...
- mysql源码分析-启动过程
mysql源码分析-启动过程 概要 # sql/mysqld.cc, 不包含psi的初始化过程 mysqld_main: // 加载my.cnf和my.cnf.d,还有命令行参数 if (load_d ...
随机推荐
- MyBatis架构设计及源代码分析系列(一):MyBatis架构
如果不太熟悉MyBatis使用的请先参见MyBatis官方文档,这对理解其架构设计和源码分析有很大好处. 一.概述 MyBatis并不是一个完整的ORM框架,其官方首页是这么介绍自己 The MyBa ...
- BZOJ-1975 魔法猪学院 K短路 (A*+SPFA)
1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 1323 Solved: 433 [Submit][Statu ...
- BZOJ-3130 费用流 (听题目胡扯丶裸最大流) 二分判定+最大流+实数精度乱搞
DCrusher爷喜欢A我做的水题,没办法,只能A他做不动的题了.... 3130: [Sdoi2013]费用流 Time Limit: 10 Sec Memory Limit: 128 MBSec ...
- poj 1006 中国剩余定理解同余方程
其实画个图就明白了, 该问题就是求同余方程组的解: n+d≡p (mod 23) n+d≡e (mod 28) n+d≡i (mod 33) #include "iostream" ...
- mint锁屏设置
心血来潮,给笔记本装了linux,版本是当下最火的mint.唔,使用体验不错-下面记录的是修改mint锁屏相关设置的修改方式. In Linux Mint 13, the screen lock fe ...
- TCP/IP详解 学习七
静态选路的前提: 1) 网络比较小 2) 网络之间单点连接 3) 网络之间没有多余的路由 动态选路协议,用于路由器之间的通信,有以下几种: 1) ...
- hihocoder #1034 毁灭者问题
传送门 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在 Warcraft III 之冰封王座中,毁灭者是不死族打三本后期时的一个魔法飞行单位. 毁灭者的核心技能之一, ...
- Opencv不用每次创建项目配置vs2010 vc++目录 库目录等项
可以设置成编译器的环境配置,VS2010相对其他版本虽然去掉了编译器配置 但可以通过属性管理器配置编译器环境. 设置对应的vc++目录 链接器就可以了,这样就是对整个编译器配置了 下次就不用再配了.
- 利用dedecms autoindex让文章列表加上序列号
有些时候我们在制作模板的需要在文章标题前面加上序列号,可以通过织梦自带的autoindex属性来实现,实现方法很简单,只需要在序号递增的地方加上 这段代码就行,[field:global runphp ...
- CSS 仿Excel表格功能
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...