Multi-version concurrency control MVCC achieve repeatable read

Multi-version concurrency control MVCC achieve repeatable read

reference

高性能 MySQL 第3版 1.4 多版本并发控制

MVCC is implemented in a snapshot at a point in time by saving the data. MVCC different implementations of different storage engines, typically optimistic concurrency and pessimistic concurrency control.

InnoDB is MVCC to achieve

noun

系统版本号 事务版本号 记录创建时间 记录删除时间

The InnoDB MVCC is hidden by storing two columns implemented after each line recording. Save time to create a line, delete a saved time line. Certainly not the time value is stored, but the system version number. Each start a new transaction, the system will automatically increment the version number. Transaction system version number is the version number of the start time of the transaction.

Repeatable Read the execution process of MVCC

事务版本号是事务开始时刻的系统版本号 每开始一个新的事务,系统版本号都会自动递增

select

Returns the record following condition is satisfied

创建时间 <= 当前事务版本号 && ( 删除时间 == null || 删除时间 > 当前事务版本号 )

insert

插入记录的创建时间 = 当前系统版本号

Created newly inserted record is set to the current system version number, delete the time is null.

delete

被删除记录的删除时间 = 当前系统版本号

Delete to delete the recorded time is set to the current system version number, tombstone, and can not really delete data.

update

被更新记录的原记录的删除时间 = 当前系统版本号 新插入记录的创建时间 = 当前系统版本号

The time is updated to delete the original record set to the current system version number, that is a logical delete the original record. Insert a new record, which was created for the current system version number.

MVCC only read 2-level working in isolation read committed and repeatable, and other isolation levels are not using this mechanism. read uncommitted always read the latest data line, rather than in line with the current transaction version of the row, seriablizable lock on all rows read.

MVCC source parsing

http://www.ningoo.net/html/tag/mysql

http://blog.sina.com.cn/s/blog_4673e603010111ty.html

https://blog.csdn.net/joy0921/article/details/80128857

https://blog.csdn.net/u012919352/article/details/87984786

https://mp.weixin.qq.com/s?__biz=MzIxNTQ3NDMzMw==&mid=2247483670&idx=1&sn=751d84d0ce50d64934d636014abe2023&chksm=979688e4a0e101f2a51d1f06ec75e25c56f8936321ae43badc2fe9fc1257b4dc1c24223699de&scene=21#wechat_redirect

https://dev.mysql.com/doc/refman/5.5/en/innodb-consistent-read.html

https://blog.csdn.net/joy0921/article/details/80128857

Hide the three fields

row_id db_trx_id db_roll_pt ID rollback transaction record pointer ID

  • First, each row of data as well as InnoDB to roll back a DB_ROLL_PT pointer for pointing to a history of the former version of the row modification

  • When inserting a new data is recorded on the corresponding rollback pointer is NULL.
  • If the current record has a primary key, the record ID is not generated row_id
  • read view undo log

Determined by rows read view is visible

Specific determination process is as follows:

Under RR isolation level, at the time of each transaction began, all the active transactions will copy the current system to a list (read view)
under RC isolation level, when the start of each statement, will the current system All active transactions to a copy of the list (read view)

  • "Tang Cheng -2016PG Assembly - multi-database version implements insider .pdf"

https://myslide.cn/slides/3542

MySQL · · InnoDB source code analysis of the read view, rollback segments and purge process Introduction https://yq.aliyun.com/articles/560506

mysql> show engine innodb status\G;
------------
TRANSACTIONS
------------
Trx id counter AC16
Purge done for trx's n:o < AC14 undo n:o < 0
History list length 1079
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION AC15, not started
MySQL thread id 4, OS thread handle 0x43c, query id 133 localhost 127.0.0.1 root
show engine innodb status
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX\G;

