@@ -614,7 +614,7 @@ static void scan_windows(struct packed_git *p,
614
614
}
615
615
}
616
616
617
- static int unuse_one_window (struct packed_git * current , int keep_fd )
617
+ static int unuse_one_window (struct packed_git * current )
618
618
{
619
619
struct packed_git * p , * lru_p = NULL ;
620
620
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)
628
628
pack_mapped -= lru_w -> len ;
629
629
if (lru_l )
630
630
lru_l -> next = lru_w -> next ;
631
- else {
631
+ else
632
632
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
- }
640
633
free (lru_w );
641
634
pack_open_windows -- ;
642
635
return 1 ;
643
636
}
644
637
return 0 ;
645
638
}
646
639
647
- void release_pack_memory (size_t need , int fd )
640
+ void release_pack_memory (size_t need )
648
641
{
649
642
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 ))
651
644
; /* nothing */
652
645
}
653
646
@@ -658,7 +651,7 @@ void *xmmap(void *start, size_t length,
658
651
if (ret == MAP_FAILED ) {
659
652
if (!length )
660
653
return NULL ;
661
- release_pack_memory (length , fd );
654
+ release_pack_memory (length );
662
655
ret = mmap (start , length , prot , flags , fd , offset );
663
656
if (ret == MAP_FAILED )
664
657
die_errno ("Out of memory? mmap failed" );
@@ -682,6 +675,83 @@ void close_pack_windows(struct packed_git *p)
682
675
}
683
676
}
684
677
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
+
685
755
void unuse_pack (struct pack_window * * w_cursor )
686
756
{
687
757
struct pack_window * w = * w_cursor ;
@@ -777,7 +847,7 @@ static int open_packed_git_1(struct packed_git *p)
777
847
pack_max_fds = 1 ;
778
848
}
779
849
780
- while (pack_max_fds <= pack_open_fds && unuse_one_window ( NULL , -1 ))
850
+ while (pack_max_fds <= pack_open_fds && close_one_pack ( ))
781
851
; /* nothing */
782
852
783
853
p -> pack_fd = git_open_noatime (p -> pack_name );
@@ -893,7 +963,7 @@ unsigned char *use_pack(struct packed_git *p,
893
963
win -> len = (size_t )len ;
894
964
pack_mapped += win -> len ;
895
965
while (packed_git_limit < pack_mapped
896
- && unuse_one_window (p , p -> pack_fd ))
966
+ && unuse_one_window (p ))
897
967
; /* nothing */
898
968
win -> base = xmmap (NULL , win -> len ,
899
969
PROT_READ , MAP_PRIVATE ,
@@ -939,7 +1009,7 @@ static struct packed_git *alloc_packed_git(int extra)
939
1009
940
1010
static void try_to_free_pack_memory (size_t size )
941
1011
{
942
- release_pack_memory (size , -1 );
1012
+ release_pack_memory (size );
943
1013
}
944
1014
945
1015
struct packed_git * add_packed_git (const char * path , int path_len , int local )
0 commit comments