Tại sao thư mục Git .git / object / được chia nhỏ trong nhiều thư mục tiền tố SHA?


21

Git lưu trữ nội bộ các đối tượng (Blobs, cây) trong .git/objects/thư mục. Mỗi đối tượng có thể được tham chiếu bởi hàm băm SHA1 được tính từ nội dung của đối tượng.

Tuy nhiên, các đối tượng không được lưu trữ bên trong .git/objects/thư mục trực tiếp. Thay vào đó, mỗi đối tượng được lưu trữ bên trong một thư mục bắt đầu bằng tiền tố băm SHA1 của nó. Vì vậy, một đối tượng với hàm băm b7e23ec29af22b0b4e41da31e868d57226121c84sẽ được lưu trữ tại.git/objects/b7/e23ec29af22b0b4e41da31e868d57226121c84

Tại sao Git chia nhỏ lưu trữ đối tượng của nó theo cách này?

Các tài nguyên tôi có thể tìm thấy, chẳng hạn như trang trên nội bộ của Git trên git-scm, chỉ giải thích làm thế nào chứ không phải tại sao .

Câu trả lời:


33

Có thể đặt tất cả các tệp trong một thư mục, mặc dù đôi khi điều đó có thể trở nên hơi lớn. Nhiều hệ thống tập tin có một giới hạn . Bạn muốn đặt một kho lưu trữ git trên ổ đĩa được định dạng FAT32 trên thanh USB? Bạn chỉ có thể lưu trữ 65.535 tệp trong một thư mục. Điều này có nghĩa là cần phải chia nhỏ cấu trúc thư mục để việc điền vào một thư mục ít xảy ra.

Điều này thậm chí sẽ trở thành một vấn đề với các hệ thống tập tin khác và kho git lớn hơn. Một repo git tương đối nhỏ mà tôi đã đi chơi (khoảng 360MiB) và nó có 181.546 đối tượng cho các tệp 11k. Kéo repo Linux và bạn đã có 4.374.054 đối tượng. Nếu bạn đặt tất cả những thứ này trong một thư mục, sẽ không thể kiểm tra và sẽ bị sập (vì một số ý nghĩa của 'sự cố') hệ thống tệp.

Vì thế? Bạn chia nó ra theo byte. Cách tiếp cận tương tự được thực hiện với các ứng dụng như 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_

Ngoài ra, nó cũng đi đến một câu hỏi về hiệu suất. Xem xét hiệu suất NTFS với nhiều tên tệp dài :

Windows NT mất nhiều thời gian để thực hiện các thao tác thư mục trên các ổ đĩa được định dạng của hệ thống tệp Windows NT (NTFS) có chứa một số lượng lớn tệp có tên tệp dài (tên không tuân theo quy ước 8.3) trong một thư mục.

Khi NTFS liệt kê các tệp trong một thư mục, nó phải tìm kiếm 8.3 tên được liên kết với các tên tệp dài. Vì một thư mục NTFS được duy trì ở trạng thái được sắp xếp, nên các tên tệp dài và tên 8.3 tương ứng thường không nằm cạnh nhau trong danh sách thư mục. Vì vậy, NTFS sử dụng tìm kiếm tuyến tính của thư mục cho mọi tệp hiện tại. Do đó, lượng thời gian cần thiết để thực hiện danh sách thư mục tăng theo bình phương số lượng tệp trong thư mục. Đối với số lượng nhỏ tệp (dưới vài trăm), thời gian trễ là không đáng kể. Nhưng khi số lượng tệp trong một thư mục tăng lên đến vài nghìn, thời gian cần thiết để thực hiện một danh sách có thể tăng lên đến vài phút, giờ hoặc thậm chí là vài ngày. Vấn đề sẽ trầm trọng hơn nếu tên tệp dài rất giống nhau - chỉ khác nhau ở một vài ký tự cuối cùng.

Với các tệp được đặt tên theo tổng kiểm tra SHA1, đây có thể là một công thức cho hiệu suất thảm họa và kinh tởm.

Mặc dù ở trên là từ một ghi chú công nghệ từ Windows NT 3.5 (và NTFS 1.2 - thường được sử dụng từ năm 1995 đến đầu những năm 2000), điều này cũng có thể được nhìn thấy trong những thứ như EXT3 với việc triển khai hệ thống tệp được liệt kê liên kết yêu cầu tra cứu O (n) . Và ngay cả với sự thay đổi cây B đó:

Mặc dù thuật toán HTree cải thiện đáng kể thời gian tra cứu, nó có thể gây ra một số hồi quy hiệu suất cho khối lượng công việc đã sử dụng readdir () để thực hiện một số thao tác của tất cả các tệp trong một thư mục lớn.
...
Một giải pháp tiềm năng để giảm thiểu vấn đề hiệu năng này, được đề xuất bởi Daniel Phillips và Andreas Dilger, nhưng chưa được triển khai, liên quan đến hạt nhân chọn các nút inode miễn phí có số inode đáp ứng một thuộc tính nhóm băm theo tên tệp băm. Daniel và Andreas đề nghị phân bổ inode từ một loạt các nút dựa trên kích thước của thư mục, sau đó chọn một inode miễn phí từ phạm vi đó dựa trên hàm băm tên tệp. Về lý thuyết, điều này sẽ làm giảm số lượng đập mà kết quả khi truy cập vào các nút được tham chiếu trong thư mục theo thứ tự readdir. Trong đó không rõ ràng rằng chiến lược này sẽ dẫn đến tăng tốc, tuy nhiên; trong thực tế, nó có thể làm tăng tổng số khối inode có thể phải được tham chiếu, và do đó làm cho hiệu suất của khối lượng công việc readdir () + stat () trở nên tồi tệ hơn. Thông suốt,

