MySQL系列:innodb源码分析之mini transaction

日志是innodb一个非常重要的模块,在innodb中有两类日志:redo log和undo log。其中redolog日志是用来做数据异常恢复和数据库重启时页数据同步恢复的,redo log是建立在在mini transaction基础上。数据库在执行事务时,通过minitransaction产生redo log来保证事务的持久性。

1.mini transaction三个协议

mini-transcation是用来实现innodb的物理逻辑日志的写入和页恢复的,通过mini-transcation来保证并发事务操作和数据库异常是页的一致性。为了得到页的一致性,mini-transaction遵循以下三个协议:

1. The FIX Rules

2. Write-Ahead Log

3. Force-log-at-commit

1.1The FIX Rules

The FIX Rules规定如下:

修改一个页需要获得该页的x-latch

访问一个页是需要获得该页的s-latch或者x-latch

持有该页的latch直到修改或者访问该页的操作完成

1.2Write-Ahead Log

Write-Ahead Log的意思就是如果一个页操作在写入到持久设备时,必须内存中相对应的日志写入到持久化设备中。每个页有一个LSN,每次页修改需要维护这个LSN,当一个页需要写入到持久化设备时,要求内存中小于该页LSN的日志先写入到持久化设备中。日志写完后,先Fixed这个页的latch,再将内存中的页刷盘。完成刷盘后,释放页latch。这里遵循The FIX Rules协议。

1.3 Force-log-at-commit

一个事务可以同时修改了多个页,Write-AheadLog单个数据页的一致性,无法保证事务的持久性。Force -log-at-commit要求当一个事务提交时,其产生所有的mini-transaction日志必须刷到持久设备中。这样即使在页数据刷盘的时候宕机,也可以通过日志进行redo恢复。

2 mini-transaction的日志实现

innodb是采用mini-transaction来构建操作的物理逻辑日志的,在事务执行的时候,会通过mtr来保证页的数据一致性和持久性。mini-transaction是通过一个mtr_t的结构来实现mini-transaction的三个协议。mtr_t的定义如下:

typedef struct mtr_struct
    {
         ulint	 state;                      /*mtr的状态,MTR_ACTIVE、MTR_COMMITING、MTR_COMMITTED*/
         dyn_array_t	 memo;        /*正在持有的latch列表*/
         dyn_array_t	 log;             /*mtr产生的日志数据*/
         ibool	 modifications;     /*是否修改了页*/
         ulint	 n_log_recs;            /*log操作页的个数*/
         ulint	 log_mode;             /*log操作模式,MTR_LOG_ALL、MTR_LOG_NONE、MTR_LOG_SHORT_INSERTS*/
         dulint	 start_lsn;              /*mtr起始的LSN*/
         dulint  end_lsn;             /*mtr结束的LSN*/
         ulint  magic_n;             /*魔法字*/
    }mtr_t;

其中成员memo是个latch持有状态的数组列表,采用的是dyn_array_t的动态内存结构来保存的,每个单元存储的是mtr_memo_slot_t这样的结构。定义如下:

typedef struct mtr_memo_slot_struct
        {
             ulint	 type;            /*latch的类型值*/
             void*	 object;        /*latch对象句柄,可以是rw_lock_t或者buf_block_t*/
        }mtr_memo_slot_t;

latch类型如下:

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*/

memo的latch管理接口

mtr_memo_push                                       获得一个latch,并将状态信息存入mtr memo当中

mtr_release_s_latch_at_savepoint       释放memo偏移savepoint的slot锁状态

mtr_memo_contains                          判断锁对象是否在memo当中

mtr_memo_slot_release                    释放slot锁的控制权

mtr_memo_pop_all                           
释放所有memo中的锁的控制权

mt_t中的log成员是也是一个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.

标识modifications是标识是否有page的数据改动,如果有,在mtr_commit调用时会先将mtr->log刷盘,然后释放mtr所有的所控制权。日志会一定会在mtr结束时刷盘,这符合Force-log-at-commit的规定。日志写入调用的是log_write_low这个函数。

2.1 mtr_t的内存结构关系图

3 总结

mini transaction是innodb对ACID中的持久性的最小保证单元,所有涉及到事务执行、页数据刷盘、redo log数据恢复等都需要进行mini transaction的构造和执行。几乎所有的模块都涉及到mini transaction,例如:btree、page、事务、inser tbuffer、redo-log等,d对mini transcaion的理解不能孤立的去看源代码,应该结合redo
log、page相关的代码了解。它是理解innodb工作原理的基石。

时间: 2024-11-08 21:35:26

MySQL系列:innodb源码分析之mini transaction的相关文章

MySQL系列:innodb源码分析之redo log恢复

