Mini transaction

Mini transaction的定义和划分

        Mysql中所有的事务在innodb存储引擎内部都是通过mini transaction完成的,将一个事务划分成多个mini transaction的依据是:每条语句都作为一个mini transaction来执行。

       虽然,innodb将事务划分成了多个mini transaction,但是mini transaction和mysql中的事务并不一样。根据事务应该具有的ACID特性,事务是用来保证整个数据库中数据的ACID而存在的;但是mini transaction用来保证单个page的数据的一致性。事务对于数据一致性和持久性的保证在Innodb存储引擎内部是通过mini transaction来实现的。

mini transaction遵循的原则

  1. FIX Rules;
  2. Write-Ahead-Log;
  3. Force-log-at-commit;

     1、Fix Rule

         Fix Rule要求在访问或者修改一个page时,需要持有该page的latch,以此来保证并发情况下该page种数据的一致性。一般获取latch的操作称之为Fixing the page。当获得latch之后,称这个page已经Fixed。释放page的latch的操作,称为unfixing。

        为了保证数据在并发情况下的一致性,当修改一个page的时候,需要持有该page的X latch;当访问一个page的时候,需要持有该page的X latch或者S latch。一个page只有当修改完成或者是访问完成之后才释放其持有的latch。

        mini transaction虽然是用来保证单个page中数据的一致性,但是mini transaction可能需要修改多个page,那么该mini transaction必须持有多个page的latch,并在操作完成之后,按照获取latch相反的顺序释放latch。

        在Innodb存储引擎中每个page都有一个buf_block_t对象,关于Fix Rules的变量如下所示:

struct buf_block_struct {

    ......

    rw_block_t lock;

    ulint buf_fix_count;
};

       其中,变量lock实现对page的latch操作。变量buf_fix_count是一个引用计数的存在,表示有多少个操作在fix该page。当一个事务对该page进行访问或者读取时,该值自动增1。当将该page从buffer pool中刷到磁盘的时候,该变量必须为0,否则意味着还有其他事务引用该page。在Innodb存储引擎中,判断一个page是否被fix的正确操作是判断buf_fix_count是否为0。

    2、Write-Ahead Log

       Write-Ahead Log要求在一个page操作写入到持久化设备之前,首先必须将其在内存中的日志写入到持久化存储。实现如下:

      1、每个page都有一个LSN,存储在page头部File Header的FIL_PAGE_LSN位置,每次对page进行修改的时候总是要修改该值;

      2、当将一个page持久化到存储设备的时候,要求将内存中所有LSN小于该page的LSN的日志都持久化到存储设备,然后才开始将内存中的page持久化到存储设备;

      3、将内存中的page写入到持久存储设备的时候,page需要fixed,以此保证page中数据的一致性;

    3、Force-log-at-commit

        Write-Ahead Log保证了日志总是先于内存中的数据page被刷新到磁盘,但是仅仅依靠WAL无法保证事务的持久性。为了能在数据库宕机的时候恢复已经提交的事务,应该保证已经提交的事务的日志能够及时落盘。Force-log-at-commit就是保证当事务提交的时候,对应事务的日志持久化到存储设备。那么,即使数据库发生宕机,也能根据日志恢复数据库中的数据。

Mini transaction的实现

        mini transaction在Innodb中是通过mtr_struct来实现的。其对应的结构如下:

struct mtr_struct {

    ulint state;

    dyn_array_t memo;

    dyn_array_t log;

    ibool modification;

    ulint n_log_recs;

    ulint log_mode;

    dulint start_lsn;

    dulint end_lsn;

    ulint magic_n;
};

         state: mini transaction的状态信息,有效值为MTR_ACTIVE, MTR_COMMTING, MTR_COMMITTED;

         memo: 持有的latch信息;

         log: 产生的日志;

         modification: 该mini transaction是否修改了数据page;

         n_log_recs: 有多少page的日志被写入到变量log中,一个mini transacton可以同时修改多个page;

         log_mode: MTR_LOG_ALL, MTR_LOG_NONE, MTR_LOG_SHORT_INSERTS;

         start_lsn: mini transaction开始时的LSN;

         end_lsn: mini transaction结束时的LSN;

         magic_n: 仅在debug模式下使用;

        变量memo保存着latch信息,也就是为了遵循FIX Rules规则而存在。它保存内容的数据结构为mtr_memo_slot_struct,其定义与说明下所示。

        函数mtr_memo_release用于释放已经持有的latch对象,释放的顺序是后进先出。

        Innodb的重做日志是物理逻辑日志,分为MLOG_SINGLE_REC和MLOG_MULTI_REC两种类型。通过在每条日志头部的type字段设置MLOG_SINGLE_REC_FLAG来标志该mini transaction操作是否只涉及一个page的修改。如果一个mini transaction需要同时维护多个page中数据的一致性,那么其在mini-transaction结束时会额外写入1个字节大小的MLOG_MULTI_REC_END信息,表示该mini-transaction产生了修改多个page的日志。当一个mini-transaction涉及到多个page的修改时,只有读到最后一个0x1F的日志,才应用前面所有的操作,否则丢弃前面所有的操作。

Mini transaction的使用

       在Innodb存储引擎中,mini-transaction总是按照如下的顺序使用:

       1、mtr_t mtr;

       2、mtr_start(&mtr);

             ......

       3、mtr_commit(&mtr);

       函数mtr_start首先初始化mtr。函数mtr_commit按照顺序执行如下的步骤。

       1、如果mtr->modified为true,调用函数log_reverse_and_write_fast或者log_write_low将mtr中保存的日志按照先进先出的顺序写入到重做日志缓冲,这个过程中需要持有锁log_sys->mutex;

       2、调用函数mtr_memo_pop_all释放mtr持有的所有latch;

       3、若mtr->modified为true,调用函数log_release释放步骤1所持有的log_sys->mutex;

       innodb存储引擎首先修改缓冲池中的page,然后再释放log_sys->mutex锁。这是为了保证当释放log_sys->mutex时,所有的脏page都已经完成了更新。当执行函数log_checkpoint、以及将脏page插入到flush list时,page的LSN修改操作已经完成。

       这里需要特别注意log_sys->mutex这个互斥量。mini-transaction写入重做日志缓冲需要持有log_sys->mutex这个互斥量,而从重做日志缓冲写入到重做日志文件时依然要持有该互斥量。因此,该互斥量成为innodb内部线程争夺的热点,或者说成为性能的瓶颈。另外,从重做日志缓冲写入到重做日志文件是缓冲写的方式,重做日志缓冲的数据首先写入到文件的页缓存中,在对文件做fsync的之前就已经释放了log_sys->mutex,因此可以实现事务的组提交。也就是一个事务在进行fsync时,其他事务就获得log_sys->mutex对象,并将事务的重做日志条目写入到重做日志缓冲中,待下一次事务提交时,可以将多个事务的重做日志一次性地写入到重做日志文件中。

       当一个事务没有对page进行任何修改的时候,同样需要使用mini-transaction功能,这是因为访问数据同样需要符合FIX Rules规格,而mini-transaction包含此项功能。当进行mtr_commit的时候,由于page没有进行任何的修改,因此只对相应的page进行unfix操作。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值