Ngẫu nhiên, bit này về cách cải thiện hiệu suất là từ năm 2005, cùng năm git đã được phát hành.

Như đã thấy với Firefox và nhiều ứng dụng khác có nhiều tệp được lưu trong bộ nhớ cache, thiết kế chia tách bộ đệm theo byte. Nó có chi phí hiệu năng không đáng kể và khi được sử dụng đa nền tảng với các hệ thống có thể là một chút về phía cũ, rất có thể là sự khác biệt giữa chương trình làm việc hay không.


1
Bạn đã nhận thấy rằng bài viết hiệu suất NTFS mà bạn trích dẫn áp dụng cho NT 3.5, phát hành năm 1994, phải không?
Avner Shahar-Kashtan

1
@ AvnerShahar-Kashtan yep. Git được phát hành vào năm 2005. Tôi biết những gì tôi đã sử dụng hệ thống tệp dựa trên NTFS v1.2 trong môi trường công ty vào đầu những năm 2000 (dù sao tại một công ty công nghệ). Chắc chắn có sự chồng chéo giữa các yêu cầu của git và các hệ thống tệp trên các hệ thống phổ biến tại thời điểm đó.

Có lẽ sẽ rõ ràng hơn nếu bạn tuyên bố rằng đây có thể là một tạo tác lịch sử của tình trạng công nghệ khi git được giới thiệu, bởi vì như vậy, đối với một câu hỏi được hỏi vào năm 2015, trích dẫn một giới hạn kỹ thuật hai mươi tuổi (đưa ra câu trả lời ) có vẻ khó hiểu.
Avner Shahar-Kashtan

Công bằng mà nói, githệ thống "gói" giảm thiểu rất nhiều vấn đề này. Về mặt lý thuyết, gitcó thể chỉ sử dụng một thư mục duy nhất và chỉ đóng gói lại khi số lượng tệp trong thư mục đó vượt quá giới hạn nhất định (có thể phụ thuộc vào FS).
nneonneo

5
@ AvnerShahar-Kashtan nếu bạn đọc bài viết SO được liên kết, bạn có thể thấy rằng việc xử lý các thư mục chứa một số lượng lớn tệp có vấn đề trên nhiều hệ thống tệp và hệ điều hành, không chỉ NT 3.5. Giới hạn tệp sang một bên, thậm chí chỉ liệt kê các tệp có thể phải chịu một lượng lớn chi phí.

8

Có hai lý do tại sao điều này là mong muốn.

Thư mục không thể lớn tùy ý. Ví dụ: một số hệ thống tập tin (hợp lý hiện đại!) Được giới hạn ở 32000 mục trong một thư mục. Số lượng xác nhận trong nhân Linux là theo thứ tự độ lớn đó. Việc phân chia các cam kết bằng hai chữ số hex đầu tiên của chúng giới hạn kích thước cấp cao nhất là 256 mục. Các thư mục con sẽ nhỏ hơn nhiều cho repos git điển hình.

Thư mục được quét tuyến tính. Trong một số hệ thống tệp (ví dụ: họ Ext *), thư mục là danh sách được liên kết hoặc bảng mục nhập. Để tra cứu một tệp, toàn bộ danh sách được quét cho đến khi tìm thấy tên tệp phù hợp. Rõ ràng, điều này là không mong muốn cho hiệu suất. Nhiều hệ thống tệp hiện đại cũng sử dụng bảng băm hoặc cây B để tra cứu nhanh, nhưng không phải ai cũng có thể có chúng. Giữ mỗi thư mục nhỏ có nghĩa là thời gian truy cập nhanh.


1
"một số hệ thống tập tin (hợp lý hiện đại!) bị giới hạn ở 32000 mục trong một thư mục." Nếu đó là giới hạn nghiêm ngặt nhất mà Git gặp phải, thì Git có nên sử dụng ba ký tự đầu tiên của hàm băm, thay vì hai ký tự đầu tiên không? Điều này có nghĩa là objectsthư mục có thể chứa tới 4096 thư mục con thay vì bị giới hạn ở 256, đáp ứng yêu cầu ở trên, nhưng với lợi thế bổ sung là các thư mục con đó sẽ ít có khả năng kết thúc chứa> 32000 tệp.
sampablokuper

1

256 thùng này cho phép git lưu trữ các kho lưu trữ lớn hơn trên các hệ thống tệp giới hạn số tệp trong một thư mục và cung cấp hiệu suất gốc trên các hệ thống tệp trở nên chậm hơn với các thư mục chứa nhiều tệp.


1

Có một số hệ thống tập tin và / hoặc triển khai hệ thống tập tin và / hoặc triển khai libc trong đó hiệu suất giảm xuống với số lượng lớn các mục nhập thư mục.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.