天天看點

MySQL源碼學習:InnoDB的ib_logfile寫入政策

ib_logfile是innodb的事務日志檔案。本文簡要說明其寫入時機、寫入政策及如何保證資料安全。

1、 基本概念

a) ib_logfile檔案個數由innodb_log_files_in_group配置決定,若為2,則在datadir目錄下有兩個檔案,指令從0開始,分别為ib_logfile0和ib_logfile.

b) 檔案為順序寫入,當達到最後一個檔案末尾時,會從第一個檔案開始順序複用。

c) lsn: log sequence number,是一個遞增的整數。 ib_logfile中的每次寫入操作都包含至少1個log,每個log都帶有一個lsn。在記憶體page修複過程中,隻有大于page_lsn的log才會被使用。

d) lsn的儲存在全局變量log_sys中。遞增數值等于每個log的實際内容長度。即如果新增的一個log長度是len,則log_sys->lsn += len.

e) ib_logfile每次寫入以512(os_file_log_block_size)位元組為機關。實際寫入函數 log_group_write_buf (log/log0log.c)

f) 每次寫盤後是否flush,由參數innodb_flush_log_at_trx_commit控制。

2、 log_sys介紹

log_sys是一個全局記憶體結構。以下說明幾個成員的意義。

lsn

表示已經配置設定的最後一個lsn的值。

written_to_all_lsn

n表示實際已經寫盤的lsn。需要這個值是因為并非每次生成log後就寫盤。

flushed_to_disk_lsn

表示刷到磁盤的lsn。需要這個值是因為并非每次寫盤後就flush。

buf

待寫入的内容儲存在buf中

buf_size

buf的大小。由配置中innodb_log_buffer_size決定,實際大小為innodb_log_buffer_size /16k * 16k。

buf_next_to_write

buf中下一個要寫入磁盤的位置

buf_free

buf中實際内容的最後位置。當buf_free> buf_next_to_write時,說明記憶體中還有資料未寫盤。

3、相關更新

用一個簡單的更新語句來說明log_sys以及ib_logfile的更新内容的過程。假設我們的更新隻涉及到非索引的固定長度字段。

a) 在bufferpool中寫入undo log。 對于一個單一的語句,需要先建立一個undolog頭。

b) 在bufferpool中寫入undo log的實際内容。

c) 在log_sys->buf中寫入buffer page的更新内容。此處儲存了更新的完整資訊。

d) 在log_sys->buf中寫入啟動事務(trx_prepare)的日志

e) 将c、d更新的log内容寫入ib_logfile中。

f) 在log_sys->buf中寫入事務結束(trx_commit)的日志

g) 将f步驟的log内容寫入ib_logfile中。

4、 說明

a) 完成上述所有操作時,資料檔案還沒有更新。

b) 每次寫入log_sys->buf時同時更新lsn和buf_free。 每次寫ib_logfile時同時更新written_to_all_lsn和buf_next_to_write;

c) 每次寫ib_logfile時以512位元組為對齊,如需寫入600位元組,則實際寫入1k。寫到最後一個檔案末尾則從第一個檔案重複使用。

d) 從上述流程看到,在a~d過程中若出現異常關閉,由于沒有寫入到磁盤中,是以整個事務放棄;若在e剛完成時出現異常關閉,雖然事務内容已經寫盤,但沒有送出。在重新開機恢複的時候,發現這個事務還沒有送出,邏輯上整個事務放棄。 (重新開機日志中會有found 1 prepared transaction(s) in innodb字樣)。在g完成後出現異常關閉,則能夠在重新開機恢複中正常送出。

在e和f之間會寫mysql的bin-log,若bin-log寫完前異常關閉,事務無效,bin-log寫入成功後,則異常重新開機後能夠根據bin-log恢複事務的修改。

e) 若涉及到索引更新,在步驟c之後會增加索引更新的log。由于索引可能有merge過程,是以在merge過程中會另外增加寫入一個log。但事務完全送出仍在步驟g中。索引的更新由于已經寫盤,并不會是以丢失。

繼續閱讀