Gitの.git / objects /フォルダーが多くのSHAプレフィックスフォルダーに分割されているのはなぜですか?


21

Gitは、オブジェクト(Blob、ツリー)を.git/objects/フォルダーに内部的に保存します。各オブジェクトは、オブジェクトのコンテンツから計算されるSHA1ハッシュによって参照できます。

ただし、オブジェクトは.git/objects/フォルダ内に直接保存されません。代わりに、各オブジェクトは、SHA1ハッシュのプレフィックスで始まるフォルダー内に保存されます。そのため、ハッシュb7e23ec29af22b0b4e41da31e868d57226121c84を持つオブジェクトは次の場所に保存されます.git/objects/b7/e23ec29af22b0b4e41da31e868d57226121c84

Gitがオブジェクトストレージをこのように細分するのはなぜですか?

git-scmのGitの内部のページなど、私が見つけることができるリソースは、howではなくhowだけを説明しました

回答:


33

すべてのファイルを1つのディレクトリに置くことは可能ですが、それが少し大きくなることもあります。 多くのファイルシステムには制限があります。USBスティックのFAT32フォーマットのドライブにGitリポジトリを置きたいですか?1つのディレクトリに65,535個のファイルしか保存できません。これは、単一のディレクトリがいっぱいになる可能性が低くなるように、ディレクトリ構造を細分化する必要があることを意味します。

これは、他のファイルシステムや大規模なgitリポジトリでも問題になります。ぶらぶらしている比較的小さなgitレポジトリ(約360MiB)で、11kファイル用に181,546個のオブジェクトがあります。プルのLinuxレポを、あなたは4374054個のオブジェクトを持っています。これらをすべて1つのディレクトリに配置すると、ファイルシステムをチェックアウトできず、(「クラッシュ」の意味で)クラッシュします。

そう?バイトごとに分割します。FireFoxなどのアプリケーションでも同様のアプローチが行われます。

~/Li/Ca/Fi/Pr/7a/Cache $ ls
0/           4/           8/           C/           _CACHE_001_
1/           5/           9/           D/           _CACHE_002_
2/           6/           A/           E/           _CACHE_003_
3/           7/           B/           F/           _CACHE_MAP_

これ以外にも、パフォーマンスの問題があります。多数の長いファイル名を使用したNTFSパフォーマンスを考慮してください。

Windows NTは、単一のディレクトリに長いファイル名(8.3形式の規則に準拠しない名前)を持つ多数のファイルを含むWindows NTファイルシステム(NTFS)形式のドライブでディレクトリ操作を実行するのに時間がかかります。

NTFSがディレクトリ内のファイルを列挙するとき、長いファイル名に関連付けられている8.3名を検索する必要があります。NTFSディレクトリは並べ替えられた状態で維持されるため、対応する長いファイル名と8.3形式の名前は通常、ディレクトリ一覧で隣り合っていません。したがって、NTFSは、存在するすべてのファイルに対してディレクトリの線形検索を使用します。その結果、ディレクトリリストの実行に必要な時間は、ディレクトリ内のファイル数の2乗に比例して増加します。少数のファイル(数百未満)の場合、時間遅延は無視できます。ただし、ディレクトリ内のファイルの数が数千に増加すると、リストの実行に必要な時間が数分、数時間、または数日にも増加する可能性があります。長いファイル名が非常に似ている場合、最後の数文字だけが異なる場合、問題は悪化します。

SHA1チェックサムにちなんで名前が付けられたファイルでは、これは災害とひどいパフォーマンスのレシピになる可能性があります。

これはのようなものでも見ることができる- (一般的に1995年から2000年代初頭に使用し、NTFS 1.2)以上では、Windows NT 3.5からテクニカルノートからですがEXT3ファイルシステムの実装はリストリンクされている O(n)は、ルックアップを必要とします。そして、そのBツリーの変更があっても:

