簡體中文 ▾ 主題 ▾ 最新版本 ▾ 多包索引 上次更新於 2.50.0

Git 物件目錄包含一個 pack 目錄,其中包含 packfile(字尾為“.pack”)和 pack-index(字尾為“.idx”)。pack-index 提供了一種查詢物件並導航到其在包中偏移量的方法,但這些必須與 packfile 成對出現。這種配對取決於檔名,因為 pack-index 與其 pack 檔案僅在後綴上不同。雖然 pack-index 為每個 packfile 提供快速查詢,但隨著 packfile 數量的增加,此效能會下降,因為縮寫需要檢查每個 packfile,並且我們更有可能在我們最近使用的 packfile 上查詢失敗。對於某些大型倉庫,由於儲存空間或過長的重新打包時間,將其重新打包成單個 packfile 是不可行的。

多包索引(簡稱 MIDX)儲存物件列表及其在多個 packfile 中的偏移量。它包含

  • packfile 名稱列表。

  • 按物件 ID 排序的列表。

  • 第 i 個物件 ID 的元資料列表,包括

    • 一個值 j,指代第 j 個 packfile。

    • 物件在第 j 個 packfile 中的偏移量。

  • 如果需要大偏移量,我們使用另一個類似版本 2 pack-index 的大偏移量列表。

    • 一個可選的偽包序物件列表(與 MIDX 點陣圖一起使用)。

因此,我們可以為任意數量的 packfile 提供 O(log N) 的查詢時間。

設計詳情

  • MIDX 儲存在 .git/objects/pack 目錄中名為 multi-pack-index 的檔案中。這也可以儲存在備用 pack 目錄中。它僅指代同一目錄中的 packfile。

  • core.multiPackIndex 配置設定必須開啟(預設),才能使用 MIDX 檔案。將其設定為 false 會阻止 Git 讀取 MIDX 檔案,即使存在也不讀取。

  • 檔案格式包含物件 ID 雜湊函式的引數,因此未來雜湊演算法的更改不需要更改格式。

  • MIDX 每個物件 ID 只保留一條記錄。如果一個物件出現在多個 packfile 中,則 MIDX 會選擇首選 packfile 中的副本,否則會從最近修改的 packfile 中選擇。

  • 如果 pack 目錄中存在未在 MIDX 中註冊的 packfile,則這些 packfile 將載入到 packed_git 列表和 packed_git_mru 快取中。

  • pack-index(.idx 檔案)保留在 pack 目錄中,這樣我們就可以刪除 MIDX 檔案,將 core.midx 設定為 false,或降級而不會丟失任何資訊。

  • MIDX 檔案格式採用基於塊的方法(類似於 commit-graph 檔案),允許新增可選資料。

增量多包索引

隨著倉庫規模的增長,編寫包含所有 packfile 的多包索引(MIDX)變得更加昂貴。為了適應這一點,“增量多包索引”功能允許組合多包索引的“鏈”。

鏈中的每個獨立元件只需包含少量 packfile。追加到鏈中不會使鏈的早期部分失效,因此倉庫可以透過確定 MIDX 鏈中每個層的包數量來控制更新 MIDX 鏈所花費的時間。

設計現狀

目前,增量多包索引功能缺少兩個重要元件

  • 重寫 MIDX 鏈早期部分的能力(即,將相鄰的 MIDX 層集合“壓縮”成單個 MIDX)。目前,縮小 MIDX 鏈的唯一受支援方法是在不帶 --split 標誌的情況下從頭重寫整個鏈。

    目前沒有根本性的限制阻礙實現此功能。為了降低複雜性,它在初始實現中被省略,但將在以後新增。

  • 對可達性點陣圖的支援。經典的單一 MIDX 實現確實支援可達性點陣圖(有關更多詳細資訊,請參閱 gitformat-pack[5] 中標題為“多包索引反向索引”的部分)。

    如上所述,沒有根本性的限制阻礙將增量 MIDX 格式擴充套件以支援可達性點陣圖。下面的設計專門考慮了這一點,並且將在未來的補丁系列中新增對可達性點陣圖的支援。出於與上述相同的原因,它在當前實現中被省略了。

    簡而言之,為了支援增量 MIDX 功能的可達性點陣圖,偽包序的概念被擴充套件到增量 MIDX 鏈的每個層,以形成一個串聯的偽包序。這種串聯與鏈本身以相同的順序發生(換句話說,對於鏈 {$H1, $H2, $H3} 的串聯偽包序將是 $H1 的偽包序,然後是 $H2 的偽包序,再然後是 $H3 的偽包序)。

    佈局將隨後被擴充套件,以便增量 MIDX 鏈的每個層都可以寫入一個 *.bitmap 檔案。每個層的點陣圖中的物件都按鏈中前一層中的物件數量進行偏移。

檔案佈局

增量 MIDX 不儲存單個 multi-pack-index 檔案(帶可選的 .rev.bitmap 副檔名)在 $GIT_DIR/objects/pack 中,而是採用以下佈局儲存:

$GIT_DIR/objects/pack/multi-pack-index.d/
$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-chain
$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H1.midx
$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H2.midx
$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H3.midx

