ITPub博客

首页 > 数据库 > MySQL > MySQL 5.6 global read lock 介绍

MySQL 5.6 global read lock 介绍

原创 MySQL 作者:jesselyu 时间:2015-03-03 23:32:57 0 删除 编辑

 

global read lock

Global_read_lock类实现global read lock。它有两个私有成员,分别在global和commit域保护global read lock。

1. 
m_mdl_global_shared_lock

MDL_ticket类型,用于”GLOBAL” namespace内保护global read lock,阻止所有DDL语句。
实现方法是会在
GLOBAL namespace层级获取MDL shared锁。我们知道,对一个object 修改时,需要获取GLOBAL级别的MDL IX(Intension Exclusive)锁。
由于
MDL_shared 与MDL_INTENSION_EXCLUSIVE的排斥,所以就达到阻止其它DDL的目的。

2. 
m_mdl_blocks_commits_lock
DML_ticket类型,用于”COMMIT” namespace,阻止所有事务commit,即DML操作。


上面两者的结合,完整实现了global read lock的意义。

 

通常来讲,global read lock的实现也是分两步的,首先是lock_global_read_lock(),其次是make_global_read_lock_block_commit。但是第二步是可选的,如果没有第二步,commit事务将被允许。

 

Flush tables with read lock

    Flush tables with read lock也是获取global read lock的方法之一。但是flush tables with read lock在上面两步中插入了另外一步,就是close_cached_tables()。这一步的作用是,关闭已经打开的table。

但是这一步本来也会被堵,原因想必大家都非常清楚,那就是之前还有被操作的并持续打开的表。

所以这里会有一个问题:为什么m_mdl_global_shared_lock()和m_mdl_blocks_commits_lock()不能合到一起,作为第一步,然后再close_cached_tables()?

原因很简单,这样会导致死锁。假设这样一个场景:

线程T1: select * from tab1 for update

线程T2: update tab1 set b=3         #此时被row-level lock堵住

线程T3: flush tables with read lock    #被线程T2堵住,因为需要关闭表

接下来T1 commit事务,这将被T3堵住。T1堵住T2,T2堵住T3,T3堵住T1。

由此,死锁产生。所以read lock和commit lock分开到第1和第3步实现才是安全的。

 

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/30088583/viewspace-1447289/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
资深Oracle RAC及Exadata部署实施运维专家,曾从事PostgreSQL内核开发与性能优化。丰富的大规模数据库管理架构设计经验。目前在阿里巴巴从事数据库架构工作以及新技术引进,对分布式存储,云计算及并行编程有一定研究。技术讨论请加微信:ljs521688

注册时间:2015-01-01

  • 博文量
    43
  • 访问量
    574868