[关闭]
@lixiang9194 2020-09-24T22:50:32.000000Z 字数 3537 阅读 1569

mysql 源码:mvcc一致性读的可见性实现

未分类


一、环境准备

  1. CREATE TABLE `students` (
  2. `id` INT ( 11 ) NOT NULL,
  3. `name` VARCHAR ( 255 ) DEFAULT '',
  4. `age` INT ( 11 ) DEFAULT 0,
  5. `sex` TINYINT ( 1 ) DEFAULT 0,
  6. `addr` VARCHAR ( 255 ) DEFAULT '',
  7. PRIMARY KEY ( `id` ),
  8. KEY `age` ( `age` ),
  9. KEY `name_age_sex` ( `name`, `age`, `sex` ) USING BTREE
  10. ) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
  11. Insert into students values(1, 'zhangsan', 21, 1, 'beijing');
  12. Insert into students values(2, 'xiaohong', 22, 2, 'shandong');
  13. Insert into students values(3, 'jack', 23, 1, 'hebei');

二、问题

  1. readview 的开启、初始化流程
  2. readview 的关闭
  3. 如何确定当前事务进行当前读或快照读
  4. 聚簇索引、非聚簇索引快照读的异同

三、实验

1. readview 的开启、初始化流程

断点:

开启方式:

  1. ReadView *trx_assign_read_view(trx_t *trx)
  2. {
  3. ...
  4. } else if (!MVCC::is_view_active(trx->read_view)) {
  5. trx_sys->mvcc->view_open(trx->read_view, trx);
  6. }
  7. return (trx->read_view);
  8. }
  9. dberr_t row_search_mvcc(...) {
  10. ...
  11. // row0sel.cc:4813
  12. if (!srv_read_only_mode) {
  13. trx_assign_read_view(trx);
  14. }
  15. ...
  16. }

实验:

  1. session A:
  2. begin;
  3. update students set name = "zhangsanA" where id=1;
  4. //select * from students;
  5. session B:
  6. begin;
  7. update students set name = "jackB" where id=3;
  8. commit;
  9. session A:
  10. select * from students;
  11. rollback;
2. readview 的关闭

断点:

  1. int ha_innobase::external_lock(THD *thd, int lock_type)
  2. {
  3. ...
  4. else if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
  5. MVCC::is_view_active(trx->read_view)) {
  6. mutex_enter(&trx_sys->mutex);
  7. trx_sys->mvcc->view_close(trx->read_view, true);
  8. ...
  9. }
  1. set session transaction isolation level read committed;
3. 如何确定本次进行当前读、快照读

影响因素:sql(select、select for update)、隔离级别(ru、rc、rr、se)
断点:b row0sel.cc:5193(row_search_mvcc)

  1. show variables like "%isolation%”;
  1. //加锁当前读
  2. if (prebuilt->select_lock_type != LOCK_NONE) {
  3. auto row_to_range_relation = row_compare_row_to_range(
  4. set_also_gap_locks, trx, unique_search, index, clust_index, rec, comp,
  5. mode, direction, search_tuple, offsets, moves_up, prebuilt);
  6. //确定锁类型
  7. if (row_to_range_relation.row_can_be_in_range) {
  8. if (row_to_range_relation.gap_can_intersect_range) {
  9. lock_type = LOCK_ORDINARY;
  10. } else {
  11. lock_type = LOCK_REC_NOT_GAP;
  12. }
  13. } else {
  14. if (row_to_range_relation.gap_can_intersect_range) {
  15. lock_type = LOCK_GAP;
  16. } else {
  17. err = DB_RECORD_NOT_FOUND;
  18. goto normal_return;
  19. }
  20. }
  21. //加锁
  22. err = sel_set_rec_lock(pcur, rec, index, offsets, prebuilt->select_mode,
  23. prebuilt->select_lock_type, lock_type, thr, &mtr);
  24. //当前读
  25. row_sel_build_committed_vers_for_mysql(
  26. clust_index, prebuilt, rec, &offsets, &heap, &old_vers,
  27. need_vrow ? &vrow : nullptr, &mtr);
  28. } else {
  29. //无锁 一致性读
  30. if (trx->isolation_level == TRX_ISO_READ_UNCOMMITTED) {
  31. //读未提交,直接返回最新记录
  32. } else if (index == clust_index) {
  33. //聚簇索引可见性判断
  34. if (srv_force_recovery < 5 &&
  35. !lock_clust_rec_cons_read_sees(rec, index, offsets,
  36. trx_get_read_view(trx))) {
  37. err = row_sel_build_prev_vers_for_mysql(
  38. trx->read_view, clust_index, prebuilt, rec, &offsets, &heap,
  39. &old_vers, need_vrow ? &vrow : nullptr, &mtr,
  40. prebuilt->get_lob_undo());
  41. }
  42. } else {
  43. //二级索引可见性判断
  44. if (!srv_read_only_mode &&
  45. !lock_sec_rec_cons_read_sees(rec, index, trx->read_view)) {
  46. //如果不可见,先尝试索引下推
  47. switch (row_search_idx_cond_check(buf, prebuilt, rec, offsets)) {
  48. case ICP_NO_MATCH:
  49. goto next_rec;
  50. case ICP_OUT_OF_RANGE:
  51. err = DB_RECORD_NOT_FOUND;
  52. goto idx_cond_failed;
  53. case ICP_MATCH:
  54. goto requires_clust_rec;
  55. }
  56. }
  57. }
  58. }

数据更新:

  1. session B:
  2. begin;
  3. select * from students;
  4. session A:
  5. begin;
  6. update students set age=23 where id=1;
  7. commit;
  8. session B:
  9. select * from students for update; //当前读
  10. select * from students; //聚簇索引
  11. select * from students where age=23 and name like "%ac%"; //二级索引

四、参考文档

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注