Skip to content

Commit 04fbba0

Browse files
committed
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
2 parents 9a7eaad + 7c3ecb3 commit 04fbba0

File tree

3 files changed

+87
-17
lines changed

3 files changed

+87
-17
lines changed

builtin/pack-objects.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1809,7 +1809,7 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
18091809
static void try_to_free_from_threads(size_t size)
18101810
{
18111811
read_lock();
1812-
release_pack_memory(size, -1);
1812+
release_pack_memory(size);
18131813
read_unlock();
18141814
}
18151815

git-compat-util.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ int inet_pton(int af, const char *src, void *dst);
524524
const char *inet_ntop(int af, const void *src, char *dst, size_t size);
525525
#endif
526526

527-
extern void release_pack_memory(size_t, int);
527+
extern void release_pack_memory(size_t);
528528

529529
typedef void (*try_to_free_t)(size_t);
530530
extern try_to_free_t set_try_to_free_routine(try_to_free_t);

sha1_file.c

Lines changed: 85 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ static void scan_windows(struct packed_git *p,
614614
}
615615
}
616616

617-
static int unuse_one_window(struct packed_git *current, int keep_fd)
617+
static int unuse_one_window(struct packed_git *current)
618618
{
619619
struct packed_git *p, *lru_p = NULL;
620620
struct pack_window *lru_w = NULL, *lru_l = NULL;
@@ -628,26 +628,19 @@ static int unuse_one_window(struct packed_git *current, int keep_fd)
628628
pack_mapped -= lru_w->len;
629629
if (lru_l)
630630
lru_l->next = lru_w->next;
631-
else {
631+
else
632632
lru_p->windows = lru_w->next;
633-
if (!lru_p->windows && lru_p->pack_fd != -1
634-
&& lru_p->pack_fd != keep_fd) {
635-
close(lru_p->pack_fd);
636-
pack_open_fds--;
637-
lru_p->pack_fd = -1;
638-
}
639-
}
640633
free(lru_w);
641634
pack_open_windows--;
642635
return 1;
643636
}
644637
return 0;
645638
}
646639

647-
void release_pack_memory(size_t need, int fd)
640+
void release_pack_memory(size_t need)
648641
{
649642
size_t cur = pack_mapped;
650-
while (need >= (cur - pack_mapped) && unuse_one_window(NULL, fd))
643+
while (need >= (cur - pack_mapped) && unuse_one_window(NULL))
651644
; /* nothing */
652645
}
653646

@@ -658,7 +651,7 @@ void *xmmap(void *start, size_t length,
658651
if (ret == MAP_FAILED) {
659652
if (!length)
660653
return NULL;
661-
release_pack_memory(length, fd);
654+
release_pack_memory(length);
662655
ret = mmap(start, length, prot, flags, fd, offset);
663656
if (ret == MAP_FAILED)
664657
die_errno("Out of memory? mmap failed");
@@ -682,6 +675,83 @@ void close_pack_windows(struct packed_git *p)
682675
}
683676
}
684677

678+
/*
679+
* The LRU pack is the one with the oldest MRU window, preferring packs
680+
* with no used windows, or the oldest mtime if it has no windows allocated.
681+
*/
682+
static void find_lru_pack(struct packed_git *p, struct packed_git **lru_p, struct pack_window **mru_w, int *accept_windows_inuse)
683+
{
684+
struct pack_window *w, *this_mru_w;
685+
int has_windows_inuse = 0;
686+
687+
/*
688+
* Reject this pack if it has windows and the previously selected
689+
* one does not. If this pack does not have windows, reject
690+
* it if the pack file is newer than the previously selected one.
691+
*/
692+
if (*lru_p && !*mru_w && (p->windows || p->mtime > (*lru_p)->mtime))
693+
return;
694+
695+
for (w = this_mru_w = p->windows; w; w = w->next) {
696+
/*
697+
* Reject this pack if any of its windows are in use,
698+
* but the previously selected pack did not have any
699+
* inuse windows. Otherwise, record that this pack
700+
* has windows in use.
701+
*/
702+
if (w->inuse_cnt) {
703+
if (*accept_windows_inuse)
704+
has_windows_inuse = 1;
705+
else
706+
return;
707+
}
708+
709+
if (w->last_used > this_mru_w->last_used)
710+
this_mru_w = w;
711+
712+
/*
713+
* Reject this pack if it has windows that have been
714+
* used more recently than the previously selected pack.
715+
* If the previously selected pack had windows inuse and
716+
* we have not encountered a window in this pack that is
717+
* inuse, skip this check since we prefer a pack with no
718+
* inuse windows to one that has inuse windows.
719+
*/
720+
if (*mru_w && *accept_windows_inuse == has_windows_inuse &&
721+
this_mru_w->last_used > (*mru_w)->last_used)
722+
return;
723+
}
724+
725+
/*
726+
* Select this pack.
727+
*/
728+
*mru_w = this_mru_w;
729+
*lru_p = p;
730+
*accept_windows_inuse = has_windows_inuse;
731+
}
732+
733+
static int close_one_pack(void)
734+
{
735+
struct packed_git *p, *lru_p = NULL;
736+
struct pack_window *mru_w = NULL;
737+
int accept_windows_inuse = 1;
738+
739+
for (p = packed_git; p; p = p->next) {
740+
if (p->pack_fd == -1)
741+
continue;
742+
find_lru_pack(p, &lru_p, &mru_w, &accept_windows_inuse);
743+
}
744+
745+
if (lru_p) {
746+
close(lru_p->pack_fd);
747+
pack_open_fds--;
748+
lru_p->pack_fd = -1;
749+
return 1;
750+
}
751+
752+
return 0;
753+
}
754+
685755
void unuse_pack(struct pack_window **w_cursor)
686756
{
687757
struct pack_window *w = *w_cursor;
@@ -777,7 +847,7 @@ static int open_packed_git_1(struct packed_git *p)
777847
pack_max_fds = 1;
778848
}
779849

780-
while (pack_max_fds <= pack_open_fds && unuse_one_window(NULL, -1))
850+
while (pack_max_fds <= pack_open_fds && close_one_pack())
781851
; /* nothing */
782852

783853
p->pack_fd = git_open_noatime(p->pack_name);
@@ -893,7 +963,7 @@ unsigned char *use_pack(struct packed_git *p,
893963
win->len = (size_t)len;
894964
pack_mapped += win->len;
895965
while (packed_git_limit < pack_mapped
896-
&& unuse_one_window(p, p->pack_fd))
966+
&& unuse_one_window(p))
897967
; /* nothing */
898968
win->base = xmmap(NULL, win->len,
899969
PROT_READ, MAP_PRIVATE,
@@ -939,7 +1009,7 @@ static struct packed_git *alloc_packed_git(int extra)
9391009

9401010
static void try_to_free_pack_memory(size_t size)
9411011
{
942-
release_pack_memory(size, -1);
1012+
release_pack_memory(size);
9431013
}
9441014

9451015
struct packed_git *add_packed_git(const char *path, int path_len, int local)

0 commit comments

Comments
 (0)