Skip to content

Commit

Permalink
Work around EMFILE when there are too many pack files
Browse files Browse the repository at this point in the history
When opening any files in the object database, release unused pack
windows if the open(2) syscall fails due to EMFILE (too many open
files in this process).  This allows Git to degrade gracefully on
a repository with thousands of pack files, and a commit stored in
a loose object in the middle of the history.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Shawn O. Pearce authored and Junio C Hamano committed Nov 3, 2010
1 parent 4865d2b commit f2e872a
Showing 1 changed file with 27 additions and 16 deletions.
43 changes: 27 additions & 16 deletions sha1_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ static size_t sz_fmt(size_t s) { return s; }

const unsigned char null_sha1[20];

static int git_open_noatime(const char *name);
static int git_open_noatime(const char *name, struct packed_git *p);

int safe_create_leading_directories(char *path)
{
Expand Down Expand Up @@ -300,7 +300,7 @@ static void read_info_alternates(const char * relative_base, int depth)
int fd;

sprintf(path, "%s/%s", relative_base, alt_file_name);
fd = git_open_noatime(path);
fd = git_open_noatime(path, NULL);
if (fd < 0)
return;
if (fstat(fd, &st) || (st.st_size == 0)) {
Expand Down Expand Up @@ -413,7 +413,7 @@ static int check_packed_git_idx(const char *path, struct packed_git *p)
struct pack_idx_header *hdr;
size_t idx_size;
uint32_t version, nr, i, *index;
int fd = git_open_noatime(path);
int fd = git_open_noatime(path, p);
struct stat st;

if (fd < 0)
Expand Down Expand Up @@ -657,9 +657,7 @@ static int open_packed_git_1(struct packed_git *p)
if (!p->index_data && open_pack_index(p))
return error("packfile %s index unavailable", p->pack_name);

p->pack_fd = git_open_noatime(p->pack_name);
while (p->pack_fd < 0 && errno == EMFILE && unuse_one_window(p, -1))
p->pack_fd = git_open_noatime(p->pack_name);
p->pack_fd = git_open_noatime(p->pack_name, p);
if (p->pack_fd < 0 || fstat(p->pack_fd, &st))
return -1;

Expand Down Expand Up @@ -876,7 +874,7 @@ static void prepare_packed_git_one(char *objdir, int local)
sprintf(path, "%s/pack", objdir);
len = strlen(path);
dir = opendir(path);
while (!dir && errno == EMFILE && unuse_one_window(packed_git, -1))
while (!dir && errno == EMFILE && unuse_one_window(NULL, -1))
dir = opendir(path);
if (!dir) {
if (errno != ENOENT)
Expand Down Expand Up @@ -1024,18 +1022,31 @@ int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long siz
return hashcmp(sha1, real_sha1) ? -1 : 0;
}

static int git_open_noatime(const char *name)
static int git_open_noatime(const char *name, struct packed_git *p)
{
static int sha1_file_open_flag = O_NOATIME;
int fd = open(name, O_RDONLY | sha1_file_open_flag);

/* Might the failure be due to O_NOATIME? */
if (fd < 0 && errno != ENOENT && sha1_file_open_flag) {
fd = open(name, O_RDONLY);
for (;;) {
int fd = open(name, O_RDONLY | sha1_file_open_flag);
if (fd >= 0)
return fd;

/* Might the failure be insufficient file descriptors? */
if (errno == EMFILE) {
if (unuse_one_window(p, -1))
continue;
else
return -1;
}

/* Might the failure be due to O_NOATIME? */
if (errno != ENOENT && sha1_file_open_flag) {
sha1_file_open_flag = 0;
continue;
}

return -1;
}
return fd;
}

static int open_sha1_file(const unsigned char *sha1)
Expand All @@ -1044,7 +1055,7 @@ static int open_sha1_file(const unsigned char *sha1)
char *name = sha1_file_name(sha1);
struct alternate_object_database *alt;

fd = git_open_noatime(name);
fd = git_open_noatime(name, NULL);
if (fd >= 0)
return fd;

Expand All @@ -1053,7 +1064,7 @@ static int open_sha1_file(const unsigned char *sha1)
for (alt = alt_odb_list; alt; alt = alt->next) {
name = alt->name;
fill_sha1_path(name, sha1);
fd = git_open_noatime(alt->base);
fd = git_open_noatime(alt->base, NULL);
if (fd >= 0)
return fd;
}
Expand Down Expand Up @@ -2314,7 +2325,7 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,

filename = sha1_file_name(sha1);
fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
while (fd < 0 && errno == EMFILE && unuse_one_window(packed_git, -1))
while (fd < 0 && errno == EMFILE && unuse_one_window(NULL, -1))
fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
if (fd < 0) {
if (errno == EACCES)
Expand Down

0 comments on commit f2e872a

Please sign in to comment.