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
Install ruby
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.