<b>現象</b>
5.6版本,在建立innodb表過程中,若發生crash,會導緻服務無法啟動。
<b>背景</b>
每個innodb表a建立成功後有兩個檔案a.frm和a.ibd。建表流程如下:
1、建立a.frm
2、建立a.ibd
3、初始化a.ibd
4、将表a加入innodb字典
若crash發生在步驟2之後,則隻保留一個完整的a.frm和一個空檔案a.idb。
<b>崩潰恢複</b>
在上述的crash發生後,下一次啟動則需要做崩潰恢複。崩潰恢複的一個邏輯是需要周遊資料目錄下的所有.ibd檔案,驗證檔案與字典的一緻性。
對于長度為0的.ibd 檔案,報錯并跳過,繼續檢測下一個表。
以上是5.5和5.6共有的邏輯。但5.6的一個新特性破壞了這個規則。
<b>遠端目錄</b>
5.6支援create table的時候指定其他目錄。文法是create table 裡新增參數data directory.這樣一個表就可能存在多個表空間。每個表空間對應一個資料結構(fsp_open_info).
這意味着在崩潰恢複過程中,需要驗證哪一個表空間是可用的(fil_validate_single_table_tablespace),
驗證的方法是嘗試讀取該表空間的第一個page,若可用則将對應的fsp_open_info::success設定為true。
而在讀取本地預設表空間的第一個頁時,若碰到讀取失敗,直接exit(1),導緻程式直接退出。“若檔案小于4個page就報錯”的邏輯,是在這個exit之後。
<b>分析改進</b>
其實在這個場景下,多出來的a.frm和a.ibd并不會導緻系統嚴重問題。由于表a還沒有記錄入系統字典,實際上隻需要将這兩個檔案直接删掉即可。
是以5.6的這個新增要求過于苛刻。改進方法是将檔案大小的判斷提前,若發現小于4個page,則直接報錯跳過這個表。