mysql5.7 : reduce lock_sys_t::mutex contention when converting implicit lock to an explicit lock
worklog: http://dev.mysql.com/worklog/task/?id=6899
rev: http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5743
背景:
1.什麼是隐式鎖
所謂的隐式鎖,可以了解成一個記錄标記,在記憶體的鎖對象hash中是不存在的。但我們在更新資料塊時,會進行如下操作:
#對于聚集索引,每次更改或插入記錄會同時寫入對應的事務id和復原段指針
#對于二級索引,每次更改/插入二級索引記錄,會更新二級索引頁的最大事務id。
我們知道,innodb在插入記錄時,是不加鎖的。如果事務a插入記錄rec1,且未送出時。事務b嘗試update rec1,這時候事務b會去判斷rec1上儲存的事務id是否活躍,如果活躍的話,那麼就 “幫助” 事務a 去建立一個鎖對象,加入到hash中,然後自身進入等待事務a狀态,也就是所謂的隐式鎖轉換為顯式鎖。
該worklog主要優化了該轉換的過程
原始邏輯
參考函數lock_rec_convert_impl_to_expl
0.找到修改或插入目前記錄的事務id (記做trx_id, 不持有鎖),如果不是活躍的事務id,不做操作,退出函數
1. acquire the lock_sys_t::mutex
2. (trx_rw_is_active)
acquire the trx_sys_t::mutex
scan the trx_sys_t::rw_trx_list for trx_id_t (only rw transactions can insert)
release the trx_sys_t::mutex
return handle if transaction found
3. if handle found then
do an implicit to explicit record conversion
endif
4. release the lock_sys_t::mutex
可以看到,在該操作的過程中,全程持有lock_sys mutex,持有鎖的原因是防止事務送出掉.當讀寫事務連結清單非常長時(例如高并發寫入時),這種開銷将是不可接受的。
優化後的邏輯
if handle found then
acquire the trx_t::mutex
increment trx_t::n_ref_count ——增加計數,表示對這個事務進行隐式鎖轉換
release the trx_t::mutex
acquire the lock_sys_t::mutex
release the lock_sys_t::mutex
decrement trx_t::n_ref_count ——完成隐式轉換,重置計數
這裡實際上在查找目前記錄上的活躍事務id時,直接傳回的是其事務對象,而不是事務id
在事務commit時進行檢查 (函數lock_trx_release_locks)
if trx_t::n_ref_count > 0
while (trx_t::n_ref_count > 0) ———>目前正在做隐式到顯式的鎖轉換
sleep/delay
acquire the trx_t::n_ref_count
end while
通過該修改,我們可以在擷取活躍事務對象的時候無需持有lock sys mutex。在低并發下,可能沒有太多收益,但在高并發下,讀寫事務連結清單較長時,可能會影響到性能。
但該特性帶來的額外開銷是,事務在commit時需要檢查ref count,理論上鎖轉換過程應該很快.