天天看點

MySQL系列:innodb源碼分析之mini transaction

  日志是innodb一個非常重要的子產品,在innodb中有兩類日志:redo log和undo log。其中redolog日志是用來做資料異常恢複和資料庫重新開機時頁資料同步恢複的,redo log是建立在在mini transaction基礎上。資料庫在執行事務時,通過minitransaction産生redo log來保證事務的持久性。

1.mini transaction三個協定

mini-transcation是用來實作innodb的實體邏輯日志的寫入和頁恢複的,通過mini-transcation來保證并發事務操作和資料庫異常是頁的一緻性。為了得到頁的一緻性,mini-transaction遵循以下三個協定:

        1. The FIX Rules

      2. Write-Ahead Log

      3. Force-log-at-commit

1.1The FIX Rules

The FIX Rules規定如下:

              修改一個頁需要獲得該頁的x-latch

              通路一個頁是需要獲得該頁的s-latch或者x-latch

              持有該頁的latch直到修改或者通路該頁的操作完成

1.2Write-Ahead Log

Write-Ahead Log的意思就是如果一個頁操作在寫入到持久裝置時,必須記憶體中相對應的日志寫入到持久化裝置中。每個頁有一個LSN,每次頁修改需要維護這個LSN,當一個頁需要寫入到持久化裝置時,要求記憶體中小于該頁LSN的日志先寫入到持久化裝置中。日志寫完後,先Fixed這個頁的latch,再将記憶體中的頁刷盤。完成刷盤後,釋放頁latch。這裡遵循The FIX Rules協定。

1.3 Force-log-at-commit

    一個事務可以同時修改了多個頁,Write-AheadLog單個資料頁的一緻性,無法保證事務的持久性。Force -log-at-commit要求當一個事務送出時,其産生所有的mini-transaction日志必須刷到持久裝置中。這樣即使在頁資料刷盤的時候當機,也可以通過日志進行redo恢複。

2 mini-transaction的日志實作

    innodb是采用mini-transaction來建構操作的實體邏輯日志的,在事務執行的時候,會通過mtr來保證頁的資料一緻性和持久性。mini-transaction是通過一個mtr_t的結構來實作mini-transaction的三個協定。mtr_t的定義如下:

typedef struct mtr_struct
    {
         ulint     state;                      /*mtr的狀态,MTR_ACTIVE、MTR_COMMITING、MTR_COMMITTED*/
         dyn_array_t     memo;        /*正在持有的latch清單*/
         dyn_array_t     log;             /*mtr産生的日志資料*/
         ibool     modifications;     /*是否修改了頁*/
         ulint     n_log_recs;            /*log操作頁的個數*/
         ulint     log_mode;             /*log操作模式,MTR_LOG_ALL、MTR_LOG_NONE、MTR_LOG_SHORT_INSERTS*/
         dulint     start_lsn;              /*mtr起始的LSN*/
         dulint  end_lsn;             /*mtr結束的LSN*/
         ulint  magic_n;             /*魔法字*/
    }mtr_t;      

其中成員memo是個latch持有狀态的數組清單,采用的是dyn_array_t的動态記憶體結構來儲存的,每個單元存儲的是mtr_memo_slot_t這樣的結構。定義如下:

typedef struct mtr_memo_slot_struct
        {
             ulint   type;            /*latch的類型值*/
             void*   object;        /*latch對象句柄,可以是rw_lock_t或者buf_block_t*/
        }mtr_memo_slot_t;      

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                                       獲得一個latch,并将狀态資訊存入mtr memo當中

    mtr_release_s_latch_at_savepoint       釋放memo偏移savepoint的slot鎖狀态

    mtr_memo_contains                          判斷鎖對象是否在memo當中

    mtr_memo_slot_release                    釋放slot鎖的控制權

    mtr_memo_pop_all                           

mt_t中的log成員是也是一個dyn_array_t動态結構的記憶體,用來儲存mtr産生的日志資訊。日志的寫入是通過mtr0log.h來寫入的。這裡指的一提的是日志格式,日志格式是有日志頭和日志體組成,日志頭資訊是由type、space和page no組成,由mlog_write_initial_log_record_fast函數寫入到mtr_t的log中的。以下是一個比較具體的示意圖:

MySQL系列:innodb源碼分析之mini transaction

log body的資料寫入是通過mtr0log.h中的日志寫入方法進行寫入的。每寫入一跳記錄檔,n_log_recs會加1.

辨別modifications是辨別是否有page的資料改動,如果有,在mtr_commit調用時會先将mtr->log刷盤,然後釋放mtr所有的所控制權。日志會一定會在mtr結束時刷盤,這符合Force-log-at-commit的規定。日志寫入調用的是log_write_low這個函數。

2.1 mtr_t的記憶體結構關系圖

MySQL系列:innodb源碼分析之mini transaction

3 總結

mini transaction是innodb對ACID中的持久性的最小保證單元,所有涉及到事務執行、頁資料刷盤、redo log資料恢複等都需要進行mini transaction的構造和執行。幾乎所有的子產品都涉及到mini transaction,例如:btree、page、事務、inser tbuffer、redo-log等,d對mini transcaion的了解不能孤立的去看源代碼,應該結合redo log、page相關的代碼了解。它是了解innodb工作原理的基石。