在這裏插入圖片描述

接下來我們來深入到 F2FS 的實現層面。這部分會比較技術性,但會盡量清晰地闡述其核心機制和數據結構。

一、F2FS 的宏觀佈局:段(Segment)為核心的架構

F2FS 將整個存儲空間格式化為一個線性的地址空間,並將其劃分為固定大小的塊,這些塊以 "段(Segment)" 為核心進行組織。

  1. 超級塊

    • 位置:固定在存儲設備的 第0號偏移量第1號偏移量(作為備份)。
    • 內容:存儲文件系統的元數據,如魔數(標識F2FS)、扇區數、段數、檢查點位置、活動日誌的段號等。它是掛載文件系統的起點。
  2. 檢查點

    • 作用:這是 F2FS 的 一致性核心。它保存了文件系統在某個一致狀態下的關鍵元數據的快照。
    • 內容
      • 文件系統元數據的版本號。
      • 有效節點位圖有效數據位圖。這兩個位圖記錄了哪些節點和數據塊在當前檢查點是有效的。
      • 指向當前活動節點和數據日誌區域的指針。
    • 工作原理:F2FS 始終維護兩個檢查點(例如,CP#1 和 CP#2)。當需要做檢查點時,它會將所有髒的元數據(節點、數據位圖等)刷寫到磁盤,然後更新下一個檢查點。如果系統在檢查點過程中崩潰,恢復時會回退到上一個完好的檢查點,確保一致性。
  3. 段信息表

    • 作用:這是一個數組,每個條目對應一個,記錄了該段的詳細信息。
    • 內容
      • 有效塊數量:該段中當前有效的塊數。這是垃圾回收器選擇回收目標的關鍵依據。
      • 段類型:標識這個段屬於哪個日誌區域(Hot/Warm/Cold Node/Data),實現了冷熱數據分離
  4. 節點地址表

    • 作用:這是一個數組,用於將節點號 映射到節點的物理磁盤地址。可以把它想象成一個節點的“總目錄”。

二、關鍵數據結構

1. 節點

節點是 F2FS 中用於表示文件和目錄元數據的核心結構。有幾種類型:

  • inode:

    • 與傳統文件系統類似,每個文件或目錄都有一個 inode。
    • 它包含了文件的元數據(權限、大小、時間戳等)。
    • 最關鍵的是,它包含了指向文件數據的指針。
  • 直接/間接節點:

    • F2FS 的 inode 本身只能容納少量直接數據指針。
    • 對於大文件,它使用樹形結構來擴展:
      • 直接節點:包含直接指向數據塊地址的指針。
      • 間接節點:包含指向直接節點的指針。
      • 雙間接節點:包含指向間接節點的指針。
    • 這種樹形結構允許 F2FS 高效地管理大文件。
  • 目錄節點:

    • 目錄在 F2FS 中被實現為一個文件,其內容是一系列目錄項。
    • 為了快速查找,F2FS 使用一種稱為 "哈希桶" 的結構來組織目錄項。目錄項根據文件名的哈希值被分配到不同的桶中,大大加快了文件查找速度。

2. 段(Segment)和區(Section)

  • :F2FS 分配和垃圾回收的基本單位。一個段通常包含 512 個 4KB 的塊(即 2MB)。這是 NAND Flash 擦除塊大小的抽象。
  • :由 連續 的段組成的邏輯集合。F2FS 有 六個主要的區,對應其冷熱數據分離策略:
    • Hot Data, Warm Data, Cold Data
    • Hot Node, Warm Node, Cold Node
  • 日誌:每個區實際上就是一個循環寫入的日誌。當需要寫入特定類型的數據時,F2FS 就追加寫入到對應區的當前寫入位置。

三、核心操作流程

1. 寫入流程(異地更新)

  1. 確定類型:當一個寫入請求到達時,F2FS 首先根據其元數據(例如,是文件數據還是節點,更新頻率如何)判斷其冷熱類型
  2. 分配位置:文件系統從對應的中,分配一個新的、空閒的塊。它不會去覆蓋舊數據。
  3. 寫入數據:將新數據寫入到這個新分配的塊中。
  4. 更新元數據
    • 更新文件的 節點,將其中的指針從指向舊數據塊改為指向新數據塊
    • 這個節點本身的更新也是一個“異地更新”過程:將新的節點寫入到對應的 Node 區的新位置。
  5. 更新位圖:在內存中,將舊數據塊標記為"無效",新數據塊標記為"有效"。
  6. 提交檢查點:最終,這些元數據的更改會通過檢查點 持久化到磁盤,完成整個寫入操作。

2. 垃圾回收流程

這是 F2FS 保持性能的關鍵後台任務。

  1. 選擇受害者段:垃圾回收器會週期性地被觸發。它掃描段信息表,尋找 有效塊數量最少 的段。這些段是回收效率最高的,因為需要搬移的有效數據最少。
  2. 搬移有效數據:GC 讀取被選中的段中所有仍然有效的數據塊。
  3. 異地更新有效數據:將這些有效數據作為新數據,重新寫入到對應類型的日誌區域的新位置。這意味着 GC 本身也會引發寫入,但其目標是減少未來的寫入放大。
  4. 擦除段:一旦段中的所有有效數據都被搬走,這個整個段就可以被安全地擦除,並加入到空閒段列表中,供未來分配使用。

GC 觸發策略

  • 後台 GC:在系統空閒時進行,對用户體驗影響小。
  • 前台 GC:當空閒空間嚴重不足時,在寫入路徑中同步進行,會導致性能下降和卡頓。F2FS 的設計目標就是通過智能的後台 GC 來儘量避免前台 GC。

3. 文件讀取流程

讀取流程相對直接,但體現了其元數據組織的效率:

  1. 根據文件名,在目錄的哈希桶中找到其目錄項,獲取 inode 號
  2. 通過 節點地址表,找到該 inode 的物理地址。
  3. 讀取 inode。
  4. 根據 inode 中的指針樹(直接/間接節點),找到文件數據所在的物理塊地址。
  5. 從這些地址讀取數據。

四、F2FS 的現代特性與優化

  1. 原子寫

    • 對於數據庫等應用,需要保證多個寫入操作的原子性(要麼全成功,要麼全失敗)。
    • F2FS 實現了原生的原子寫支持,可以將多個分散的寫操作在文件系統層面捆綁為一個原子事務,極大地提升了像 SQLite 這類數據庫的性能。
  2. 內聯數據

    • 對於非常小(例如幾百字節)的文件,F2FS 可以不為其分配單獨的數據塊,而是將其數據直接存儲在 inode 的額外空間裏。
    • 這避免了為小文件分配整個塊(4KB)的空間浪費,也減少了一次 I/O,提升了小文件讀寫性能。
  3. 內聯目錄

    • 對於條目很少的目錄,其目錄項也可以直接存儲在 inode 中,加快目錄查找速度。
  4. 刷新控制

    • F2FS 提供了精細的緩存刷新策略控制,允許應用程序根據數據的重要性選擇是儘快刷盤還是延遲刷盤,以在數據安全性和性能之間取得平衡。

總結

F2FS 的實現是一個複雜而精巧的工程,其核心思想可以概括為:

  • 以日誌結構為基礎,擁抱閃存的“異地更新”特性。
  • 以冷熱數據分離為靈魂,通過劃分多個日誌區域來優化垃圾回收和寫入性能。
  • 以段為管理單元,與閃存的物理特性對齊。
  • 以檢查點為一致性保障,確保元數據的崩潰恢復能力。

通過這種從底層硬件特性出發的深度定製設計,F2FS 成功地在隨機寫入密集型負載下超越了傳統文件系統,成為了現代移動設備和存儲系統的重要基石。它的實現細節充分體現了在計算機系統中,軟件(文件系統)與硬件(閃存)協同設計的巨大威力。


結束語 Flutter是一個由Google開發的開源UI工具包,它可以讓您在不同平台上創建高質量、美觀的應用程序,而無需編寫大量平台特定的代碼。我將學習和深入研究Flutter的方方面面。從基礎知識到高級技巧,從UI設計到性能優化,歡飲關注一起討論學習,共同進入Flutter的精彩世界!