Mysql innodb源码MTR模块,了解源码能帮助DBA更熟悉数据库运行原理、更容易定位排查问题。那么什么是Mtr?Mtr究竟是用来做什么的?围绕几个问题我们来做一下深入研究。
一、什么是MTR?
Mtr即Mini-transaction的缩写,字面意思小事物,相对逻辑事物而言,我们把它称作物理事物。属于Innodb存储引擎的底层模块。主要用于锁和日志信息。
我们知道Innodb事物有四种特性:ACID即原子性、一致性、隔离性、持久性,通常称为逻辑事物。用来保证一致性和持久性的机制就是Mtr,即锁和日志,一旦事务提交,则其所做的修改会永久保存到数据库。
二、MTR原理
1) The FIX Rules:
修改或访问一个页需要获得该页的x-latch或s-latch,直到修改或者访问该页的操作完成。每个页都有个buf_block_t的对象:
struct buf_block_struct{
......
rw_lock_t
lock; #对页的latch操作
ulint
buf_fix_count; #有多少个操作fix该页
......
其中lock实现对页的latch操作,buf_fix_count表示有多个操作fix该页。多个事物读取一个页时,该变量就会自增。当一个页根据LRU算法从缓冲池中替换时,该变量必须为0。
2) Write-Ahead Log:
如果一个页操作在写入到持久设备时,必须先将内存中小于该页LSN的日志写入到持久化设备中。
3) Force-log-at-commit:
前面两个主要是为了保证事物的一致性,而事物的持久性还需要这个规则进一步加强。一个事物可以涉及多个页,当事物提交时,产生所有的Mtr日志必须刷到持久设备中。通过innodb_flush_log_at_trx_commit参数控制是否必须启用该规则。
-
在innodb中有两类日志:redo log和undo log。其中redo log是用来做数据异常恢复和
数据库
重启时页数据同步恢复的,redo log就是建立在Mtr基础上。数据库在执行事务时,通过Mtr产生redo log来保证事务的持久性。
-
物理事务从名字来看是物理的,因为在innodb存储引擎中,只要是涉及到文件读取、修改等物理操作,都离不开Mtr,可以说Mtr是内存与文件之间的一个桥梁。
-
可参考下图:
三、MTR工作方式
物理事务既然被称为事务,那它同样有事务的开始与提交,在innodb中,物理事务的开始其实就是对物理事务的结构体mtr_t的初始化,在mtr0mtr.h文件中,其中包括下面一些成员:
这个结构体中dyn_array_t是两个动态数组:
-
成员state表示mtr的状态,包括三种状态;
-
成员memo用来存储所有这个物理事务用到(访问)的页面,这些页面都是被所属的物理事务上了锁的(读锁或者写锁,某些时候会不上锁);
-
成员log用来存储这个物理事务在访问修改数据页面的过程中产生的所有日志,这个日志就是数据库中经常说到的重做(redo log)日志;
-
成员n_log_recs表示这个物理事务操作的页个数;
-
log_mode表示这个物理事务的日志模式,包括MTR_LOG_ALL(写日志)、MTR_LOG_NONE(不写日志)等;
-
LSN两个成员表示这个物理事务开始前的LSN及这个物理事务提交后产生的新的LSN。
是个latch持有状态的数组列表,采用的是dyn_array_t的动态内存结构来保存的,每个单元存储的是mtr_memo_slot_t这样的结构。定义如下:
la
tchty
pe如下:
MTR_MEMO_PAGE_S_FIX
|
/rw_locks-latch/
|
MTR_MEMO_PAGE_X_FIX
|
/rw_lockx-latch/
|
MTR_MEMO_BUF_FIX
|
/buf_block_t/
|
MTR_MEMO_S_LOCK
|
/rw_lock s-latch/
|
MTR_MEMO_X_LOCK
|
/rw_lock x-latch/
|
object是
latch的对象,可以是rw_lock_t对象,也可以是buf_block_t对象。
memo的l
atch管理接口:
mtr_memo_push
|
获得一个latch,并将状态信息存入mtr memo当中
|
mtr_memo_slot_t
|
保存latch内容
|
mtr_release_s_latch_at_savepoint
|
释放memo偏移savepoint的slot锁状态
|
mtr_memo_contains
|
判断锁对象是否在memo当中
|
mtr_memo_slot_release
|
释放slot锁的控制权
|
mtr_memo_pop_all
|
释放所有memo中的锁的控制权
|
是也是一个dyn_array_t动态结构的内存,用来保存mtr产生的日志信息。日志的写入是通过mtr0log.h来写入的。
重做日志虽然有很多种类型,但重做的日志格式是统一的,日志格式是有日志头和日志体组成,日志头信息是由type、space和page no组成,由mlog_write_initial_log_record_fast函数写入到mtr_t的log中的。log body的数据写入是通过mtr0log.h中的日志写入方法进行写入的,每写入一条操作日志,n_log_recs会加1。
以下是一个比较具体的示意图:
是标识是否有page的数据改动,如果有,在mtr_commit调用时会先将mtr->log刷盘,然后释放mtr所有的所控制权。日志一定会在mtr结束时刷盘,这符合Force-log-at-commit的规则。日志写入调用的是log_write_low这个函数。
-
首先在系统将一个页面载入到缓冲区的时候,需要新开始一个(mtr_start)或者一个已经开始的物理事务,载入时需要指定页的获取方式,比如是用来读取的还是用来修改的,这样会影响物理事务对这个页的上锁情况,如果用来修改,则上X锁,否则上S锁(当然还可以指定不上锁)。在确定了获取方式、这个页的表空间ID及页号之后,就可以通过函数buf_page_t来获取指定页面了。
-
当找到相应页后,物理事务就要对它上指定的锁,此时需要对这个页的上锁情况进行检查,一个页的上锁情况是在结构体buf_block_struct中的lock中体现的,此时如果这个页还没有上锁,则这个物理事务直接对其上锁,否则还需要考虑两个锁的兼容性,只有两个锁都是共享锁(S)的情况下才是可以上锁成功的,否则需要等待。当上锁成功后,物理事务会将这个页的内存结构存储到上面提到的memo动态数组中。然后这个物理事务就可以访问这个页了。mtr_start再mtr0mtr.ic文件中。
-
物理事务对页面的访问包括两种操作,一种是读,另一种是写,读就是简单读取其指定页面内偏移及长度的数据;写则是指定从某一偏移开始写入指定长度的新数据,同时如果这个物理事务是写日志的(MTR_LOG_ALL),此时还需要对刚才的写操作记下日志,这里的日志就逻辑事务中提到的redo日志。写下相应的日志之后,同样将其存储到上面的log动态数组中,同时要将上面结构体中的n_log_recs自增,维护这个物理事务的日志计数值。
-
物理事务的读写过程主要就是上面介绍的内容,其最重要的是它的提交过程。物理事务的提交是通过mtr_commit来实现的,物理事务的提交主要是将所有这个物理事务产生的日志写入到innodb的日志系统的日志缓冲区中,然后等待srv_master_thread线程定时将日志系统的日志缓冲区中的日志数据刷到日志文件中。
四、确保MTR完整性
上面已经提过,物理事务和逻辑事务一样,也是可以保证数据库操作的完整性的,一般说来,一个操作必须要在一个物理事务中完成,也就是指要么这个操作已经完成,要么什么也没有做,否则有可能造成数据不完整的问题,因为在数据库系统做redo操作时是以一个物理事务为单位做的,如果一个物理事务的日志是不完整的,则它对应的所有日志都不会重做。那么如何辨别一个物理事务是否完整呢?
这个问题是在物理事务提交时用了个很巧妙的方法保证了,在提交前,如果发现这个物理事务有日志,则在日志最后再写一些特殊的日志,这些特殊的日志就是一个物理事务结束的标志,那么提交时一起将这些特殊的日志写入,在重做时如果当前这一批日志信息最后面存在这个标志,则说明这些日志是完整的,否则就是不完整的,则不会重做。
物理事务提交时还有一项很重要的工作就是处理上面结构体中动态数组memo中的内容,现在都已经知道这个数组中存储的是这个物理事务所有访问过的页面,并且都已经上了锁,那么在它提交时,如果发现这些页面中有已经被修改过的,则这些页面就成为了脏页,这些脏页需要被加入到innodb的buffer缓冲区中的更新链表中(
详细了解BUFFER
),当然如果已经在更新链中,则直接跳过(不能重复加入),svr_master_thread线程会定时检查这个链表,将一定数目的脏页刷到磁盘中,加入之后还需要将这个页面上的锁释放掉,表示这个页面已经处理完成;如果页面没有被修改,或者只是用来读取数据的,则只需要直接将其共享锁(S锁)释放掉即可。
上面的内容就是Mtr的一个完整的讲述,因为它是比较底层的一个模块,牵扯的东西比较多,这里重点讲述了物理事务的意义、操作原理、与BUFFER系统的关联、日志的产生等内容。
Mtr是innodb对ACID中的持久性的最小保证单元,所有涉及到事务执行、页数据刷盘、redo log数据恢复等都需要进行mini transaction的构造和执行。几乎所有的模块都涉及到minitransaction,例如:btree、page、事务、inser tbuffer、redo-log等,对mini transcaion的理解不能孤立的去看源码,应该结合redo log、page等相关的代码了解。它是理解innodb工作原理的基石。
六、MTR涉及的模块文件
.h头文件统一放在include目录下,全局变量定义,宏定义、函数说明等
|
.ic也在include目录下,这类文件为每个模块定义了内联函数
|
.c\.cc标准源文件,在各自模块目录下,具体实现功能
|
mtr0mtr.h
|
mtr0mtr.ic
|
page0cur.c
|
mtr0log.h
|
mtr0log.ic
|
mtr0mtr.cc
|
mtr0types.h
|
|
mtr0log.cc
|
mem0mem.h
|
|
|
dyn0dyn.h
|
|
|
buf0types.h
|
|
|
sync0rw.h
|
|
|
ut0byte.h
|
|
|
page0types.h
|
|
|
dict0types.h
|
|
|
buf0buf.h
|
|
|
mach0data.h
|
|
|
什么是redo?
redo log是重做日志,是wal(Write ahead log)的基础.
mysql
在
innodb
buffer中修改的数据并不会实时刷新到磁盘,这就全部都是随机的io,性能很差,但是这时候需要redo来保证
数据的持久化。
主要的作用:
1.将随机刷盘转化为顺序刷盘,提高性能
2.crash recovery: 当故障发生导致内存数据丢失后,
InnoDB
会在重启时,通过重放REDO,将Page恢复到崩溃前的状态
这也是和普通的文件系统最大的区别
redo对我们来说最
标签:
MySQL
标签:
MySQL
结构标签:
MySQL
redoRedo log 相关结构和记入过程:1. log_sys对象(1). log_sys作用log_sys是redo日志系统的关键全局变量。负责三项事情:log record从
mtr
_buf复制到logbuffer:用户线程
mtr
_commit时,将
mtr
_buf中的redo record,拷贝到log buffer中;log recor...
目录一、LNMP相关概念二、安装Nginx服务1、安装依赖包2、创建运行用户3、编译安装4、路径优化5、添加Nginx系统服务三、安装
MySQL
服务1、安装
Mysql
环境依赖包2、创建运行用户3、编译安装四、安装配置PHP
解析
环境1、安装环境依赖包2、编译安装3、路径优化4、调整PHP配置文件(1)调整主配置文件(2)调整进程服务配置文件(3)调整扩展配置文件5、启动php-fpm6、配置Nginx支持PHP
解析
7、测试访问页8、验证数据库五、部署Discz社区论坛web应用
一、LNMP相关概念
本文内容部分来自对官方文档的翻译和理解,部分来源于遇到问题的整理和记录。
mysql
-test quick-start:
参考http://dev.
mysql
.com/doc/
mysql
test/2.0/en/writing-tests-quick-start.html
1、 进到测试目录
shell> cd
mysql
-version/
mysql
-test
1
MTR
(mini-transaction) 微事务
在
MySQL
的
InnoDB
日志管理机制中,有一个很重要的概念就是
MTR
。
MTR
是
InnoDB
存储擎中一个很重要的用来保证物理写的完整性和持久性的机制。
2
MTR
在
MysQL
架构中的位置
MTR
是上面的逻辑层与下面物理层的交互窗口
3
MTR
作用
主要保证物理操作的一致性和原子性;
同时也是用来保证下层物理数据正确性、完整性及持久性的机制。
在
innodb
中实现了自己的内存池系统和内存堆分配系统,在
innodb
的内存管理系统中,大致分为三个部分:基础的内存块分配管理、内存伙伴分配器和内存堆分配器。
innodb
定义和实现内存池的主要目的是提供内存的使用率和效率,防止内存碎片和内存分配跟踪和调试。我们先来看看他们的关系和结构。下面是它的关系结构图:上图中的:ut_mem_block块是基础内存管理Buddy allocator是内存伙伴分...
准备好可用的cmake,bison(这一点很重要),放到环境变量中。在官网下载
mysql
源码
,选择5.6.25版本(原因以后再解释)。用cmd.exe打开,在
源码
主目录下创建bld文件夹,至此,
源码
下载及编译过程结束。...