MySQL 5.6 global read lock 介紹

jesselyu發表於2015-03-03

 

global read lock

Global_read_lock類實現global read lock。它有兩個私有成員,分別在globalcommit域保護global read lock

1. 
m_mdl_global_shared_lock

MDL_ticket型別,用於”GLOBAL” namespace內保護global read lock,阻止所有DDL語句。
實現方法是會在
GLOBAL namespace層級獲取MDL shared鎖。我們知道,對一個object 修改時,需要獲取GLOBAL級別的MDL IXIntension 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

執行緒T2update tab1 set b=3         #此時被row-level lock堵住

執行緒T3flush tables with read lock    #被執行緒T2堵住,因為需要關閉表

接下來T1 commit事務,這將被T3堵住。T1堵住T2T2堵住T3T3堵住T1

由此,死鎖產生。所以read lockcommit lock分開到第1和第3步實現才是安全的。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30088583/viewspace-1447289/,如需轉載,請註明出處,否則將追究法律責任。

相關文章