HTreeアルゴリズムはルックアップ時間を大幅に改善しましたが、readdir()を使用して大きなディレクトリ内のすべてのファイルの何らかの操作を実行するワークロードのパフォーマンスの低下を引き起こす可能性がありました。
...
ダニエル・フィリップスとアンドレアス・ディルガーによって提案されたが、まだ実装されていないこのパフォーマンスの問題を軽減するための潜在的な解決策の1つは、ファイル名ハッシュによってiノードをグループ化するプロパティを満たすiノード番号を持つ無料のiノードをカーネルが選択することです。DanielとAndreasは、ディレクトリのサイズに基づいてiノードの範囲からiノードを割り当て、ファイル名のハッシュに基づいてその範囲から無料のiノードを選択することを提案しています。これは、理論的には、ディレクトリで参照されているinodeにreaddir順序でアクセスするときに生じるスラッシングの量を減らす必要があります。ただし、この戦略が高速化をもたらすかどうかは明らかではありません。実際、参照する必要のあるiノードブロックの総数が増える可能性があるため、readdir()+ stat()ワークロードのパフォーマンスが低下します。明らかに、

ちなみに、パフォーマンスを改善する方法に関するこのビットは、同じ年のgitがリリースされた2005年からのものでした。

Firefoxや多くのハッシュキャッシュファイルを持つ他の多くのアプリケーションで見られるように、バイトごとにキャッシュを分割する設計。パフォーマンスコストはごくわずかであり、クロスプラットフォームを少し古いシステムで使用すると、プログラムが動作するかどうかが非常によくなります。


1
引用したNTFSパフォーマンスの記事が1994年にリリースされたNT 3.5に適用されることに気づきましたか?
アヴナーシャハル

1
@ AvnerShahar-Kashtanうん。Gitは2005年にリリースされました。NTFSv1.2ベースのファイルシステムを企業環境で使用していたことは、2000年代初期まで(それでもハイテク企業で)知っていました。当時のgitと一般的に利用可能なシステム上のファイルシステムの要件には確かに重複があります。

おそらく、これがgitが導入されたときの技術状態の歴史的成果物である可能性があると述べた場合、おそらく2015年に尋ねられた質問に対して、20年の技術的制限を引用して(答えをたたくと) )わかりにくいようです。
アヴナーシャハル

公平にするために、gitの「パック」システムはこれらの問題の多くを軽減します。理論的にgitは、単一のディレクトリのみを使用し、そのディレクトリ内のファイル数が特定の(おそらくFSに依存する)制限を超えたときに再パックすることもできます。
nneonneo

5
@ AvnerShahar-KashtanリンクされたSOの記事を読むと、NT 3.5だけでなく、複数のファイルシステムとオペレーティングシステムで多数のファイルを含むディレクトリを扱うことが問題になることがわかります。ファイルの制限は別として、ファイルを一覧表示するだけでも大量のオーバーヘッドが発生する可能性があります。

8

これが望ましい理由は2つあります。

ディレクトリを任意に大きくすることはできません。例えば、いくつかの(かなり現代的な!)ファイルシステムは、単一ディレクトリ内の32000エントリに制限されています。Linuxカーネルでのコミットの数はその程度です。コミットを最初の2桁の16進数で分割すると、最上位のサイズが256エントリに制限されます。サブディレクトリは、典型的なgitリポジトリの場合、はるかに小さくなります。

ディレクトリは直線的にスキャンされます。一部のファイルシステム(Ext *ファミリなど)では、ディレクトリはリンクリストまたはエントリのテーブルです。ファイルを検索するには、一致するファイル名が見つかるまでリスト全体がスキャンされます。明らかに、これはパフォーマンスにとって望ましくありません。多くの最新のファイルシステムでは、高速ルックアップのためにハッシュテーブルまたはBツリーが追加で使用されていますが、誰もが持っているわけではありません。各ディレクトリを小さく保つと、アクセス時間が高速になります。


1
「一部の(かなり現代的な!)ファイルシステムは、単一ディレクトリ内の32000エントリに制限されています。」それがGitが満たす最も厳しい制限である場合、Gitが最初の2つではなく、ハッシュの最初の3文字を使用した方が良いでしょうか?これは、ディレクトリが256に制限される代わりに最大4096のサブディレクトリを保持できることを意味し、上記の要件を満たしますが、これらのサブディレクトリは32000を超えるファイル自体を含む可能性が16倍低くなるという追加の利点があります。objects
サンパブロクパー

1

これらの256バケットにより、gitはディレクトリ内のファイル数を制限するファイルシステムに大きなリポジトリを保存し、多くのファイルを含むディレクトリで遅くなるファイルシステムでパフォーマンスを低下させます。


1

多数のディレクトリエントリでパフォーマンスが低下するファイルシステムやファイルシステムの実装、libcの実装があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.