Skip to content

Commit d131b7a

Browse files
spearcegitster
authored andcommitted
sha1_file.c: Don't retain open fds on small packs
If a pack file is small enough that its entire contents fits within one mmap window, mmap the file and then immediately close its file descriptor. This reduces the number of file descriptors that are needed to read from repositories with many tiny pack files, such as one that has received 1000 pushes (and created 1000 small pack files) since its last repack. Signed-off-by: Shawn O. Pearce <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 38abd9b commit d131b7a

File tree

3 files changed

+39
-6
lines changed

3 files changed

+39
-6
lines changed

cache.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,8 @@ extern struct packed_git {
899899
time_t mtime;
900900
int pack_fd;
901901
unsigned pack_local:1,
902-
pack_keep:1;
902+
pack_keep:1,
903+
do_not_close:1;
903904
unsigned char sha1[20];
904905
/* something like ".git/objects/pack/xxxxx.pack" */
905906
char pack_name[FLEX_ARRAY]; /* more */

fast-import.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,7 @@ static void start_packfile(void)
871871
p = xcalloc(1, sizeof(*p) + strlen(tmpfile) + 2);
872872
strcpy(p->pack_name, tmpfile);
873873
p->pack_fd = pack_fd;
874+
p->do_not_close = 1;
874875
pack_file = sha1fd(pack_fd, p->pack_name);
875876

876877
hdr.hdr_signature = htonl(PACK_SIGNATURE);

sha1_file.c

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,8 @@ static int unuse_one_window(struct packed_git *current, int keep_fd)
596596
lru_l->next = lru_w->next;
597597
else {
598598
lru_p->windows = lru_w->next;
599-
if (!lru_p->windows && lru_p->pack_fd != keep_fd) {
599+
if (!lru_p->windows && lru_p->pack_fd != -1
600+
&& lru_p->pack_fd != keep_fd) {
600601
close(lru_p->pack_fd);
601602
pack_open_fds--;
602603
lru_p->pack_fd = -1;
@@ -812,14 +813,13 @@ unsigned char *use_pack(struct packed_git *p,
812813
{
813814
struct pack_window *win = *w_cursor;
814815

815-
if (p->pack_fd == -1 && open_packed_git(p))
816-
die("packfile %s cannot be accessed", p->pack_name);
817-
818816
/* Since packfiles end in a hash of their content and it's
819817
* pointless to ask for an offset into the middle of that
820818
* hash, and the in_window function above wouldn't match
821819
* don't allow an offset too close to the end of the file.
822820
*/
821+
if (!p->pack_size && p->pack_fd == -1 && open_packed_git(p))
822+
die("packfile %s cannot be accessed", p->pack_name);
823823
if (offset > (p->pack_size - 20))
824824
die("offset beyond end of packfile (truncated pack?)");
825825

@@ -833,6 +833,10 @@ unsigned char *use_pack(struct packed_git *p,
833833
if (!win) {
834834
size_t window_align = packed_git_window_size / 2;
835835
off_t len;
836+
837+
if (p->pack_fd == -1 && open_packed_git(p))
838+
die("packfile %s cannot be accessed", p->pack_name);
839+
836840
win = xcalloc(1, sizeof(*win));
837841
win->offset = (offset / window_align) * window_align;
838842
len = p->pack_size - win->offset;
@@ -850,6 +854,12 @@ unsigned char *use_pack(struct packed_git *p,
850854
die("packfile %s cannot be mapped: %s",
851855
p->pack_name,
852856
strerror(errno));
857+
if (!win->offset && win->len == p->pack_size
858+
&& !p->do_not_close) {
859+
close(p->pack_fd);
860+
pack_open_fds--;
861+
p->pack_fd = -1;
862+
}
853863
pack_mmap_calls++;
854864
pack_open_windows++;
855865
if (pack_mapped > peak_pack_mapped)
@@ -1950,6 +1960,27 @@ off_t find_pack_entry_one(const unsigned char *sha1,
19501960
return 0;
19511961
}
19521962

1963+
static int is_pack_valid(struct packed_git *p)
1964+
{
1965+
/* An already open pack is known to be valid. */
1966+
if (p->pack_fd != -1)
1967+
return 1;
1968+
1969+
/* If the pack has one window completely covering the
1970+
* file size, the pack is known to be valid even if
1971+
* the descriptor is not currently open.
1972+
*/
1973+
if (p->windows) {
1974+
struct pack_window *w = p->windows;
1975+
1976+
if (!w->offset && w->len == p->pack_size)
1977+
return 1;
1978+
}
1979+
1980+
/* Force the pack to open to prove its valid. */
1981+
return !open_packed_git(p);
1982+
}
1983+
19531984
static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
19541985
{
19551986
static struct packed_git *last_found = (void *)1;
@@ -1979,7 +2010,7 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
19792010
* it may have been deleted since the index
19802011
* was loaded!
19812012
*/
1982-
if (p->pack_fd == -1 && open_packed_git(p)) {
2013+
if (!is_pack_valid(p)) {
19832014
error("packfile %s cannot be accessed", p->pack_name);
19842015
goto next;
19852016
}

0 commit comments

Comments
 (0)