Git .git / objects / klasörü neden birçok SHA öneki klasöründe alt bölümlere ayrılmıştır?


21

Git dahili olarak nesneleri (Blobs, ağaçlar) .git/objects/klasörde saklar . Her nesneye, nesnenin içeriğinden hesaplanan bir SHA1 karması ile başvurulabilir.

Ancak, nesneler .git/objects/doğrudan klasörün içinde saklanmaz . Bunun yerine, her nesne SHA1 karmasının ön ekiyle başlayan bir klasörde saklanır. Yani karma olan bir nesne b7e23ec29af22b0b4e41da31e868d57226121c84depoda saklanır..git/objects/b7/e23ec29af22b0b4e41da31e868d57226121c84

Git neden nesne deposunu bu şekilde böler?

Gibi bulabildiğim kaynakları, seyahatseverlerin Git iç yapısına sayfa git-SCM üzerinde, yalnızca izah nasıl değil neden .

Yanıtlar:


33

Tüm dosyaları bir dizine koymak mümkündür, ancak bu bazen biraz daha büyük olabilir. Birçok dosya sisteminin bir sınırı vardır . USB bellekte FAT32 formatlı bir sürücüye git deposu koymak ister misiniz? Yalnızca 65.535 dosyayı tek bir dizinde saklayabilirsiniz. Bu, dizin yapısını tek bir dizinin doldurulmasının daha az olası olacağı şekilde bölmenin gerekli olduğu anlamına gelir.

Bu, diğer dosya sistemlerinde ve daha büyük git depolarında da sorun olabilir. Takıldığım nispeten küçük bir git deposu (yaklaşık 360MiB) ve 11k dosyaları için 181.546 nesnesi var. Linux deposunu çekin, 4.374.054 nesneye sahipsiniz. Bunları tek bir dizine koyacak olsaydınız, dosya sistemini kontrol etmek ve çökmek (bir miktar 'kilitlenme' anlamında) imkansız olurdu.

Yani? Bayt ile ayırdın. FireFox gibi uygulamalarla da benzer yaklaşımlar yapılmaktadır:

~/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_

Bunun ötesinde, aynı zamanda bir performans sorununa gider. Sayısız Uzun Dosya Adı ile NTFS Performansını Düşünün :

Windows NT, tek bir dizinde uzun dosya adlarına (8.3 kurallarına uymayan adlar) sahip çok sayıda dosya içeren Windows NT dosya sistemi (NTFS) biçimli sürücülerinde dizin işlemlerini gerçekleştirmek için uzun zaman alır.

NTFS bir dizindeki dosyaları sıraladığında, uzun dosya adlarıyla ilişkili 8.3 adı bulmalıdır. Bir NTFS dizini, sıralanmış bir durumda tutulduğundan, karşılık gelen uzun dosya adları ve 8.3 adları, dizin listesinde genellikle yan yana değildir. Bu nedenle, NTFS mevcut her dosya için dizinde doğrusal bir arama kullanır. Sonuç olarak, bir dizin listesini gerçekleştirmek için gereken süre, dizindeki dosya sayısının karesiyle birlikte artar. Az sayıda dosya için (birkaç yüzden az) zaman gecikmesi ihmal edilebilir düzeydedir. Ancak bir dizindeki dosya sayısı birkaç bine yükseldikçe, bir listeyi gerçekleştirmek için gereken süre dakikalara, saatlere ve hatta günlere yükselebilir. Uzun dosya adları birbirine çok benzerse sorun daha da kötüleşir - sadece son birkaç karakterden farklıdır.

SHA1 sağlama toplamından sonra adlandırılmış dosyalarda, bu felaket ve berbat performans için bir reçete olabilir.

