日志是innodb1個(gè)非常重要的模塊,在innodb中有兩類日志:redo log和undo log。其中redolog日志是用來(lái)做數(shù)據(jù)異常恢復(fù)和數(shù)據(jù)庫(kù)重啟時(shí)頁(yè)數(shù)據(jù)同步恢復(fù)的,redo log是建立在在mini transaction基礎(chǔ)上。數(shù)據(jù)庫(kù)在履行事務(wù)時(shí),通過minitransaction產(chǎn)生redo log來(lái)保證事務(wù)的持久性。
mini-transcation是用來(lái)實(shí)現(xiàn)innodb的物理邏輯日志的寫入和頁(yè)恢復(fù)的,通過mini-transcation來(lái)保證并發(fā)事務(wù)操作和數(shù)據(jù)庫(kù)異常是頁(yè)的1致性。為了得到頁(yè)的1致性,mini-transaction遵守以下3個(gè)協(xié)議:
1. The FIX Rules
2. Write-Ahead Log
3. Force-log-at-commit
The FIX Rules規(guī)定以下:
修改1個(gè)頁(yè)需要取得該頁(yè)的x-latch
訪問1個(gè)頁(yè)是需要取得該頁(yè)的s-latch或x-latch
持有該頁(yè)的latch直到修改或訪問該頁(yè)的操作完成
Write-Ahead Log的意思就是如果1個(gè)頁(yè)操作在寫入到持久裝備時(shí),必須內(nèi)存中相對(duì)應(yīng)的日志寫入到持久化裝備中。每一個(gè)頁(yè)有1個(gè)LSN,每次頁(yè)修改需要保護(hù)這個(gè)LSN,當(dāng)1個(gè)頁(yè)需要寫入到持久化裝備時(shí),要求內(nèi)存中小于該頁(yè)LSN的日志先寫入到持久化裝備中。日志寫完后,先Fixed這個(gè)頁(yè)的latch,再將內(nèi)存中的頁(yè)刷盤。完成刷盤后,釋放頁(yè)latch。這里遵守The FIX Rules協(xié)議。
1個(gè)事務(wù)可以同時(shí)修改了多個(gè)頁(yè),Write-AheadLog單個(gè)數(shù)據(jù)頁(yè)的1致性,沒法保證事務(wù)的持久性。Force -log-at-commit要求當(dāng)1個(gè)事務(wù)提交時(shí),其產(chǎn)生所有的mini-transaction日志必須刷到持久裝備中。這樣即便在頁(yè)數(shù)據(jù)刷盤的時(shí)候宕機(jī),也能夠通過日志進(jìn)行redo恢復(fù)。
innodb是采取mini-transaction來(lái)構(gòu)建操作的物理邏輯日志的,在事務(wù)履行的時(shí)候,會(huì)通過mtr來(lái)保證頁(yè)的數(shù)據(jù)1致性和持久性。mini-transaction是通過1個(gè)mtr_t的結(jié)構(gòu)來(lái)實(shí)現(xiàn)mini-transaction的3個(gè)協(xié)議。mtr_t的定義以下:
其中成員memo是個(gè)latch持有狀態(tài)的數(shù)組列表,采取的是dyn_array_t的動(dòng)態(tài)內(nèi)存結(jié)構(gòu)來(lái)保存的,每一個(gè)單元存儲(chǔ)的是mtr_memo_slot_t這樣的結(jié)構(gòu)。定義以下:
latch類型以下:
MTR_MEMO_PAGE_S_FIX /*rw_locks-latch*/
MTR_MEMO_PAGE_X_FIX /*rw_lockx-latch*/
MTR_MEMO_BUF_FIX /*buf_block_t*/
MTR_MEMO_S_LOCK /*rw_lock s-latch*/
MTR_MEMO_X_LOCK /*rw_lock x-latch*/
memo的latch管理接口
mtr_memo_push 取得1個(gè)latch,并將狀態(tài)信息存入mtr memo當(dāng)中
mtr_release_s_latch_at_savepoint 釋放memo偏移savepoint的slot鎖狀態(tài)
mtr_memo_contains 判斷鎖對(duì)象是不是在memo當(dāng)中
mtr_memo_slot_release 釋放slot鎖的控制權(quán)
mtr_memo_pop_all
釋放所有memo中的鎖的控制權(quán)
mt_t中的log成員是也是1個(gè)dyn_array_t動(dòng)態(tài)結(jié)構(gòu)的內(nèi)存,用來(lái)保存mtr產(chǎn)生的日志信息。日志的寫入是通過mtr0log.h來(lái)寫入的。這里指的1提的是日志格式,日志格式是有日志頭和日志體組成,日志頭信息是由type、space和page no組成,由mlog_write_initial_log_record_fast函數(shù)寫入到mtr_t的log中的。以下是1個(gè)比較具體的示意圖:
log body的數(shù)據(jù)寫入是通過mtr0log.h中的日志寫入方法進(jìn)行寫入的。每寫入1跳操作日志,n_log_recs會(huì)加1.
標(biāo)識(shí)modifications是標(biāo)識(shí)是不是有page的數(shù)據(jù)改動(dòng),如果有,在mtr_commit調(diào)用時(shí)會(huì)先將mtr->log刷盤,然后釋放mtr所有的所控制權(quán)。日志會(huì)1定會(huì)在mtr結(jié)束時(shí)刷盤,這符合Force-log-at-commit的規(guī)定。日志寫入調(diào)用的是log_write_low這個(gè)函數(shù)。
上一篇 生成隨機(jī)數(shù)工具