MySQL5.7:新的日誌型別MLOG_FILE_NAME來避免崩潰恢復時掃描全部ibd

zhaiwx_yinfeng發表於2016-05-10

前言

對應 Worklog:http://dev.mysql.com/worklog/task/?id=7142

對應change log entry:

Incompatible Change: A new log record type (MLOG_FILE_NAME) is used to identify file-per-table tablespaces that have been modified since the last checkpoint. This enhancement simplifies tablespace discovery during crash recovery and eliminates scans on the file system prior to redo log application. For more information about the benefits of this enhancement, see Tablespace Discovery During Crash Recovery.

This enhancement changes the redo log format, requiring that MySQL be shut down cleanly before upgrading to or downgrading from MySQL 5.7.5.

問題:

改進的主要目的是為了消除在crash recovery時對檔案目錄的掃描,因為在innodb層無法根據redo log中的space id直接找到對應的檔案,因此需要開啟每個ibd的第一個page來進行判定。

新的修改簡化了上述邏輯,只有在一次checkpoint後被修改了的表才需要被讀取,其他的乾淨的表空間無需掃描。 在WL#7142中也處理了類似RENAME這樣的崩潰恢復邏輯,不在本文的討論範圍之內,後續單獨開文討論。

 

更改:

1.REDO LOG型別修改

MLOG_FILE_CREATE2、MLOG_FILE_CREATE:使用MLOG_FILE_NAME來代替

MLOG_FILE_RENAME:使用MLOG_FILE_RENAME2來代替

增加新型別:

MLOG_FILE_RENAME2:(space_id, first_page_number, filename, new_filename)

MLOG_FILE_CREATE:(space_id, name)

MLOG_CHECKPOINT

 

詳細見:enum mlog_id_t 列舉型別中關於各個型別的註釋

 

2.Mini Transaction事務提交時的修改

 

當需要修改資料頁時,在開啟一個mini transaction後,需要:

        mtr_start(&mtr);

mtr.set_named_space(index->space);

 

set_named_space 會將當前的space id儲存到mtr_t::m_named_space中

 

mtr_commit時,如果對資料做了修改,那麼在5.7中分為兩步。

入口函式:mtr_t::Command::execute

a.mtr_t::Command::prepare_write()

#根據set_named_space 函式設定的space id,進行判斷:

 

        fil_space_t*    space

= is_predefined_tablespace(m_impl->m_named_space)

? NULL

: fil_names_write(m_impl->m_named_space, m_impl->m_mtr);

 

如果是預定義的系統表空間(ibdata, undo space ,tmp space),space = NULL; 否則呼叫函式 fil_names_write(m_impl->m_named_space, m_impl->m_mtr)寫入一個MLOG_FILE_NAME型別的REDO記錄;

 

#如果該space是上次CHECKPOINT後第一次被修改(呼叫 fil_names_dirty(space)),需要append一個1位元組的MLOG_MULTI_REC_END型別,因為當前mtr肯定大於1個log 記錄了(一個mtr可能包含多個log rec)

 

在函式fil_names_dirty中,會判斷space->max_lsn值是否為0,如果為0,表示第一次修改,加入到fil_system->named_spaces連結串列中;否則,設定space->max_lsn為當前的log_sys->lsn; (後面再說何時reset max_lsn為0)

 

#否則,需要忽略掉在fil_names_write寫入的REDO記錄。

 

b.mtr_t::Command::finish_write

將redo log從cache寫入redo log 公共buffer

 

3. Redo checkpoint

對應函式log_checkpoint

這裡會呼叫函式fil_names_clear,遍歷fil_system->named_spaces連結串列,如果space->max_lsn的值小於當前做checkpoint的LSN(在該LSN之前的髒頁已經刷盤),則將其中每個space->max_lsn設定為0,並從連結串列取出。同時寫一個MLOG_FILE_NAME日誌(所有named_spaces上的成員)。

然後寫一個MLOG_CHECKPOINT日誌,參考函式:mtr_t::commit_checkpoint。

 

因此這個mini transaction應該包含fil_system->named_spaces連結串列上每個成員的MLOG_FILE_NAME日誌以及緊隨其後的一個MLOG_CHECKPOINT日誌

 

4.崩潰恢復

 

在crash recovery時,會有一個記憶體結構物件來維護space id和表名的對映關係:

typedef std::map<

ulint,

file_name_t,

std::less<ulint>,

ut_allocator<std::pair<const ulint, file_name_t> > >    recv_spaces_t;

static recv_spaces_t    recv_spaces;

 

參考函式:

recv_parse_or_apply_log_rec_body–>fil_name_parse –>fil_name_process

 

 

相關程式碼:

http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/7825

http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/7829

http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/7888

http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/7966

http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/8152

http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/8560

 


相關文章