(Ve NTFS 1.2 - Yaygın erken 2000'lere 1995 kullanılır) Yukarıdaki Windows NT 3.5 bir teknoloji nottan iken bu da örneğin şeylere görülebilir EXT3'e ile bağlantılı listeleri olma dosya sisteminin uygulamaları O (n) gerektiren arama . Ve o B-ağacı değişikliğinde bile:

HTree algoritması arama sürelerini önemli ölçüde iyileştirirken, readdir () işlevini kullanan iş yükleri için büyük bir dizindeki tüm dosyaların bazı işlemlerini gerçekleştirmek için bazı performans gerilimlerine neden olabilir.
...
Daniel Phillips ve Andreas Dilger tarafından önerilen, ancak henüz uygulanmamış olan bu performans sorununu hafifletmek için olası bir çözüm, inode numaraları, inode'larını dosya adlarının karma değerlerine göre gruplayan bir özelliğe sahip olan serbest inodeları seçmeyi içerir. Daniel ve Andreas, inode'yu dizinin büyüklüğüne göre bir inode aralığından ayırmayı ve sonra da dosya adı karma değerini temel alarak o aralıktan bir inode seçmeyi önerir. Bu teorik olarak, readdir sırasına dizinde belirtilen inode'lara erişirken ortaya çıkan yığılma miktarını azaltmalıdır. Bununla birlikte, bu stratejinin hızlanmaya neden olacağı açık değildir; aslında, başvuruda bulunulması gerekebilecek toplam inode bloğu sayısını artırabilir ve bu nedenle readdir () + stat () iş yüklerinin performansını daha da kötüleştirebilir. Açıkça,

Bu arada, performansın nasıl artırılacağı konusundaki bu bit 2005'ten itibaren gitti, aynı yıl serbest bırakıldı.

Firefox'ta ve çok sayıda karma önbelleğe alınmış dosya içeren birçok uygulamada görüldüğü gibi, önbelleği baytla bölme tasarımı. Bu, ihmal edilebilir bir performans maliyetine sahiptir ve eski tarafta biraz olabilen sistemler ile çapraz platform kullanıldığında, programın çalışıp çalışmadığı arasındaki fark çok iyi olabilir.


1
Aldığınız NTFS performans makalesinin 1994 tarihli NT 3.5'e uygulandığını fark ettiniz, değil mi?
Avner Shahar-Kashtan

1
@ AvnerShahar-Kashtan evet. Git 2005 yılında piyasaya sürüldü. NTFS v1.2 tabanlı dosya sistemlerini, 2000'li yılların başında (yine de bir teknoloji firmasında) kurumsal bir ortamda kullandığımı biliyorum. Git'in gereklilikleri ve o sırada yaygın olarak bulunan sistemlerdeki dosya sistemleri arasında kesinlikle bir örtüşme vardır.

Belki bunun, git tanıtıldığı zamanki teknolojinin tarihsel bir eseri olabileceğini söyleseydiniz daha açık olurdu, çünkü 2015'te sorulan bir soru için, yirmi yıllık bir teknik sınırlamadan alıntı yaparak (cevabını alıyordu) ) kafa karıştırıcı görünüyor.
Avner Shahar-Kashtan

Adil olmak gerekirse, git'' pack '' sistemi bu sorunların çoğunu hafifletir. Teorik olarak, gityalnızca tek bir dizin kullanıyor olabilir ve bu dizindeki dosya sayısı belirli (muhtemelen FS'ye bağımlı) bir sınırı aştığında yeniden paketleme yapar.
nneonneo

5
@ AvnerShahar-Kashtan bağlantılı SO makalesini okursanız, çok sayıda dosya içeren dizinlerle çalışmanın sadece NT 3.5 değil, birden fazla dosya sisteminde ve işletim sisteminde sorunlu olduğunu görebilirsiniz. Dosya sınırları bir yana, sadece dosyaları listelemek bile büyük miktarda ek yüke neden olabilir.

8

Bunun istenmesinin iki nedeni var.

Dizinler isteğe bağlı olarak büyük olamaz. Örneğin, bazı (oldukça modern!) Dosya sistemleri tek bir dizindeki 32000 giriş ile sınırlıdır. Linux çekirdeğindeki işlemelerin sayısı bu büyüklük sırasına göredir. Taahhütleri ilk iki onaltılık haneye göre alt bölümlere yerleştirmek üst seviye boyutu 256 girişle sınırlar. Alt dizinler tipik git repoları için çok daha küçük olacaktır.

Dizinler doğrusal olarak taranır. Bazı dosya sistemlerinde (örneğin, Ext * ailesi), bir dizin bağlantılı bir liste veya giriş tablosudur. Bir dosyayı aramak için, eşleşen bir dosya adı bulunana kadar listenin tamamı taranır. Açıkçası, bu performans için istenmeyen bir durumdur. Çoğu modern dosya sistemi ayrıca hızlı arama için karma tabloları veya B-ağaçları kullanır, ancak herkesin elinde olmayabilir. Her dizini küçük tutmak, hızlı erişim süreleri demektir.


1
"bazı (oldukça modern!) dosya sistemleri tek bir dizindeki 32000 girişle sınırlıdır." O Git toplantıdır en katı sınırlama ise Git birinci kullanmış etmek için, o zaman daha iyi olmaz üç öncelikle yerine, esrar karakterleri ikisi ? Bu, objectsdizinin yukarıdaki şartı yerine getirerek 256 ile sınırlandırmak yerine 4096'ya kadar alt dizini tutabileceği, ancak bu alt dizinlerin> 32000 dosya içermesi ihtimalinin 16 kat daha düşük olacağı anlamına geleceği anlamına gelir .
sampablokuper 11:16

1

Bu 256 kova, git'in bir dizindeki sayı dosyalarını sınırlayan dosya sistemlerinde daha büyük depoları saklamasını ve birçok dosya içeren dizinlerle yavaşlayan dosya sistemlerinde iniş performansı sağlamasını sağlar.


1

Performansın çok sayıda dizin girdisi ile düştüğü bazı dosya sistemleri ve / veya dosya sistemi uygulamaları ve / veya libc uygulamaları vardır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.