2222#define DEFAULT_MAPPED_LIMIT \
2323 ((1024 * 1024) * (sizeof(void*) >= 8 ? 8192ULL : 256UL))
2424
25- /* default ulimit -n on macOS is just 256 */
26- #define DEFAULT_FILE_LIMIT 128
25+ /* default is unlimited */
26+ #define DEFAULT_FILE_LIMIT 0
2727
2828size_t git_mwindow__window_size = DEFAULT_WINDOW_SIZE ;
2929size_t git_mwindow__mapped_limit = DEFAULT_MAPPED_LIMIT ;
3030size_t git_mwindow__file_limit = DEFAULT_FILE_LIMIT ;
3131
3232/* Whenever you want to read or modify this, grab git__mwindow_mutex */
33- static git_mwindow_ctl mem_ctl ;
33+ git_mwindow_ctl git_mwindow__mem_ctl ;
3434
3535/* Global list of mwindow files, to open packs once across repos */
3636git_strmap * git__pack_cache = NULL ;
@@ -136,7 +136,7 @@ void git_mwindow_free_all(git_mwindow_file *mwf)
136136 */
137137void git_mwindow_free_all_locked (git_mwindow_file * mwf )
138138{
139- git_mwindow_ctl * ctl = & mem_ctl ;
139+ git_mwindow_ctl * ctl = & git_mwindow__mem_ctl ;
140140 size_t i ;
141141
142142 /*
@@ -178,94 +178,131 @@ int git_mwindow_contains(git_mwindow *win, off64_t offset)
178178 && offset <= (off64_t )(win_off + win -> window_map .len );
179179}
180180
181+ #define GIT_MWINDOW__LRU -1
182+ #define GIT_MWINDOW__MRU 1
183+
181184/*
182- * Find the least-recently-used window in a file
185+ * Find the least- or most-recently-used window in a file that is not currently
186+ * being used. The 'only_unused' flag controls whether the caller requires the
187+ * file to only have unused windows.
188+ *
189+ * Returns whether such a window was found in the file.
183190 */
184- static void git_mwindow_scan_lru (
185- git_mwindow_file * mwf ,
186- git_mwindow * * lru_w ,
187- git_mwindow * * lru_l )
191+ static bool git_mwindow_scan_recently_used (
192+ git_mwindow_file * mwf ,
193+ git_mwindow * * out_window ,
194+ git_mwindow * * out_last ,
195+ bool only_unused ,
196+ int comparison_sign )
188197{
189- git_mwindow * w , * w_l ;
190-
191- for (w_l = NULL , w = mwf -> windows ; w ; w = w -> next ) {
192- if (!w -> inuse_cnt ) {
193- /*
194- * If the current one is more recent than the last one,
195- * store it in the output parameter. If lru_w is NULL,
196- * it's the first loop, so store it as well.
197- */
198- if (!* lru_w || w -> last_used < (* lru_w )-> last_used ) {
199- * lru_w = w ;
200- * lru_l = w_l ;
201- }
198+ git_mwindow * w , * w_last ;
199+ git_mwindow * lru_window = NULL , * lru_last = NULL ;
200+
201+ assert (mwf );
202+ assert (out_window );
203+
204+ lru_window = * out_window ;
205+ if (out_last )
206+ lru_last = * out_last ;
207+
208+ for (w_last = NULL , w = mwf -> windows ; w ; w_last = w , w = w -> next ) {
209+ if (w -> inuse_cnt ) {
210+ if (only_unused )
211+ return false;
212+ /* This window is currently being used. Skip it. */
213+ continue ;
214+ }
215+
216+ /*
217+ * If the current one is more (or less) recent than the last one,
218+ * store it in the output parameter. If lru_window is NULL,
219+ * it's the first loop, so store it as well.
220+ */
221+ if (!lru_window ||
222+ (comparison_sign == GIT_MWINDOW__LRU && lru_window -> last_used > w -> last_used ) ||
223+ (comparison_sign == GIT_MWINDOW__MRU && lru_window -> last_used < w -> last_used )) {
224+ lru_window = w ;
225+ lru_last = w_last ;
202226 }
203- w_l = w ;
204227 }
228+
229+ if (!lru_window && !lru_last )
230+ return false;
231+
232+ * out_window = lru_window ;
233+ if (out_last )
234+ * out_last = lru_last ;
235+ return true;
205236}
206237
207238/*
208- * Close the least recently used window. Called under lock from new_window.
239+ * Close the least recently used window (that is currently not being used) out
240+ * of all the files. Called under lock from new_window.
209241 */
210242static int git_mwindow_close_lru_window (void )
211243{
212- git_mwindow_ctl * ctl = & mem_ctl ;
244+ git_mwindow_ctl * ctl = & git_mwindow__mem_ctl ;
213245 git_mwindow_file * cur ;
214246 size_t i ;
215- git_mwindow * lru_w = NULL , * lru_l = NULL , * * list = NULL ;
247+ git_mwindow * lru_window = NULL , * lru_last = NULL , * * list = NULL ;
216248
217249 git_vector_foreach (& ctl -> windowfiles , i , cur ) {
218- git_mwindow * last = lru_w ;
219- git_mwindow_scan_lru (cur , & lru_w , & lru_l );
220- if (lru_w != last )
250+ if (git_mwindow_scan_recently_used (
251+ cur , & lru_window , & lru_last , false, GIT_MWINDOW__LRU )) {
221252 list = & cur -> windows ;
253+ }
222254 }
223255
224- if (!lru_w ) {
256+ if (!lru_window ) {
225257 git_error_set (GIT_ERROR_OS , "failed to close memory window; couldn't find LRU" );
226258 return -1 ;
227259 }
228260
229- ctl -> mapped -= lru_w -> window_map .len ;
230- git_futils_mmap_free (& lru_w -> window_map );
261+ ctl -> mapped -= lru_window -> window_map .len ;
262+ git_futils_mmap_free (& lru_window -> window_map );
231263
232- if (lru_l )
233- lru_l -> next = lru_w -> next ;
264+ if (lru_last )
265+ lru_last -> next = lru_window -> next ;
234266 else
235- * list = lru_w -> next ;
267+ * list = lru_window -> next ;
236268
237- git__free (lru_w );
269+ git__free (lru_window );
238270 ctl -> open_windows -- ;
239271
240272 return 0 ;
241273}
242274
243275/*
244- * Close the file that contains the least recently used window. Called under
245- * lock from new_window.
276+ * Close the file that does not have any open windows AND contains the
277+ * least-recently-used most-recently-used window.
278+ *
279+ * Called under lock from new_window.
246280 */
247281static int git_mwindow_close_lru_file (void )
248282{
249- git_mwindow_ctl * ctl = & mem_ctl ;
250- git_mwindow_file * lru_f = NULL , * cur ;
283+ git_mwindow_ctl * ctl = & git_mwindow__mem_ctl ;
284+ git_mwindow_file * lru_file = NULL , * current_file = NULL ;
285+ git_mwindow * lru_window = NULL ;
251286 size_t i ;
252- git_mwindow * lru_w = NULL , * lru_l = NULL ;
253287
254- git_vector_foreach (& ctl -> windowfiles , i , cur ) {
255- git_mwindow * last = lru_w ;
256- git_mwindow_scan_lru (cur , & lru_w , & lru_l );
257- if (lru_w != last )
258- lru_f = cur ;
288+ git_vector_foreach (& ctl -> windowfiles , i , current_file ) {
289+ git_mwindow * mru_window = NULL ;
290+ if (!git_mwindow_scan_recently_used (
291+ current_file , & mru_window , NULL , true, GIT_MWINDOW__MRU )) {
292+ continue ;
293+ }
294+ if (!lru_window || lru_window -> last_used > mru_window -> last_used )
295+ lru_file = current_file ;
259296 }
260297
261- if (!lru_f ) {
298+ if (!lru_file ) {
262299 git_error_set (GIT_ERROR_OS , "failed to close memory window file; couldn't find LRU" );
263300 return -1 ;
264301 }
265302
266- git_mwindow_free_all_locked (lru_f );
267- p_close (lru_f -> fd );
268- lru_f -> fd = -1 ;
303+ git_mwindow_free_all_locked (lru_file );
304+ p_close (lru_file -> fd );
305+ lru_file -> fd = -1 ;
269306
270307 return 0 ;
271308}
@@ -276,7 +313,7 @@ static git_mwindow *new_window(
276313 off64_t size ,
277314 off64_t offset )
278315{
279- git_mwindow_ctl * ctl = & mem_ctl ;
316+ git_mwindow_ctl * ctl = & git_mwindow__mem_ctl ;
280317 size_t walign = git_mwindow__window_size / 2 ;
281318 off64_t len ;
282319 git_mwindow * w ;
@@ -342,7 +379,7 @@ unsigned char *git_mwindow_open(
342379 size_t extra ,
343380 unsigned int * left )
344381{
345- git_mwindow_ctl * ctl = & mem_ctl ;
382+ git_mwindow_ctl * ctl = & git_mwindow__mem_ctl ;
346383 git_mwindow * w = * cursor ;
347384
348385 if (git_mutex_lock (& git__mwindow_mutex )) {
@@ -394,7 +431,7 @@ unsigned char *git_mwindow_open(
394431
395432int git_mwindow_file_register (git_mwindow_file * mwf )
396433{
397- git_mwindow_ctl * ctl = & mem_ctl ;
434+ git_mwindow_ctl * ctl = & git_mwindow__mem_ctl ;
398435 int ret ;
399436
400437 if (git_mutex_lock (& git__mwindow_mutex )) {
@@ -408,8 +445,10 @@ int git_mwindow_file_register(git_mwindow_file *mwf)
408445 return -1 ;
409446 }
410447
411- while (git_mwindow__file_limit <= ctl -> windowfiles .length &&
412- git_mwindow_close_lru_file () == 0 ) /* nop */ ;
448+ if (git_mwindow__file_limit ) {
449+ while (git_mwindow__file_limit <= ctl -> windowfiles .length &&
450+ git_mwindow_close_lru_file () == 0 ) /* nop */ ;
451+ }
413452
414453 ret = git_vector_insert (& ctl -> windowfiles , mwf );
415454 git_mutex_unlock (& git__mwindow_mutex );
@@ -419,7 +458,7 @@ int git_mwindow_file_register(git_mwindow_file *mwf)
419458
420459void git_mwindow_file_deregister (git_mwindow_file * mwf )
421460{
422- git_mwindow_ctl * ctl = & mem_ctl ;
461+ git_mwindow_ctl * ctl = & git_mwindow__mem_ctl ;
423462 git_mwindow_file * cur ;
424463 size_t i ;
425464
0 commit comments