Mengapa Git .git / objek / folder terbagi dalam banyak folder awalan SHA?

21

Git secara internal menyimpan objek (Gumpalan, pohon) di .git/objects/folder. Setiap objek dapat direferensikan oleh hash SHA1 yang dihitung dari isi objek.

Namun, Objek tidak disimpan di dalam .git/objects/folder secara langsung. Sebaliknya, setiap objek disimpan di dalam folder yang dimulai dengan awalan hash SHA1-nya. Jadi objek dengan hash b7e23ec29af22b0b4e41da31e868d57226121c84akan disimpan di.git/objects/b7/e23ec29af22b0b4e41da31e868d57226121c84

Mengapa Git membagi penyimpanan objeknya dengan cara ini?

Sumber daya yang dapat saya temukan, seperti halaman di internal Git di git-scm, hanya menjelaskan caranya , bukan mengapa .

Qqwy
sumber

Jawaban:

33

Dimungkinkan untuk meletakkan semua file dalam satu direktori, meskipun terkadang itu bisa menjadi agak besar. Banyak sistem file memiliki batas . Anda ingin meletakkan repositori git pada drive yang diformat FAT32 pada stik USB? Anda hanya dapat menyimpan 65.535 file dalam satu direktori. Ini berarti bahwa perlu untuk membagi struktur direktori sehingga mengisi satu direktori lebih kecil kemungkinannya.

Ini bahkan akan menjadi masalah dengan sistem file lain dan repositori git yang lebih besar. Repo git yang relatif kecil yang saya dapatkan (sekitar 360MiB) dan memiliki 181.546 objek untuk file 11k. Tarik repo Linux dan Anda punya 4.374.054 objek. Jika Anda meletakkan semua ini dalam satu direktori, tidak mungkin untuk memeriksa dan akan crash (untuk beberapa arti 'crash') sistem file.

Begitu? Anda membaginya dengan byte. Pendekatan serupa dilakukan dengan aplikasi seperti 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_

Selain itu, ini juga menyangkut masalah kinerja. Pertimbangkan Kinerja NTFS dengan Banyak Nama File Panjang :

Windows NT membutuhkan waktu lama untuk melakukan operasi direktori pada drive yang diformat sistem file Windows NT (NTFS) yang berisi sejumlah besar file dengan nama file yang panjang (nama yang tidak sesuai dengan konvensi 8.3) dalam satu direktori.

Ketika NTFS menghitung file dalam direktori, itu harus mencari 8,3 nama yang terkait dengan nama file panjang. Karena direktori NTFS dikelola dalam keadaan diurutkan, nama file panjang dan 8.3 nama yang sesuai umumnya tidak bersebelahan dalam daftar direktori. Jadi, NTFS menggunakan pencarian linear dari direktori untuk setiap file yang ada. Akibatnya, jumlah waktu yang diperlukan untuk melakukan daftar direktori meningkat dengan kuadrat jumlah file dalam direktori. Untuk sejumlah kecil file (kurang dari beberapa ratus) waktu tunda dapat diabaikan. Tetapi karena jumlah file dalam direktori meningkat hingga beberapa ribu, waktu yang diperlukan untuk melakukan listing dapat meningkat menjadi beberapa menit, jam, atau bahkan berhari-hari. Masalahnya diperburuk jika nama file yang panjang sangat mirip - hanya berbeda dalam beberapa karakter terakhir.

Dengan file yang dinamai dengan checksum SHA1, ini bisa menjadi resep untuk kinerja bencana dan buruk.

Sementara di atas adalah dari catatan teknologi dari Windows NT 3.5 (dan NTFS 1.2 - biasa digunakan dari 1995 hingga awal 2000-an) ini juga dapat dilihat dalam hal-hal seperti EXT3 dengan implementasi dari filesystem yang dihubungkan daftar yang memerlukan O (n) lookup . Dan bahkan dengan perubahan B-tree:

Sementara algoritma HTree secara signifikan meningkatkan waktu pencarian, hal itu dapat menyebabkan beberapa regresi kinerja untuk beban kerja yang menggunakan readdir () untuk melakukan beberapa operasi semua file dalam direktori besar.
...
Salah satu solusi potensial untuk mengurangi masalah kinerja ini, yang telah disarankan oleh Daniel Phillips dan Andreas Dilger, tetapi belum diimplementasikan, melibatkan kernel memilih inode bebas yang nomor inodenya memenuhi properti yang mengelompokkan inode dengan hash nama file mereka. Daniel dan Andreas menyarankan untuk mengalokasikan inode dari berbagai inode berdasarkan ukuran direktori, dan kemudian memilih inode gratis dari rentang itu berdasarkan hash nama file. Ini seharusnya secara teori mengurangi jumlah labrakan yang dihasilkan saat mengakses inode yang dirujuk dalam direktori dalam urutan readdir. Namun tidak jelas bahwa strategi ini akan menghasilkan percepatan; sebenarnya itu dapat meningkatkan jumlah total blok inode yang mungkin harus direferensikan, dan dengan demikian membuat kinerja readdir () + stat () beban kerja lebih buruk. Jelas,

