zoukankan      html  css  js  c++  java
  • 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隔离级别。

  • 相关阅读:
    Attach Files to Objects 将文件附加到对象
    Provide Several View Variants for End-Users 为最终用户提供多个视图变体
    Audit Object Changes 审核对象更改
    Toggle the WinForms Ribbon Interface 切换 WinForms 功能区界面
    Change Style of Navigation Items 更改导航项的样式
    Apply Grouping to List View Data 将分组应用于列表视图数据
    Choose the WinForms UI Type 选择 WinForms UI 类型
    Filter List Views 筛选器列表视图
    Make a List View Editable 使列表视图可编辑
    Add a Preview to a List View将预览添加到列表视图
  • 原文地址:https://www.cnblogs.com/xpchild/p/3925382.html
Copyright © 2011-2022 走看看