https://www.cnblogs.com/itcomputer/articles/5084611.html

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX\G;
*************************** 1. row ***************************
                    trx_id: AC16
                 trx_state: RUNNING
               trx_started: 2019-08-03 11:50:27
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 0
       trx_mysql_thread_id: 10
                 trx_query: NULL
       trx_operation_state: NULL
         trx_tables_in_use: 0
         trx_tables_locked: 0
          trx_lock_structs: 0
     trx_lock_memory_bytes: 376
           trx_rows_locked: 0
         trx_rows_modified: 0
   trx_concurrency_tickets: 0
       trx_isolation_level: READ COMMITTED
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 10000
1 row in set (0.00 sec)

I opened the two transactions AC18 AC17, transaction counter = AC19

mysql> show engine innodb status\G;
------------
TRANSACTIONS
------------
Trx id counter AC19
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX\G;
*************************** 1. row ***************************
                    trx_id: AC18
                 trx_state: RUNNING
               trx_started: 2019-08-03 11:56:40
*************************** 2. row ***************************
                    trx_id: AC17
                 trx_state: RUNNING
               trx_started: 2019-08-03 11:55:08
            
mysql> SELECT tx.trx_id
    -> FROM information_schema.innodb_trx tx
    -> WHERE tx.trx_mysql_thread_id = connection_id();
+--------+
| trx_id |
+--------+
| AC17   |
+--------+
1 row in set (0.07 sec)
mysql> SELECT tx.trx_id
    -> FROM information_schema.innodb_trx tx
    -> WHERE tx.trx_mysql_thread_id = connection_id();
+--------+
| trx_id |
+--------+
| AC18   |
+--------+
1 row in set (0.00 sec)
mysql> SELECT tx.trx_id
    -> FROM information_schema.innodb_trx tx
    -> WHERE tx.trx_mysql_thread_id = connection_id();
Empty set (0.00 sec)

https://www.jdon.com/51517

RR isolation level (except Gap lock) and RC different isolation level is to create a snapshot of the time difference. RR isolation level at the start time of the transaction, rather the first read read view of creation; RC isolation level is the start time to create read view in the statement.

Create / read view closed needs to hold trx_sys-> mutex, degrade system performance, this version 5.7 is optimized, read view when the transaction commits session will cache read-only transaction.

Read view中保存的trx_sys状态主要包括

low_limit_id:high water mark,大于等于view->low_limit_id的事务对于view都是不可见的
up_limit_id:low water mark,小于view->up_limit_id的事务对于view一定是可见的
low_limit_no:trx_no小于view->low_limit_no的undo log对于view是可以purge的
rw_trx_ids:读写事务数组

Read view创建之后,读数据时比较记录最后更新的trx_id和view的 high/low water mark和读写事务数组即可判断可见性。
如前所述,如果记录最新数据是当前事务trx的更新结果,对应当前read view一定是可见的。

除此之外可以通过high/low water mark快速判断:

trx_id < view->up_limit_id的记录对于当前read view是一定可见的;
trx_id >= view->low_limit_id的记录对于当前read view是一定不可见的;
如果trx_id落在[up_limit_id, low_limit_id),需要在活跃读写事务数组查找trx_id是否存在,如果存在,记录对于当前read view是不可见的。
storage/innobase/read/read0read.c
http://blog.sina.com.cn/s/blog_4673e603010111ty.html

storage/innobase/include/read0read.ic

view->n_trx_ids 数量
view->up_limit_id
view->low_limit_id
/*********************************************************************//**
Checks if a read view sees the specified transaction.
@return TRUE if sees */
UNIV_INLINE
ibool   
read_view_sees_trx_id(
/*==================*/
    const read_view_t*  view,   /*!< in: read view */
    trx_id_t        trx_id) /*!< in: trx id */
{
    ulint   n_ids;
    ulint   i;

    if (trx_id < view->up_limit_id) {

        return(TRUE);
    }

    if (trx_id >= view->low_limit_id) {

        return(FALSE);
    }

    /* We go through the trx ids in the array smallest first: this order
    may save CPU time, because if there was a very long running
    transaction in the trx id array, its trx id is looked at first, and
    the first two comparisons may well decide the visibility of trx_id. */

    n_ids = view->n_trx_ids;

    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);
        }
    }

    return(TRUE);
}

