B 樹目錄(B-tree directory)
/ B-tree = BEE-tree /
一個有十個檔案的目錄很簡單:把目錄項存成一串清單、掃過去就好。但一個有一百萬個檔案的目錄——想想郵件佇列或快取——是另一回事。如果查一個名字意味著掃描一串一百萬筆的線性清單,那個目錄裡每次開啟都會慢如爬行。解法是把目錄的目錄項照資料庫組織一張大表的方式來組織:放進一棵以名字為鍵的樹,讓任何查找只需幾步而非一百萬步。那就是 B 樹目錄(或它的近親,雜湊目錄)。
三種目錄佈局要分清楚。線性目錄單純地附加目錄項;查找是 O(n)——對小目錄沒問題,是歷史上的預設。雜湊目錄(ext4 稱之為 HTree)把每個檔名雜湊成一個鍵、並把那些鍵索引在一棵淺樹裡,所以找一個名字意味著把它雜湊、再下降一兩層,大約 O(log n),而目錄項本身仍存在目錄區塊裡。真正的 B 樹(或 B+ 樹)目錄,如 XFS 與 Btrfs,把名字保存在一棵平衡的多路樹裡,即使百萬筆也保持淺,並支援有序走訪。在所有可擴展的方案裡,新增或移除名字會重新平衡或重新雜湊,而非重寫一個巨大的清單。
為何重要:這正是一個百萬檔案的目錄「能用」還是「是效能陷阱」之別。誠實的注意事項:雜湊/B 樹目錄用簡單的名字序列出去換取快速查找,所以 readdir() 回傳目錄項的順序可能看起來雜亂(雜湊序,而非字母序);而在按雜湊排序的目錄裡建檔,可能把它們的 inode 撒得四散,傷害日後的循序掃描。大多數日常目錄都小到單純的線性佈局完全沒問題——樹的機制只在大規模時才賺回它的成本。
線性: 查 "x" 掃描第 0,1,2,...,999999 筆 (O(n)) HTree: hash("x") = 0x6b3a;下降索引區塊 -> 葉區塊 -> 目錄項 (O(log n)) # 數百萬個檔案時:線性爬行,樹保持只有幾跳深
把名字雜湊、再下降一棵淺樹,把百萬筆的掃描變成幾跳。
雜湊或 B 樹目錄不會以字母順序回傳名字——readdir() 以雜湊序或樹序給出,看起來像隨機。需要排序輸出的程式必須自己排序結果;依賴目錄列出順序是一個經典的可攜性錯誤。