MySQL8.0新特性:增加系統檔案追蹤spaceID和物理檔案的對映
update:從8.0.11開始,又改成了開啟全部ibd檔案,但是改成了並行掃描
Note1: 本文所有程式碼相關的內容都是基於MySQL8.0.3,而目前版本還處於RC和快速開發的狀態,不排除後面的版本邏輯,函式名等發生變化。
Note2: 主要程式碼在這個commit 中,感興趣的也可以自行閱讀程式碼
Note3: 本文僅是本人的閱碼筆記,記錄的比較凌亂。。。
前面我們提到了MySQL5.7的幾個崩潰恢復產生的效能退化 為了解決崩潰恢復的效率問題, MySQL8.0對crash recovery的邏輯進行了進一步的優化。 在之前的版本中,InnoDB通過向redo log中寫入日誌來追蹤在一次checkpoint後修改過的表空間資訊,這樣就無需在crash recovery時開啟所有的表空間,只需蒐集哪些被影響到的表空間。而到了8.0新版本里,採用了一種全新的方式:單獨建立了系統對映檔案, 將space id及路徑資訊輪換著寫到兩個指定的系統檔案tablespaces.open.1 and tablespaces.open.2中(ref Fil_Open::write
)
實現的思路其實不復雜,就是將所有的表空間ID和對應的路徑資訊儲存到系統檔案中,在崩潰恢復時再按需開啟。
系統檔案更新
那麼如何保證所有的表空間資訊都一個不漏的儲存到系統檔案了呢 ? 實際上他跟蹤了所有的表空間檔案操作,並更新記憶體cache中(Fil_Open::m_spaces
), 如下:
a. fil_node_open_file
fil_system->m_open.enter();
fil_system->m_open.log(node->space->id, node->name);
fil_system->m_open.exit();
開啟表空間檔案後,寫一條日誌MLOG_FILE_OPEN, 並將表空間狀態 Nodes::OPEN以及日誌end lsn在記憶體中進行更新(Fil_Open::Nodes::load)
b. fil_node_close_file
fil_system->m_open.enter();
fil_system->m_open.close(node->space->id, node->name);
fil_system->m_open.exit();
關閉表空間檔案後, 將快取的表空間資訊LSN重置為0,並將狀態設定為CLOSED (Fil_Open::Nodes::close
)
c. fil_name_write_rename
fil_system->m_open.enter();
fil_system->m_open.log(space_id, new_name);
fil_system->m_open.to_file();
fil_system->m_open.exit();
在物理rename檔案之前, 將新的表空間名通過MLOG_FILE_OPEN寫到redo log中,記錄新檔案的狀態到記憶體。
隨後就將快取的表空間資訊寫到系統對映檔案中(Fil_Open::to_file
)
d. fil_delete_tablespace
fil_system->m_open.enter();
fil_system->m_open.deleted(id);
fil_system->m_open.exit();
在物理刪除檔案之後,將對應的表空間狀態設定為DELETED (Fil_Open::deleted
)
e. fil_ibd_create
fil_system->m_open.enter();
fil_system->m_open.open(space_id, file->name, log_get_lsn());
fil_system->m_open.exit();
在物理建立表空間檔案之後, 呼叫Fil_Open::open
將新檔案的資訊儲存到記憶體中。同樣的包含建立檔案時的LSN
可見InnoDB在對檔案進行開啟,關閉,建立,刪除,重新命名這些操作時都進行了追蹤,其中CREATE/DELETE/RENAME的cache更新均發生在記錄對應的MLOG_FILE_*日誌之前。
另外我們也可以看到,表空間資訊不是直接寫入的,而是經過zip壓縮後再寫的,以減少磁碟空間佔用。
那麼何時將快取的資訊刷到磁碟呢 ?
第一種情況是rename tablespace時,會做一次寫檔案
第二種情況是做checkpoint之前會去做一次flush(fil_tablespace_open_sync_to_disk
), 相比第一種情況,這裡先做一次清理(Fil_Open::purge -> Fil_Open::Nodes::purge
),將狀態為DELETED/MISSING的無效表空間記錄刪除掉,再刷到磁碟
當系統正常關閉時,InnoDB會去將系統檔案中的資訊全部清除掉(fil_tablespace_open_clear
),因為崩潰恢復無需用到。
崩潰恢復
那麼崩潰恢復時,如何使用該檔案呢?
首先在啟動時(srv_start
), 當確定了需要崩潰恢復時(recv_recovery_from_checkpoint_start
),就會去從系統對映檔案中載入表空間資訊到記憶體中(fil_tablespace_open_init_for_recovery --> Fil_Open::from_file
)。
隨後開始讀redo log並解析, 如下堆疊:
recv_recovery_begin
|--> recv_scan_log_recs
|--> recv_parse_log_recs
|--> recv_single_rec
|--> recv_multi_rec
在將redo log加入到hash table之前,會先進行判斷,只有在檔案中找到的表空間,才需要去apply日誌。
if (space_id == TRX_SYS_SPACE
|| fil_tablespace_lookup_for_recovery(space_id)) {
recv_add_to_hash_table(
type, space_id, page_no, body,
ptr + len, old_lsn, recv_sys->recovered_lsn);
} else {
recv_sys->missing_ids.insert(space_id);
}
由於系統檔案不是實時flush的,因此在解析到MLOG_FILE_*型別的redo時, 也要對快取的表空間資訊進行修正(fil_tablespace_name_recover --> fil_name_process_for_recovery
) ,以確保所有需要apply redo的tablespace都load到記憶體中。
在執行崩潰恢復時,InnoDB會按需去開啟表空間檔案,然後再去apply日誌。(recv_apply_hashed_log_recs --> fil_tablespace_open_for_recovery
),只有那些需要做崩潰恢復的檔案,才會被開啟。
相關文章
- PostgreSQL 物理檔案對映解析SQL
- 檔案和檔案系統
- 檔案系統的物理結構分配
- UNIX根檔案系統和附加檔案系統
- 檔案-跟蹤檔案
- Java中的獲取檔案的物理絕對路徑,和讀取檔案Java
- Mybatis對映檔案簡介MyBatis
- 各檔案系統對單個檔案大小的限制
- 檔案描述符和檔案系統
- Oracle 跟蹤檔案和檔案轉儲(dump)Oracle
- 控制檔案的跟蹤檔案全文
- Godot 4.0 檔案系統特性的總結Go
- 載入Mapper對映檔案APP
- 【Git】取消追蹤多個檔案或目錄Git
- 分散式檔案系統(HDFS)與 linux系統檔案系統 對比分散式Linux
- vmware中增加硬碟掛載檔案系統硬碟
- Oracle跟蹤檔案trace檔案Oracle
- Database 物理檔案Database
- Linux檔案系統-目錄和檔案管理Linux
- nginx容器卷對映檔案不生效Nginx
- 使用記憶體對映檔案(mmap)記憶體
- fsutil,您可以執行多種檔案系統操作,包括查詢和設定檔案系統特性,refsutil 是用於管理和維護ReFS檔案系統的實用程式 管理ReFS檔案系統的命令列工具命令列
- 記憶體對映檔案詳解-----C++實現(即一塊記憶體和一個檔案相對映對應)記憶體C++
- Oracle12c新特性(1)線上重新命名檔案和遷移檔案Oracle
- Mybatis基礎:Mybatis對映配置檔案,Mybatis核心配置檔案,Mybatis傳統方式開發MyBatis
- oracle跟蹤檔案和跟蹤事件(zt)Oracle事件
- 檔案系統和檔案 API 安全性缺失指南API
- 關於檔案系統在建立目錄檔案和普通檔案時的區別
- Ubuntu下修改hosts檔案中的域名對映Ubuntu
- MyBatis系列之對映檔案中的ResultMapsMyBatis
- 檔案的基本管理和XFS檔案系統備份恢復
- mysql物理檔案 02MySql
- windows下檔案系統支援的檔案大小Windows
- 檔案系統
- 增加oracle的控制檔案Oracle
- 多日誌檔案資料幫你追蹤使用者
- OA系統之檔案借閱管理,對檔案的去向實時掌控
- 裸裝置表空間對映檔案