storage/innobase/include/read0read.h

struct read_view_struct{
    ulint       type;   /*!< VIEW_NORMAL, VIEW_HIGH_GRANULARITY */
    undo_no_t   undo_no;/*!< 0 or if type is
                VIEW_HIGH_GRANULARITY
                transaction undo_no when this high-granularity
                consistent read view was created */
    trx_id_t    low_limit_no;
                /*!< The view does not need to see the undo
                logs for transactions whose transaction number
                is strictly smaller (<) than this value: they
                can be removed in purge if not needed by other
                views */
    trx_id_t    low_limit_id;
                /*!< The read should not see any transaction
                with trx id >= this value. In other words,
                this is the "high water mark". */
    trx_id_t    up_limit_id;
                /*!< The read should see all trx ids which
                are strictly smaller (<) than this value.
                In other words,
                this is the "low water mark". */
    ulint       n_trx_ids;
                /*!< Number of cells in the trx_ids array */
    trx_id_t*   trx_ids;/*!< Additional trx ids which the read should
                not see: typically, these are the active
                transactions at the time when the read is
                serialized, except the reading transaction
                itself; the trx ids in this array are in a
                descending order. These trx_ids should be
                between the "low" and "high" water marks,
                that is, up_limit_id and low_limit_id. */
    trx_id_t    creator_trx_id;
                /*!< trx id of creating transaction, or
                0 used in purge */
    UT_LIST_NODE_T(read_view_t) view_list;
                /*!< List of read views in trx_sys */
};
trx_id_t    trx_id = row_get_rec_trx_id(rec, index, offsets); //获取记录上的TRX_ID这里需要解释下,我们一个查询可能满足的记录数有多个。那我们每读取一条记录的时候就要根据这条记录上的TRX_ID判断这条记录是否可见
return(view->changes_visible(trx_id, index->table->name)); //判断记录可见性
--------------------- 
作者:仲培艺 
来源:CSDN 
原文:https://blog.csdn.net/joy0921/article/details/80128857 
版权声明:本文为博主原创文章,转载请附上博文链接!
对于不可见的记录都是通过row_vers_build_for_consistent_read函数查询UNDO构建老版本记录,直到记录可见。

这里需要说明一点 不同的事务隔离级别,可见性的实现也不一样:

READ-COMMITTED 
事务内的每个查询语句都会重新创建Read View,这样就会产生不可重复读现象发生

REPEATABLE-READ 
事务内开始时创建Read View , 在事务结束这段时间内 每一次查询都不会重新重建Read View , 从而实现了可重复读。

trx_sys->trx_list

https://blog.csdn.net/longxibendi/article/details/42012629

Read view创建之后,读数据时比较记录最后更新的trx_id和view的high/low water mark和读写事务数组即可判断可见性。

https://cloud.tencent.com/developer/ask/210171

https://blog.jcole.us/innodb/

https://github.com/jeremycole/innodb_ruby/wiki

[root@instance-fjii60o3 ~]# gem install innodb_ruby
-bash: gem: command not found

https://rubygems.org/

[root@instance-fjii60o3 develop]# wget https://rubygems.org/rubygems/rubygems-3.0.4.tgz
-rw-r--r-- 1 root root    883664 Jun 14 11:35 rubygems-3.0.4.tgz

Linux installation gem https://www.csdn.net/gather_2b/MtjaUgysNDYzNS1ibG9n.html

[root@instance-fjii60o3 rubygems-3.0.4]# bin/gem
/usr/bin/env: ruby: No such file or directory

Linux install ruby

https://www.cnblogs.com/xuliangxing/p/7132656.html?utm_source=itdadao&utm_medium=referral

[root@instance-fjii60o3 rubygems-3.0.4]# yum list install | grep ruby
Error: No matching Packages to list
[root@instance-fjii60o3 rubygems-3.0.4]# yum list installed | grep ruby
ruby.x86_64                            2.0.0.648-35.el7_6             @updates  
ruby-irb.noarch                        2.0.0.648-35.el7_6             @updates  
ruby-libs.x86_64                       2.0.0.648-35.el7_6             @updates  
rubygem-bigdecimal.x86_64              1.2.0-35.el7_6                 @updates  
rubygem-io-console.x86_64              0.4.2-35.el7_6                 @updates  

