• Innodb MVCC源码实现


    1. 概述

    MVCC:

    即多版本一致性,在事务模型下,使用version控制数据版本,关系型数据库基本都实现了MVCC,以对表数据的读写互不阻塞,增大了并发量。

    Oracle和MySQL数据库都是使用undo的机制来实现MVCC。
    但数据库都实现了多个事务的隔离级别,所以MVCC中对可见性的判断,也会因事务的隔离级别不同而不相同。

    2. 相关数据结构

    struct trx_struct{
    read_view_t*    global_read_view;
    read_view_t*    read_view;
    ......
    }

    事务结构体:每一个sql根据read_view或者global_read_view来实现一致性读取。

    struct read_view_struct{
    trx_id_t    low_limit_no;
    trx_id_t    low_limit_id;
    trx_id_t    up_limit_id;
    ulint    n_trx_ids;
    trx_id_t*    trx_ids;
    ......
    }

    read_view结构体:包括当前的活动事务的范围,以及活动事务数组,对于每一行记录,根据记录中的trx_id以及当前查询的read_view
    进行判断记录的可见性。

    3. 记录和undo

    记录的格式:

      每一条记录都包括:主键,trx_id, undo_point, columns
      undo_point指向了行记录的前映像,一致性版本就是通过undo来构造。

    比如测试用例:
    session1:
      create table test(id int primary key, name varchar(100));
      insert into test values(1, 'xxxx');
      commit;
    session2:
      update test set name='yyyy' where id=1;

    其形成的记录的格式如下图所示:

      

    这里只体现了undo的一个链表,我们称为undo的深度链表,用于实现mvcc。

    还存在一个undo的链表,是一个广度链表,记录了这个事务的所有undo,用于rollback,回滚事务。下一篇blog介绍undo相关的内容。

    3. 可见性判断

    函数:read_view_sees_trx_id。


    read_view中保存了当前全局的事务的范围:
    【low_limit_id, up_limit_id】

    1. 当行记录的事务ID小于当前系统的最小活动id,就是可见的。
      if (trx_id < view->up_limit_id) {
        return(TRUE);
      }
    2. 当行记录的事务ID大于当前系统的最大活动id,就是不可见的。
      if (trx_id >= view->low_limit_id) {
        return(FALSE);
      }
    3. 当行记录的事务ID在活动范围之中时,判断是否在活动链表中,如果在就不可见,如果不在就是可见的。
      for (i = 0; i < n_ids; i++) {
        trx_id_t view_trx_id
          = read_view_get_nth_trx_id(view, n_ids - i - 1);

        if (trx_id <= view_trx_id) {
        return(trx_id != view_trx_id);
        }
      }

    4. 事务隔离级别的影响

    但是:对于两张不同的事务隔离级别
      tx_isolation='READ-COMMITTED': 语句级别的一致性:只要当前语句执行前已经提交的数据都是可见的。
      tx_isolation='REPEATABLE-READ'; 语句级别的一致性:只要是当前事务执行前已经提交的数据都是可见的。

    针对这两张事务的隔离级别,使用相同的可见性判断逻辑是如何做到不同的可见性的呢?

    这里就要看看read_view的生成机制:

    1. read-commited:
      函数:ha_innobase::external_lock

      if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
        && trx->global_read_view) {
        /* At low transaction isolation levels we let
        each consistent read set its own snapshot */
    
      read_view_close_for_mysql(trx);

    即:在每次语句执行的过程中,都关闭read_view, 重新在row_search_for_mysql函数中创建当前的read_view。
    这样就可以根据当前的全局事务链表创建read_view的事务区间,实现read committed隔离级别。

    2. repeatable read:
      在repeatable read的隔离级别下,创建事务trx结构的时候,就生成了当前的global read view。
      使用trx_assign_read_view函数创建,一直维持到事务结束,这样就实现了repeatable read隔离级别。

  • 相关阅读:
    ssm依赖
    NSNotificationCenter详解
    Objective-C语法之代码块(block)的使用
    IOS UI UITableView
    IOS 多线程(4) --线程通讯
    IOS 多线程(3) --线程安全
    IOS 多线程(2) --NSThread
    IOS 多线程(1) --基础知识
    IOS UI TextFiled常用总结
    IOS UI TabBar标签栏的使用
  • 原文地址:https://www.cnblogs.com/xpchild/p/3925382.html
Copyright © 2020-2023  润新知