Merge branch 'bc/unuse-packfile'

Handle memory pressure and file descriptor pressure separately when
deciding to release pack windows to honor resource limits.

* bc/unuse-packfile:
  Don't close pack fd when free'ing pack windows
  sha1_file: introduce close_one_pack() to close packs on fd pressure
This commit is contained in:
Junio C Hamano 2013-09-04 12:30:21 -07:00
commit 04fbba0119
3 changed files with 87 additions and 17 deletions

View file

@ -1809,7 +1809,7 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
static void try_to_free_from_threads(size_t size)
{
read_lock();
release_pack_memory(size, -1);
release_pack_memory(size);
read_unlock();
}

View file

@ -524,7 +524,7 @@ int inet_pton(int af, const char *src, void *dst);
const char *inet_ntop(int af, const void *src, char *dst, size_t size);
#endif
extern void release_pack_memory(size_t, int);
extern void release_pack_memory(size_t);
typedef void (*try_to_free_t)(size_t);
extern try_to_free_t set_try_to_free_routine(try_to_free_t);

View file

@ -614,7 +614,7 @@ static void scan_windows(struct packed_git *p,
}
}
static int unuse_one_window(struct packed_git *current, int keep_fd)
static int unuse_one_window(struct packed_git *current)
{
struct packed_git *p, *lru_p = NULL;
struct pack_window *lru_w = NULL, *lru_l = NULL;
@ -628,15 +628,8 @@ static int unuse_one_window(struct packed_git *current, int keep_fd)
pack_mapped -= lru_w->len;
if (lru_l)
lru_l->next = lru_w->next;
else {
else
lru_p->windows = lru_w->next;
if (!lru_p->windows && lru_p->pack_fd != -1
&& lru_p->pack_fd != keep_fd) {
close(lru_p->pack_fd);
pack_open_fds--;
lru_p->pack_fd = -1;
}
}
free(lru_w);
pack_open_windows--;
return 1;
@ -644,10 +637,10 @@ static int unuse_one_window(struct packed_git *current, int keep_fd)
return 0;
}
void release_pack_memory(size_t need, int fd)
void release_pack_memory(size_t need)
{
size_t cur = pack_mapped;
while (need >= (cur - pack_mapped) && unuse_one_window(NULL, fd))
while (need >= (cur - pack_mapped) && unuse_one_window(NULL))
; /* nothing */
}
@ -658,7 +651,7 @@ void *xmmap(void *start, size_t length,
if (ret == MAP_FAILED) {
if (!length)
return NULL;
release_pack_memory(length, fd);
release_pack_memory(length);
ret = mmap(start, length, prot, flags, fd, offset);
if (ret == MAP_FAILED)
die_errno("Out of memory? mmap failed");
@ -682,6 +675,83 @@ void close_pack_windows(struct packed_git *p)
}
}
/*
* The LRU pack is the one with the oldest MRU window, preferring packs
* with no used windows, or the oldest mtime if it has no windows allocated.
*/
static void find_lru_pack(struct packed_git *p, struct packed_git **lru_p, struct pack_window **mru_w, int *accept_windows_inuse)
{
struct pack_window *w, *this_mru_w;
int has_windows_inuse = 0;
/*
* Reject this pack if it has windows and the previously selected
* one does not. If this pack does not have windows, reject
* it if the pack file is newer than the previously selected one.
*/
if (*lru_p && !*mru_w && (p->windows || p->mtime > (*lru_p)->mtime))
return;
for (w = this_mru_w = p->windows; w; w = w->next) {
/*
* Reject this pack if any of its windows are in use,
* but the previously selected pack did not have any
* inuse windows. Otherwise, record that this pack
* has windows in use.
*/
if (w->inuse_cnt) {
if (*accept_windows_inuse)
has_windows_inuse = 1;
else
return;
}
if (w->last_used > this_mru_w->last_used)
this_mru_w = w;
/*
* Reject this pack if it has windows that have been
* used more recently than the previously selected pack.
* If the previously selected pack had windows inuse and
* we have not encountered a window in this pack that is
* inuse, skip this check since we prefer a pack with no
* inuse windows to one that has inuse windows.
*/
if (*mru_w && *accept_windows_inuse == has_windows_inuse &&
this_mru_w->last_used > (*mru_w)->last_used)
return;
}
/*
* Select this pack.
*/
*mru_w = this_mru_w;
*lru_p = p;
*accept_windows_inuse = has_windows_inuse;
}
static int close_one_pack(void)
{
struct packed_git *p, *lru_p = NULL;
struct pack_window *mru_w = NULL;
int accept_windows_inuse = 1;
for (p = packed_git; p; p = p->next) {
if (p->pack_fd == -1)
continue;
find_lru_pack(p, &lru_p, &mru_w, &accept_windows_inuse);
}
if (lru_p) {
close(lru_p->pack_fd);
pack_open_fds--;
lru_p->pack_fd = -1;
return 1;
}
return 0;
}
void unuse_pack(struct pack_window **w_cursor)
{
struct pack_window *w = *w_cursor;
@ -777,7 +847,7 @@ static int open_packed_git_1(struct packed_git *p)
pack_max_fds = 1;
}
while (pack_max_fds <= pack_open_fds && unuse_one_window(NULL, -1))
while (pack_max_fds <= pack_open_fds && close_one_pack())
; /* nothing */
p->pack_fd = git_open_noatime(p->pack_name);
@ -893,7 +963,7 @@ unsigned char *use_pack(struct packed_git *p,
win->len = (size_t)len;
pack_mapped += win->len;
while (packed_git_limit < pack_mapped
&& unuse_one_window(p, p->pack_fd))
&& unuse_one_window(p))
; /* nothing */
win->base = xmmap(NULL, win->len,
PROT_READ, MAP_PRIVATE,
@ -939,7 +1009,7 @@ static struct packed_git *alloc_packed_git(int extra)
static void try_to_free_pack_memory(size_t size)
{
release_pack_memory(size, -1);
release_pack_memory(size);
}
struct packed_git *add_packed_git(const char *path, int path_len, int local)