Kebetulan, ini sedikit tentang cara meningkatkan kinerja dari tahun 2005, tahun yang sama git dirilis.

Seperti yang terlihat dengan Firefox dan banyak aplikasi lain yang memiliki banyak file cache hash, desain memecah cache dengan byte. Ini memiliki biaya kinerja yang dapat diabaikan, dan ketika digunakan lintas platform dengan sistem yang mungkin sedikit di sisi lama, bisa sangat baik perbedaan antara program yang bekerja atau tidak.

Komunitas
sumber
1
Anda memang memperhatikan bahwa artikel kinerja NTFS yang Anda kutip berlaku untuk NT 3.5, dirilis 1994, kan?
Avner Shahar-Kashtan
1
@ AvnerShahar-Kashtan ya Git dirilis pada tahun 2005. Saya tahu apa yang saya gunakan sistem file berbasis NTFS v1.2 di lingkungan perusahaan hingga awal 2000-an (di sebuah perusahaan teknologi tetap). Jelas ada tumpang tindih antara persyaratan git dan sistem file pada sistem yang tersedia saat itu.
Mungkin akan lebih jelas jika Anda menyatakan bahwa ini mungkin merupakan artefak sejarah keadaan teknologi ketika git diperkenalkan, karena seperti yang terjadi, untuk pertanyaan yang diajukan pada tahun 2015, mengutip batasan teknis berusia dua puluh tahun (mengambil hald jawabannya) ) tampaknya membingungkan.
Avner Shahar-Kashtan
Agar adil, gitsistem "paket" mengurangi banyak masalah ini. Secara teoritis, gitbisa menggunakan hanya satu direktori, dan hanya mengemas ulang ketika jumlah file dalam direktori itu melebihi batas tertentu (mungkin tergantung pada FS).
nneonneo
5
@ AvnerShahar-Kashtan jika Anda membaca artikel SO yang ditautkan, Anda dapat melihat bahwa berurusan dengan direktori yang berisi banyak file bermasalah pada banyak sistem file dan sistem operasi, bukan hanya NT 3.5. Mengesampingkan batas file, bahkan hanya dengan mendaftarkan file dapat menyebabkan sejumlah besar overhead.
8

Ada dua alasan mengapa ini diinginkan.

Direktori tidak boleh besar secara sewenang-wenang. Misalnya beberapa sistem file (yang cukup modern!) Terbatas pada 32000 entri dalam satu direktori. Jumlah komit di kernel Linux dalam urutan besarnya. Membagi komit dengan dua digit hex pertama membatasi ukuran tingkat atas hingga 256 entri. Sub-direktori akan jauh lebih kecil untuk repositori git tipikal.

Direktori dipindai secara linear. Dalam beberapa sistem file (misalnya keluarga Ext *), direktori adalah daftar atau tabel entri yang ditautkan. Untuk mencari file, seluruh daftar dipindai sampai nama file yang cocok ditemukan. Jelas, ini tidak diinginkan untuk kinerja. Banyak sistem file modern juga menggunakan tabel hash atau B-tree untuk pencarian cepat, tetapi tidak semua orang memilikinya. Menjaga setiap direktori tetap kecil berarti waktu akses yang cepat.

amon
sumber
1
"beberapa sistem file (yang cukup modern!) terbatas pada 32000 entri dalam satu direktori." Jika itu adalah batasan paling ketat yang Git temui, maka bukankah lebih baik bagi Git untuk menggunakan tiga karakter pertama dari hash, daripada dua yang pertama ? Ini berarti objectsdirektori tersebut dapat menampung hingga 4096 subdirektori alih-alih terbatas pada 256, memenuhi persyaratan di atas, tetapi dengan keuntungan tambahan bahwa subdirektori tersebut 16x lebih kecil kemungkinannya untuk berisi> 32000 file.
sampablokuper
1

256 bucket ini memungkinkan git untuk menyimpan repositori yang lebih besar pada sistem file yang membatasi jumlah file dalam direktori dan memberikan kinerja turunan pada sistem file yang menjadi lebih lambat dengan direktori yang berisi banyak file.

Kasper van den Berg
sumber
1

Ada beberapa filesystem dan / atau implementasi filesystem dan / atau implementasi libc di mana kinerja menurun dengan sejumlah besar entri direktori.

Jörg W Mittag
sumber