在上一篇<innodb源码分析之重做日志结构>中我们知道redo log的基本结构和日志写入步骤,那么redo log是怎么进行数据恢复的呢?在什么时候进行redo log的日志推演呢?redo log的推演只有在数据库异常或者关闭后,数据库重新启动时会进行日志推演,将数据库状态恢复到关闭前的状态.那么这个过程是怎么进行的呢?以下我们逐步来解析. 1.recv_sys_t结构 innodb在MySQL启动的时候,会对重做日志文件进行日志重做,重做日志是通过一个recv_sys_t的结构来进行数

InnoDB源码分析--缓冲池(三)

转载请附原文链接:http://www.cnblogs.com/wingsless/p/5582063.html 昨天写到了InnoDB缓冲池的预读:<InnoDB源码分析--缓冲池(二)>,最后因为着急看欧洲杯,没有把线性预读写完,今天接着写. 线性预读是由这个函数实现的:buf_read_ahead_linear,和随机预读一样,首先是要确定区域边界,这个边界内被访问过的page如果达到一个阈值(BUF_READ_AHEAD_LINEAR_THRESHOLD),就会触发预读操作.边界的算法

redis源码分析之事务Transaction(下)

接着上一篇,这篇文章分析一下redis事务操作中multi,exec,discard三个核心命令. 原文地址:http://www.jianshu.com/p/e22615586595 看本篇文章前需要先对上面文章有所了解: redis源码分析之事务Transaction(上) 一.redis事务核心命令简介 redis事务操作核心命令: //用于开启事务 {"multi",multiCommand,1,"sF",0,NULL,0,0,0,0,0}, //用来执行事

redis源码分析之事务Transaction(上)

这周学习了一下redis事务功能的实现原理,本来是想用一篇文章进行总结的,写完以后发现这块内容比较多,而且多个命令之间又互相依赖,放在一篇文章里一方面篇幅会比较大,另一方面文章组织结构会比较乱,不容易阅读.因此把事务这个模块整理成上下两篇文章进行总结. 原文地址:http://www.jianshu.com/p/acb97d620ad7 这篇文章我们重点分析一下redis事务命令中的两个辅助命令:watch跟unwatch. 一.redis事务辅助命令简介 依然从server.c文件的命令表中找

MySQL系列:innodb源码分析之表空间管理

innodb在实现表空间(table space)基于文件IO之上构建的一层逻辑存储空间管理,table space采用逻辑分层的结构:space.segment inode.extent和page.在实现层的逻辑使用了磁盘链表这种结构来管理逻辑关系.我们先来介绍磁盘链表. 1.磁盘链表 磁盘链表的实现fut0lst.*文件当中, innodb为了管理表空间和索引模块,定义了一个基于磁盘的链表,主要是用来保存磁盘数据结构之间的关系.这个链表不是基于内存指针的,而是基于page no和boffse

MySQL系列:innodb源码分析之page结构解析

在表空间结构分析当中,我们知道innodb的最小物理存储分配单位是page页,在MySQL-3.23版本的源码中,页只有两种页,一种是index page,一种是undo page.其类型值定义在fil0fil.h当中. FIL_PAGE_INDEX                         数据索引页,在表空间的inode page和xdes page都是属于这类. FIL_PAGE_UNDO_LOG                事务回滚日志页. 在这里我们主要分析的是 index p

InnoDB源码分析--缓冲池(二)

转载请附原文链接:http://www.cnblogs.com/wingsless/p/5578727.html 上一篇中我简单的分析了一下InnoDB缓冲池LRU算法的相关源码,其实说不上是分析,应该是自己的笔记,不过我还是发扬大言不惭的精神写成分析好了.在此之后,我继续阅读了Buf0rea.c文件,因为这里写的就是如何将block读取到内存中的函数. 这个文件里很显眼的有这样一个函数:buf_read_page,这是一个高层的函数,它的作用就是:reads a page asynchrono

MySQL系列:innodb源码分析之重做日志结构

在innodb的引擎实现中,为了实现事务的持久性,构建了重做日志系统.重做日志由两部分组成:内存日志缓冲区(redo log buffer)和重做日志文件.这样设计的目的显而易见,日志缓冲区是为了加快写日志的速度,而重做日志文件为日志数据提供持久化的作用.在innodb的重做日志系统中,为了更好实现日志的易恢复性.安全性和持久化性,引入了以下几个概念:LSN.log block.日志文件组.checkpoint和归档日志.以下我们分别一一来进行分析. 1.LSN 在innodb中的重做日志系统中

MySQL对于datetime 源码分析

http://tsecer.blog.163.com/blog/static/150181720160117355684/ 一.时间比较的语法分析 在mysql中,通常时间是一个必不可少的类型,而这种类型的一个特殊地方就在于它的比较函数.其实,即使对于字符串的比较函数和对于int的比较也是完全不同的,但是这个差别并不想以datetime保存的时间这么具有视觉的震撼性和表现的这么明显.这里还有一个问题在于,当mysql的yacc在进行语法分析的时候,这个时候语法分析器并没有读取一个field中的结