multi-pack-index-chain 檔案按順序包含鏈中增量 MIDX 檔案的列表。上面的示例顯示了一個鏈,其 multi-pack-index-chain 檔案將包含以下行:

$H1
$H2
$H3

multi-pack-index-$H1.midx 檔案包含多包索引鏈的第一層。multi-pack-index-$H2.midx 檔案包含鏈的第二層,依此類推。

當增量和非增量 MIDX 都存在時,非增量 MIDX 總是首先被讀取。

增量 MIDX 的物件位置

在原始的多包索引設計中,我們透過物件在其倉庫的單一多包索引中的字典序位置(按物件 ID)來引用物件。在增量多包索引設計中,我們透過物件在 MIDX 鏈中每個元件的串聯字典序中的索引來引用物件。

如果 objects_nr() 是一個返回給定 MIDX 層中物件數量的函式,那麼在(例如)$H3 中,位於字典序位置 i 的物件的索引定義為

objects_nr($H2) + objects_nr($H1) + i

(在 C 實現中,這通常計算為 i + m->num_objects_in_base)。

增量 MIDX 的偽包序

多包可達性點陣圖的原始實現,在 gitformat-pack[5] 中(參閱標題為“多包索引反向索引”的部分)大致定義了偽包序如下:

簡而言之,MIDX 的偽包是 MIDX 儲存的包中物件的去重串聯,按包序排列,並且包按 MIDX 序排列(首選包在前)。

在增量 MIDX 設計中,我們將此定義擴充套件為包含 MIDX 鏈多個層中的物件。增量 MIDX 的偽包序透過按順序串聯 MIDX 鏈每個層的偽包序來確定。形式上,兩個物件 o1o2 的比較方式如下:

  1. 如果 o1 出現在 MIDX 鏈中比 o2 更早的層中,則 o1o2 之前排序。

  2. 否則,如果 o1o2 出現在同一個 MIDX 層中,並且該 MIDX 層沒有基礎層,那麼如果 pack(o1)pack(o2) 中的一個被首選而另一個不是,則首選的那個排在非首選的那個之前。如果存在基礎層(即,該 MIDX 層不是鏈中的第一層),那麼如果 pack(o1) 在該 MIDX 層的包序中出現得更早,則 o1o2 之前排序。同樣,如果 pack(o2) 出現得更早,則情況相反。

  3. 否則,o1o2 出現在同一個包中,因此也在同一個 MIDX 層中。根據它們在包含它們的 packfile 中的偏移量對 o1o2 進行排序。

請注意,首選包是 MIDX 鏈的屬性,而不是各個層本身的屬性。從根本上說,我們可以引入每層首選包,但現在我們可以在 MIDX 中的所有包之間執行多包複用,這就不那麼重要了。

可達性點陣圖和增量 MIDX

增量 MIDX 鏈的每個層都可以將其物件(以及同一 MIDX 鏈中任何先前層中的物件)表示在自己的 *.bitmap 檔案中。

屬於增量 MIDX 鏈的 *.bitmap 檔案的結構與非增量 MIDX 點陣圖或經典單包點陣圖的結構相同。由於物件被新增到增量 MIDX 的偽包序的末尾(見上文),因此在追加到 MIDX 鏈的末尾時可以擴充套件點陣圖。

(注意:類似地,可以將 MIDX 增量層的連續序列及其 *.bitmap 檔案壓縮到單個層和 *.bitmap 中,但這尚未實現。)

使用的物件位置在偽包序中是全域性的,因此後續層將分別在其四個型別點陣圖中擁有(例如)m->num_objects_in_base0 位。這是因為我們只為與點陣圖直接對應的層中存在的物件寫入型別點陣圖條目)。

另請注意,增量 MIDX 鏈中最新層所涉及的點陣圖用於儲存關於可達性查詢中相關物件和不相關物件的可達性資訊。較早的點陣圖層僅用於從該層查詢提交和偽合併點陣圖,以及該層中物件的型別級點陣圖。

為了簡化實現,型別級點陣圖同時迭代,並且它們的結果進行邏輯或操作,以避免遞迴呼叫內部點陣圖函式。

未來工作

  • 如果多包索引擴充套件為儲存“穩定物件順序”(一個函式 Order(hash) = 整數,對於給定的雜湊是常量,即使多包索引更新),那麼 MIDX 點陣圖可以獨立於 MIDX 更新。

  • packfile 可以透過使用空檔案標記為“特殊”,這些空檔案共享初始名稱但將“.pack”替換為“.keep”或“.promisor”。我們可以在多包索引中新增一個可選的資料塊,用於記錄有關 packfile 的標誌資訊。這允許新的狀態,例如重新打包重新增量化,有助於在多包環境中進行包維護。按物件型別(提交、樹、blob 等)組織 packfile 並使用此元資料來幫助維護也可能很有用。

[0] https://bugs.chromium.org/p/git/issues/detail?id=6 Chromium 工作項:多包索引 (MIDX)

[2] https://lore.kernel.org/git/alpine.DEB.2.20.1803091557510.23109@alexmv-linux/ Git Merge 2018 貢獻者峰會筆記(包括 MIDX 討論)

scroll-to-top