@@ -24,14 +24,14 @@ char *sha1_pack_index_name(const unsigned char *sha1)
2424 return odb_pack_name (& buf , sha1 , "idx" );
2525}
2626
27- unsigned int pack_used_ctr ;
28- unsigned int pack_mmap_calls ;
29- unsigned int peak_pack_open_windows ;
30- unsigned int pack_open_windows ;
27+ static unsigned int pack_used_ctr ;
28+ static unsigned int pack_mmap_calls ;
29+ static unsigned int peak_pack_open_windows ;
30+ static unsigned int pack_open_windows ;
3131unsigned int pack_open_fds ;
32- unsigned int pack_max_fds ;
33- size_t peak_pack_mapped ;
34- size_t pack_mapped ;
32+ static unsigned int pack_max_fds ;
33+ static size_t peak_pack_mapped ;
34+ static size_t pack_mapped ;
3535struct packed_git * packed_git ;
3636
3737static struct mru packed_git_mru_storage ;
@@ -228,7 +228,7 @@ static void scan_windows(struct packed_git *p,
228228 }
229229}
230230
231- int unuse_one_window (struct packed_git * current )
231+ static int unuse_one_window (struct packed_git * current )
232232{
233233 struct packed_git * p , * lru_p = NULL ;
234234 struct pack_window * lru_w = NULL , * lru_l = NULL ;
@@ -274,7 +274,7 @@ void close_pack_windows(struct packed_git *p)
274274 }
275275}
276276
277- int close_pack_fd (struct packed_git * p )
277+ static int close_pack_fd (struct packed_git * p )
278278{
279279 if (p -> pack_fd < 0 )
280280 return 0 ;
@@ -311,3 +311,288 @@ void close_all_packs(void)
311311 else
312312 close_pack (p );
313313}
314+
315+ /*
316+ * The LRU pack is the one with the oldest MRU window, preferring packs
317+ * with no used windows, or the oldest mtime if it has no windows allocated.
318+ */
319+ static void find_lru_pack (struct packed_git * p , struct packed_git * * lru_p , struct pack_window * * mru_w , int * accept_windows_inuse )
320+ {
321+ struct pack_window * w , * this_mru_w ;
322+ int has_windows_inuse = 0 ;
323+
324+ /*
325+ * Reject this pack if it has windows and the previously selected
326+ * one does not. If this pack does not have windows, reject
327+ * it if the pack file is newer than the previously selected one.
328+ */
329+ if (* lru_p && !* mru_w && (p -> windows || p -> mtime > (* lru_p )-> mtime ))
330+ return ;
331+
332+ for (w = this_mru_w = p -> windows ; w ; w = w -> next ) {
333+ /*
334+ * Reject this pack if any of its windows are in use,
335+ * but the previously selected pack did not have any
336+ * inuse windows. Otherwise, record that this pack
337+ * has windows in use.
338+ */
339+ if (w -> inuse_cnt ) {
340+ if (* accept_windows_inuse )
341+ has_windows_inuse = 1 ;
342+ else
343+ return ;
344+ }
345+
346+ if (w -> last_used > this_mru_w -> last_used )
347+ this_mru_w = w ;
348+
349+ /*
350+ * Reject this pack if it has windows that have been
351+ * used more recently than the previously selected pack.
352+ * If the previously selected pack had windows inuse and
353+ * we have not encountered a window in this pack that is
354+ * inuse, skip this check since we prefer a pack with no
355+ * inuse windows to one that has inuse windows.
356+ */
357+ if (* mru_w && * accept_windows_inuse == has_windows_inuse &&
358+ this_mru_w -> last_used > (* mru_w )-> last_used )
359+ return ;
360+ }
361+
362+ /*
363+ * Select this pack.
364+ */
365+ * mru_w = this_mru_w ;
366+ * lru_p = p ;
367+ * accept_windows_inuse = has_windows_inuse ;
368+ }
369+
370+ static int close_one_pack (void )
371+ {
372+ struct packed_git * p , * lru_p = NULL ;
373+ struct pack_window * mru_w = NULL ;
374+ int accept_windows_inuse = 1 ;
375+
376+ for (p = packed_git ; p ; p = p -> next ) {
377+ if (p -> pack_fd == -1 )
378+ continue ;
379+ find_lru_pack (p , & lru_p , & mru_w , & accept_windows_inuse );
380+ }
381+
382+ if (lru_p )
383+ return close_pack_fd (lru_p );
384+
385+ return 0 ;
386+ }
387+
388+ static unsigned int get_max_fd_limit (void )
389+ {
390+ #ifdef RLIMIT_NOFILE
391+ {
392+ struct rlimit lim ;
393+
394+ if (!getrlimit (RLIMIT_NOFILE , & lim ))
395+ return lim .rlim_cur ;
396+ }
397+ #endif
398+
399+ #ifdef _SC_OPEN_MAX
400+ {
401+ long open_max = sysconf (_SC_OPEN_MAX );
402+ if (0 < open_max )
403+ return open_max ;
404+ /*
405+ * Otherwise, we got -1 for one of the two
406+ * reasons:
407+ *
408+ * (1) sysconf() did not understand _SC_OPEN_MAX
409+ * and signaled an error with -1; or
410+ * (2) sysconf() said there is no limit.
411+ *
412+ * We _could_ clear errno before calling sysconf() to
413+ * tell these two cases apart and return a huge number
414+ * in the latter case to let the caller cap it to a
415+ * value that is not so selfish, but letting the
416+ * fallback OPEN_MAX codepath take care of these cases
417+ * is a lot simpler.
418+ */
419+ }
420+ #endif
421+
422+ #ifdef OPEN_MAX
423+ return OPEN_MAX ;
424+ #else
425+ return 1 ; /* see the caller ;-) */
426+ #endif
427+ }
428+
429+ /*
430+ * Do not call this directly as this leaks p->pack_fd on error return;
431+ * call open_packed_git() instead.
432+ */
433+ static int open_packed_git_1 (struct packed_git * p )
434+ {
435+ struct stat st ;
436+ struct pack_header hdr ;
437+ unsigned char sha1 [20 ];
438+ unsigned char * idx_sha1 ;
439+ long fd_flag ;
440+
441+ if (!p -> index_data && open_pack_index (p ))
442+ return error ("packfile %s index unavailable" , p -> pack_name );
443+
444+ if (!pack_max_fds ) {
445+ unsigned int max_fds = get_max_fd_limit ();
446+
447+ /* Save 3 for stdin/stdout/stderr, 22 for work */
448+ if (25 < max_fds )
449+ pack_max_fds = max_fds - 25 ;
450+ else
451+ pack_max_fds = 1 ;
452+ }
453+
454+ while (pack_max_fds <= pack_open_fds && close_one_pack ())
455+ ; /* nothing */
456+
457+ p -> pack_fd = git_open (p -> pack_name );
458+ if (p -> pack_fd < 0 || fstat (p -> pack_fd , & st ))
459+ return -1 ;
460+ pack_open_fds ++ ;
461+
462+ /* If we created the struct before we had the pack we lack size. */
463+ if (!p -> pack_size ) {
464+ if (!S_ISREG (st .st_mode ))
465+ return error ("packfile %s not a regular file" , p -> pack_name );
466+ p -> pack_size = st .st_size ;
467+ } else if (p -> pack_size != st .st_size )
468+ return error ("packfile %s size changed" , p -> pack_name );
469+
470+ /* We leave these file descriptors open with sliding mmap;
471+ * there is no point keeping them open across exec(), though.
472+ */
473+ fd_flag = fcntl (p -> pack_fd , F_GETFD , 0 );
474+ if (fd_flag < 0 )
475+ return error ("cannot determine file descriptor flags" );
476+ fd_flag |= FD_CLOEXEC ;
477+ if (fcntl (p -> pack_fd , F_SETFD , fd_flag ) == -1 )
478+ return error ("cannot set FD_CLOEXEC" );
479+
480+ /* Verify we recognize this pack file format. */
481+ if (read_in_full (p -> pack_fd , & hdr , sizeof (hdr )) != sizeof (hdr ))
482+ return error ("file %s is far too short to be a packfile" , p -> pack_name );
483+ if (hdr .hdr_signature != htonl (PACK_SIGNATURE ))
484+ return error ("file %s is not a GIT packfile" , p -> pack_name );
485+ if (!pack_version_ok (hdr .hdr_version ))
486+ return error ("packfile %s is version %" PRIu32 " and not"
487+ " supported (try upgrading GIT to a newer version)" ,
488+ p -> pack_name , ntohl (hdr .hdr_version ));
489+
490+ /* Verify the pack matches its index. */
491+ if (p -> num_objects != ntohl (hdr .hdr_entries ))
492+ return error ("packfile %s claims to have %" PRIu32 " objects"
493+ " while index indicates %" PRIu32 " objects" ,
494+ p -> pack_name , ntohl (hdr .hdr_entries ),
495+ p -> num_objects );
496+ if (lseek (p -> pack_fd , p -> pack_size - sizeof (sha1 ), SEEK_SET ) == -1 )
497+ return error ("end of packfile %s is unavailable" , p -> pack_name );
498+ if (read_in_full (p -> pack_fd , sha1 , sizeof (sha1 )) != sizeof (sha1 ))
499+ return error ("packfile %s signature is unavailable" , p -> pack_name );
500+ idx_sha1 = ((unsigned char * )p -> index_data ) + p -> index_size - 40 ;
501+ if (hashcmp (sha1 , idx_sha1 ))
502+ return error ("packfile %s does not match index" , p -> pack_name );
503+ return 0 ;
504+ }
505+
506+ int open_packed_git (struct packed_git * p )
507+ {
508+ if (!open_packed_git_1 (p ))
509+ return 0 ;
510+ close_pack_fd (p );
511+ return -1 ;
512+ }
513+
514+ static int in_window (struct pack_window * win , off_t offset )
515+ {
516+ /* We must promise at least 20 bytes (one hash) after the
517+ * offset is available from this window, otherwise the offset
518+ * is not actually in this window and a different window (which
519+ * has that one hash excess) must be used. This is to support
520+ * the object header and delta base parsing routines below.
521+ */
522+ off_t win_off = win -> offset ;
523+ return win_off <= offset
524+ && (offset + 20 ) <= (win_off + win -> len );
525+ }
526+
527+ unsigned char * use_pack (struct packed_git * p ,
528+ struct pack_window * * w_cursor ,
529+ off_t offset ,
530+ unsigned long * left )
531+ {
532+ struct pack_window * win = * w_cursor ;
533+
534+ /* Since packfiles end in a hash of their content and it's
535+ * pointless to ask for an offset into the middle of that
536+ * hash, and the in_window function above wouldn't match
537+ * don't allow an offset too close to the end of the file.
538+ */
539+ if (!p -> pack_size && p -> pack_fd == -1 && open_packed_git (p ))
540+ die ("packfile %s cannot be accessed" , p -> pack_name );
541+ if (offset > (p -> pack_size - 20 ))
542+ die ("offset beyond end of packfile (truncated pack?)" );
543+ if (offset < 0 )
544+ die (_ ("offset before end of packfile (broken .idx?)" ));
545+
546+ if (!win || !in_window (win , offset )) {
547+ if (win )
548+ win -> inuse_cnt -- ;
549+ for (win = p -> windows ; win ; win = win -> next ) {
550+ if (in_window (win , offset ))
551+ break ;
552+ }
553+ if (!win ) {
554+ size_t window_align = packed_git_window_size / 2 ;
555+ off_t len ;
556+
557+ if (p -> pack_fd == -1 && open_packed_git (p ))
558+ die ("packfile %s cannot be accessed" , p -> pack_name );
559+
560+ win = xcalloc (1 , sizeof (* win ));
561+ win -> offset = (offset / window_align ) * window_align ;
562+ len = p -> pack_size - win -> offset ;
563+ if (len > packed_git_window_size )
564+ len = packed_git_window_size ;
565+ win -> len = (size_t )len ;
566+ pack_mapped += win -> len ;
567+ while (packed_git_limit < pack_mapped
568+ && unuse_one_window (p ))
569+ ; /* nothing */
570+ win -> base = xmmap (NULL , win -> len ,
571+ PROT_READ , MAP_PRIVATE ,
572+ p -> pack_fd , win -> offset );
573+ if (win -> base == MAP_FAILED )
574+ die_errno ("packfile %s cannot be mapped" ,
575+ p -> pack_name );
576+ if (!win -> offset && win -> len == p -> pack_size
577+ && !p -> do_not_close )
578+ close_pack_fd (p );
579+ pack_mmap_calls ++ ;
580+ pack_open_windows ++ ;
581+ if (pack_mapped > peak_pack_mapped )
582+ peak_pack_mapped = pack_mapped ;
583+ if (pack_open_windows > peak_pack_open_windows )
584+ peak_pack_open_windows = pack_open_windows ;
585+ win -> next = p -> windows ;
586+ p -> windows = win ;
587+ }
588+ }
589+ if (win != * w_cursor ) {
590+ win -> last_used = pack_used_ctr ++ ;
591+ win -> inuse_cnt ++ ;
592+ * w_cursor = win ;
593+ }
594+ offset -= win -> offset ;
595+ if (left )
596+ * left = win -> len - xsize_t (offset );
597+ return win -> base + offset ;
598+ }
0 commit comments