Linux install git

[root@instance-fjii60o3 ~]# yum install git
[root@instance-fjii60o3 ~]# git clone https://github.com/jeremycole/innodb_ruby.git
[root@instance-fjii60o3 rubygems-3.0.4]# gem install --user-install innodb_ruby

WARNING:  You don't have /root/.gem/ruby/bin in your PATH,
      gem executables will not run.

Installation and use of learning Ruby RubyGems (gem) Package Manager

https://blog.csdn.net/luyaran/article/details/85698936

[root@instance-fjii60o3 rubygems-3.0.4]# yum list installed | grep ruby
Existing lock /var/run/yum.pid: another copy is running as pid 11250.
Another app is currently holding the yum lock; waiting for it to exit...
  The other application is: yum
    Memory :  90 M RSS (408 MB VSZ)
    Started: Sat Aug  3 14:39:05 2019 - 16:44 ago
    State  : Sleeping, pid: 11250

System active transaction ID

MVCC visibility https://blog.csdn.net/taozhi20084525/article/details/19501075

[root@instance-fjii60o3 develop]# yum localinstall mysql-community-server-8.0.13-1.el7.x86_64.rpm 
Loaded plugins: langpacks, versionlock
Existing lock /var/run/yum.pid: another copy is running as pid 11250.
Another app is currently holding the yum lock; waiting for it to exit...
  The other application is: yum
    Memory :  89 M RSS (408 MB VSZ)
    Started: Sat Aug  3 14:39:05 2019 - 1:15:13 ago
    State  : Traced/Stopped, pid: 11250
[root@instance-fjii60o3 develop]# tar -xvf mysql-8.0.13-1.el7.x86_64.rpm-bundle.tar -C mysql8.0
mysql-community-client-8.0.13-1.el7.x86_64.rpm
mysql-community-embedded-compat-8.0.13-1.el7.x86_64.rpm
mysql-community-libs-8.0.13-1.el7.x86_64.rpm
mysql-community-server-8.0.13-1.el7.x86_64.rpm
tar: Unexpected EOF in archive
tar: rmtlseek not stopped at a record boundary
tar: Error is not recoverable: exiting now

Ruby Tools innodb record structure analysis

https://cloud.tencent.com/developer/ask/210171

https://github.com/jeremycole/innodb_ruby/wiki

  1. Install ruby

  2. gem install innodb_ruby

    innodb format parsing tools

https://rubygems.org/gems/innodb_ruby/versions

https://www.cnblogs.com/zengkefu/p/5678356.html

Linux view the file size

[root@instance-fjii60o3 ~]# du -sh MySQL-5.5.62-1.el7.x86_64.rpm-bundle.tar 
2.1M    MySQL-5.5.62-1.el7.x86_64.rpm-bundle.tar
[root@instance-fjii60o3 ~]# du -sh develop/
1.1G    develop/

Five minutes to understand Mysql row-level locking - "get to the bottom Mysql lock" https://blog.csdn.net/zcl_love_wx/article/details/81983267

Mysql There are three levels of locking: table-level locks, page-level locking, row-level locking

  • Each time the lock is a row of data locking mechanism is the row-level locking (row-level). Row-level locking is not locked MySQL own manner, but by other storage engines themselves implemented

  • Use row-level locking of the main InnoDB storage engine, and MySQL distributed storage engine NDBCluster

InnoDB's row-level locking is also divided into two types: shared locks and exclusive locks , and in the locking mechanism of the implementation process in order to allow row-level locking and table-level locking coexist , InnoDB also uses intent locks (table-level locking) of concept, and we will have a shared intent locks and intent exclusive lock both.

Guess you like

Origin www.cnblogs.com/mozq/p/12093752.html