程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> MySQL系列:innodb源碼分析之redolog恢復

MySQL系列:innodb源碼分析之redolog恢復

編輯:MySQL綜合教程

MySQL系列:innodb源碼分析之redolog恢復


 

1.recv_sys_t結構

innodb在MySQL啟動的時候,會對重做日志文件進行日志重做,重做日志是通過一個recv_sys_t的結構來進行數據恢 復和控制的。它的結構如下:
struct recv_sys_struct
{
 mutex_t	 mutex;                                 /*保護鎖*/
 ibool	 apply_log_recs;                        /*正在應用log record到page中*/
 ibool	 apply_batch_on;                     /*批量應用log record標志*/
 
 dulint	 lsn;
 ulint	 last_log_buf_size;

 byte*	 last_block;                             /*恢復時最後的塊內存緩沖區*/
 byte*	 last_block_buf_start;             /*最後塊內存緩沖區的起始位置,因為last_block是512地址對齊的,需要這個變量記錄free的地址位置*/
 byte*	 buf;                                        /*從日志塊中讀取的重做日志信息數據*/
 ulint	 len;	 /*buf有效的日志數據長度*/

 dulint	 parse_start_lsn;                       /*開始parse的lsn*/
 dulint	 scanned_lsn;                           /*已經掃描過的lsn序號*/

 ulint	 scanned_checkpoint_no;          /*恢復日志的checkpoint 序號*/
 ulint	 recovered_offset;                       /*恢復位置的偏移量*/

 dulint	 recovered_lsn;                         /*恢復的lsn位置*/
 dulint	 limit_lsn;                                  /*日志恢復最大的lsn,暫時在日志重做的過程沒有使用*/

 ibool	 found_corrupt_log;                   /*是否開啟日志恢復診斷*/

 log_group_t*	archive_group;

 mem_heap_t*	 heap;                             /*recv sys的內存分配堆,用來管理恢復過程的內存占用*/
 hash_table_t*	addr_hash;                     /*recv_addr的hash表,以space id和page no為KEY*/
 ulint	 n_addrs;                                        /*addr_hash中包含recv_addr的個數*/
};
在這個結構中,比較復雜的是addr_hash這個哈希表,這個哈希表是用sapce_id和page_no作為hash key,裡面存儲有恢復時對應的記錄內容。恢復日志在從日志文件中讀出後,進行解析成若干個recv_t並存儲在哈希表當中。在一個讀取解析周期過後,日志恢復會對hash表中的recv_t中的數據寫入到ibuf和page中。這裡為什麼要使用hash表呢?個人覺得是為了同一個page的數據批量進行恢復的緣故,這樣可以page減少隨機插入和修改。 以下是和這個過程相關的幾個數據結構:
/*對應頁的數據恢復操作集合*/ 
struct recv_addr_struct
{
 ulint	 state;          /*狀態,RECV_NOT_PROCESSED、RECV_BEING_PROCESSED、RECV_PROCESSED*/
 ulint	 space;         /*space的ID*/
 ulint	 page_no;    /*頁序號*/
 UT_LIST_BASE_NODE_T(recv_t) rec_list;
 hash_node_t	 addr_hash;
};
/*當前的記錄操作*/
struct recv_struct
{
 byte	 type;             /*log類型*/
 ulint	 len;               /*當前記錄數據長度*/
 recv_data_t*	data;	 /*當前的記錄數據list*/
 dulint	 start_lsn;     /*mtr起始lsn*/
 dulint	 end_lsn;      /*mtr結尾lns*/
 UT_LIST_NODE_T(recv_t)	rec_list;
};
/*具體的數據體*/
struct recv_data_struct  
{
 recv_data_t*	next;	/*下一個recv_data_t,next的地址後面接了一大塊內存,用於存儲rec body*/
};
他們的內存關系結構圖如下: \

2.重做日志推演過程的LSN關系

除了這個恢復的哈希表以外,recv_sys_t中的各種LSN也是和日志恢復有非常緊密的關系。以下是各種lsn的解釋: parse_start_lsn 本次日志重做恢復起始的lsn,如果是從checkpoint處開始恢復,等於checkpoint_lsn。 scanned_lsn 在恢復過程,將恢復日志從log_sys->buf解析塊後存入recv_sys->buf的日志lsn. recovered_lsn 已經將數據恢復到page中或者已經將日志操作存儲addr_hash當中的日志lsn; 在日志開始恢復時:
parse_start_lsn = scanned_lsn = recovered_lsn = 檢查點的lsn。
在日志完成恢復時:
parse_start_lsn = 檢查點的lsn
scanned_lsn = recovered_lsn = log_sys->lsn。
在日志推演過程中lsn大小關系如下:
\

3.日志恢復的主要接口和流程

恢復日志主要的接口函數: recv_recovery_from_checkpoint_start 從重做日志組內的最近的checkpoint開始恢復數據
recv_recovery_from_checkpoint_finish 結束從重做日志組內的checkpoint的數據恢復操作
recv_recovery_from_archive_start 從歸檔日志文件中進行數據恢復
recv_recovery_from_archive_finish 結束從歸檔日志中的數據恢復操作
recv_reset_logs 截取重做日志最後一段作為新的重做日志的起始位置,可能會丟失數據。
重做日志恢復數據的流程(checkpoint方式) 1.當MySQL啟動的時候,先會從數據庫文件中讀取出上次保存最大的LSN。
2.然後調用recv_recovery_from_checkpoint_start,並將最大的LSN作為參數傳入函數當中。
3.函數會先最近建立checkpoint的日志組,並讀取出對應的checkpoint信息
4.通過checkpoint lsn和傳入的最大LSN進行比較,如果相等,不進行日志恢復數據,如果不相等,進行日志恢復。
5.在啟動恢復之前,先會同步各個日志組的archive歸檔狀態
6.在開始恢復時,先會從日志文件中讀取2M的日志數據到log_sys->buf,然後對這2M的數據進行scan,校驗其合法性,而後將去掉block header的日志放入recv_sys->buf當中,這個過程稱為scan,會改變scanned lsn.
7.在對2M的日志數據scan後,innodb會對日志進行mtr操作解析,並執行相關的mtr函數。如果mtr合法,會將對應的記錄數據按space page_no作為KEY存入recv_sys->addr_hash當中。
8.當對scan的日志數據進行mtr解析後,innodb對會調用recv_apply_hashed_log_recs對整個recv_sys->addr_hash進行掃描,並按照日志相對應的操作進行對應page的數據恢復。這個過程會改變recovered_lsn。
9.如果完成第8步後,會再次從日志組文件中讀取2M數據,跳到步驟6繼續相對應的處理,直到日志文件沒有需要恢復的日志數據。
10.innodb在恢復完成日志文件中的數據後,會調用recv_recovery_from_checkpoint_finish結束日志恢復操作,主要是釋放一些開辟的內存。並進行事務和binlog的處理。
上面過程的示意圖如下: \



  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved