內(nèi)存并發(fā)控制
為了維護(hù)內(nèi)存結(jié)構(gòu)的一致性,比如Dictionary cache灼芭、sync array有额、trx system等結(jié)構(gòu)。
InnoDB并沒有直接使用glibc提供的庫彼绷,而是自己封裝了兩類:
- 一類是mutex巍佑,實(shí)現(xiàn)內(nèi)存結(jié)構(gòu)的串行化訪問。
- 一類是rw lock寄悯,實(shí)現(xiàn)讀寫阻塞萤衰,讀讀并發(fā)的訪問的讀寫鎖。
B+樹并發(fā)控制
B+樹的并發(fā)控制主要分2個(gè)方面猜旬,一個(gè)是節(jié)點(diǎn)中內(nèi)容的并發(fā)控制脆栋、另一個(gè)是樹結(jié)構(gòu)的并發(fā)控制,比如樹高的變化洒擦、頁的分裂等等椿争。
為了實(shí)現(xiàn)上述兩方面的并發(fā)控制。
5.6版本
InnoDB為每一個(gè)index熟嫩,維護(hù)兩種rw lock:
- index級(jí)別的秦踪,用于保護(hù)B-Tree結(jié)構(gòu)不被破壞。
- block級(jí)別的邦危,用于保護(hù)block內(nèi)部結(jié)構(gòu)不被破壞,僅適用于葉子節(jié)點(diǎn)舍扰,非葉子節(jié)點(diǎn)不加鎖倦蚪。
rw lock分為S、X兩種模式边苹,如果設(shè)計(jì)到SMO陵且,需要對(duì)index級(jí)別的rw lock加X鎖,這樣的實(shí)現(xiàn)帶來的好處是代碼實(shí)現(xiàn)非常簡(jiǎn)單, 但是缺點(diǎn)也很明顯由于在SMO 操作的過程中, 讀取操作也是無法進(jìn)行的, 并且SMO 操作過程可能有IO 操作, 帶來的性能抖動(dòng)非常明顯
具體參考http://mysql.taobao.org/monthly/2020/06/02/
5.7版本
主要有這兩個(gè)改動(dòng)
- rw-lock引入了sx模式个束,優(yōu)化了阻塞讀的問題慕购。
- block級(jí)別的rw-lock,非葉子幾點(diǎn)也加鎖茬底。
S沪悲、X、SX三個(gè)模式的兼容關(guān)系如下:
/*
LOCK COMPATIBILITY MATRIX
S SX X
S + + -
SX + - -
X - - -
*/
加鎖的具體流程:
- 如果是一個(gè)查詢請(qǐng)求
- 那么首先把btree index->lock S LOCK
- 然后沿著搜索btree 路徑, 遇到的non-leaf node page 都加 S LOCK
- 然后直到找到 leaf node 以后, 對(duì)leaft node page 也是 S LOCK, 然后把index-> lock 放開
image.png
2.修改請(qǐng)求的流程也參見http://mysql.taobao.org/monthly/2020/06/02/
這個(gè)page 的修改是否會(huì)引起 btree 的變化阱表? - 如果不會(huì), 那么很好, 對(duì)leaf node 執(zhí)行了X LOCK 以后, 修改完數(shù)據(jù)返回就可以
- 如果會(huì), 那么需要執(zhí)行悲觀插入操作, 重新遍歷btree. 這時(shí)候給index->lock 是加 SX LOCK。
因?yàn)橐呀?jīng)給btree 加上sx lock, 那么搜索路徑上的btree 的page 都不需要加 lock, 但是需要把搜索過程中的page 保存下來, 最后階段給搜索路徑上有可能發(fā)生結(jié)構(gòu)變化的page 加x lock较屿。
這樣就保證了在搜索的過程中, 對(duì)于read 操作的影響降到最低翩概。
只有在最后階段確定了本次修改btree 結(jié)構(gòu)的范圍, 對(duì)可能發(fā)生結(jié)構(gòu)變化的page 加X lock 以后, 才會(huì)有影響。
代碼實(shí)現(xiàn)
B樹的搜索入口函數(shù)為btr_cur_search_to_nth_level门岔,其參數(shù)latch_mode分為兩部分,低字節(jié)為如下的基本操作模式:
/** Latching modes for btr_cur_search_to_nth_level(). */
enum btr_latch_mode {
/** Search a record on a leaf page and S-latch it. */
BTR_SEARCH_LEAF = RW_S_LATCH,
/** (Prepare to) modify a record on a leaf page and X-latch it. */
BTR_MODIFY_LEAF = RW_X_LATCH,
/** Obtain no latches. */
BTR_NO_LATCHES = RW_NO_LATCH,
/** Start modifying the entire B-tree. */
BTR_MODIFY_TREE = 33,
/** Continue modifying the entire B-tree. */
BTR_CONT_MODIFY_TREE = 34,
/** Search the previous record. */
BTR_SEARCH_PREV = 35,
/** Modify the previous record. */
BTR_MODIFY_PREV = 36,
/** Start searching the entire B-tree. */
BTR_SEARCH_TREE = 37,
/** Continue searching the entire B-tree. */
BTR_CONT_SEARCH_TREE = 38
};
每種模式的加鎖流程可以參考:https://zhuanlan.zhihu.com/p/164705538
悲觀寫入
悲觀寫入因?yàn)闀?huì)涉及SMO,所以需要重新遍歷B Tree加鎖
row_ins_clust_index_entry
//這里是BTR_MODIFY_LEAF
----row_ins_clust_index_entry_low(flags, BTR_MODIFY_LEAF, index, n_uniq, entry, n_ext, thr, dup_chk_only)
--------btr_pcur_open //調(diào)用btr_cur_search_to_nth_level 查詢索引樹烤送,將cursor移動(dòng)到待插入記錄相應(yīng)的位置
------------btr_cur_optimistic_insert //樂觀插入
//如果插入失敗需要遍歷B樹寒随,此時(shí)是BTR_MODIFY_TREE
----row_ins_clust_index_entry_low(flags, BTR_MODIFY_TREE, index, n_uniq, entry, n_ext, thr, dup_chk_only)
--------btr_pcur_open //調(diào)用btr_cur_search_to_nth_level 查詢索引樹,將cursor移動(dòng)到待插入記錄相應(yīng)的位置
-----------btr_cur_optimistic_insert //樂觀插入
-----------btr_cur_pessimistic_insert //悲觀插入
http://static.kancloud.cn/taobaomysql/monthly/67063
http://mysql.taobao.org/monthly/2020/06/02/
https://zhuanlan.zhihu.com/p/164705538
http://liuyangming.tech/07-2019/InnoDB-Lock.html#insert%E7%9A%84rwlock
http://mysql.taobao.org/monthly/2017/10/03/
http://mysql.taobao.org/monthly/2018/09/01/