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

MySQL系列:innodb源碼分析之重做日志結構

編輯:MySQL綜合教程

MySQL系列:innodb源碼分析之重做日志結構


 

1.LSN

在innodb中的重做日志系統中,定義一個LSN序號,其代表的意思是日志序號。LSN在引擎中定義的是一個dulint_t類型值,相當於uint64_t,關於dulint_t的定義如下:

 

 

typedef struct dulint_struct
{
     ulint high;     /* most significant 32 bits */
     ulint low;       /* least significant 32 bits */
}dulint_t;
LSN真正的含義是儲存引擎向重做日志系統寫入的日志量(字節數),這個日志量包括寫入的日志字節 + block_header_size + block_tailer_size。LSN的初始化值是:LOG_START_LSN(相當於8192),在調用日志寫入函數LSN就一直隨著寫入的日志長度增加,具體看:

 

 

void log_write_low(byte* str, ulint str_len)
{
 log_t* log = log_sys;
. . .
part_loop:
 /*計算part length*/
 data_len = log->buf_free % OS_FILE_LOG_BLOCK_SIZE + str_len;
.  .  . 
 /*將日志內容拷貝到log buffer*/
 ut_memcpy(log->buf + log->buf_free, str, len);
 str_len -= len;
 str = str + len;
 . . .
 if(data_len = OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE){ /*完成一個block的寫入*/
. . .
      len += LOG_BLOCK_HDR_SIZE + LOG_BLOCK_TRL_SIZE;
      log->lsn = ut_dulint_add(log->lsn, len);
 . . .
 }
 else /*更改lsn*/
  log->lsn = ut_dulint_add(log->lsn, len);
 . . .
}

 

LSN是不會減小的,它是日志位置的唯一標記。在重做日志寫入、checkpoint構建和PAGE頭裡面都有LSN。

關於日志寫入:

例如當前重做日志的LSN = 2048,這時候innodb調用log_write_low寫入一個長度為700的日志,2048剛好是4個block長度,那麼需要存儲700長度的日志,需要量個BLOCK(單個block只能存496個字節)。那麼很容易得出新的LSN = 2048 + 700 + 2 * LOG_BLOCK_HDR_SIZE(12) + LOG_BLOCK_TRL_SIZE(4) = 2776。

關於checkpoint和日志恢復:

在page的fil_header中的LSN是表示最後刷新是的LSN, 假如數據庫中存在PAGE1 LSN = 1024,PAGE2 LSN = 2048, 系統重啟時,檢測到最後的checkpoint LSN = 1024,那麼系統在檢測到PAGE1不會對PAGE1進行恢復重做,當系統檢測到PAGE2的時候,會將PAGE2進行重做。一次類推,小於checkpoint LSN的頁不用重做,大於LSN checkpoint的PAGE就要進行重做。

2.Log Block

innodb在日志系統裡面定義了log block的概念,其實log block就是一個512字節的數據塊,這個數據塊包括塊頭、日志信息和塊的checksum.其結構如下:

\

Block no的最高位是描述block是否flush磁盤的標識位.通過lsn可以blockno,具體的計算過程是lsn是多少個512的整數倍,也就是no = lsn / 512 + 1;為什麼要加1呢,因為所處no的塊算成clac_lsn一定會小於傳入的lsn.所以要+1。其實就是block的數組索引值。checksum是通過從塊頭開始到塊的末尾前4個字節為止,做了一次數字疊加,代碼如下:

sum = 1;
 sh = 0;
 for(i = 0; i < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE, i ++){
      sum = sum & 0x7FFFFFFF;
      sum += (((ulint)(*(block + i))) << sh) + (ulint)(*(block + i));
      sh ++;
      if(sh > 24) 
        sh = 0;
 }
在日志恢復的時候,innodb會對加載的block進行checksum校驗,以免在恢復過程中數據產生錯誤。事務的日志寫入是基於塊的,如果事務的日志大小小於496字節,那麼會合其他的事務日志合並在一個塊中,如果事務日志的大小大於496字節,那麼會以496為長度進行分離存儲。例如:T1 = 700字節大小,T2 = 100字節大小存儲結構如下:

 

\

 

3.重做日志結構和關系圖

innodb在重做日志實現當中,設計了3個層模塊,即redo log buffer、group files和archive files。這三個層模塊的描述如下:

 

 

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