77#include "../iterator.h"
88#include "../lockfile.h"
99
10+ enum mmap_strategy {
11+ /*
12+ * Don't use mmap() at all for reading `packed-refs`.
13+ */
14+ MMAP_NONE ,
15+
16+ /*
17+ * Can use mmap() for reading `packed-refs`, but the file must
18+ * not remain mmapped. This is the usual option on Windows,
19+ * where you cannot rename a new version of a file onto a file
20+ * that is currently mmapped.
21+ */
22+ MMAP_TEMPORARY ,
23+
24+ /*
25+ * It is OK to leave the `packed-refs` file mmapped while
26+ * arbitrary other code is running.
27+ */
28+ MMAP_OK
29+ };
30+
31+ #if defined(NO_MMAP )
32+ static enum mmap_strategy mmap_strategy = MMAP_NONE ;
33+ #elif defined(MMAP_PREVENTS_DELETE )
34+ static enum mmap_strategy mmap_strategy = MMAP_TEMPORARY ;
35+ #else
36+ static enum mmap_strategy mmap_strategy = MMAP_OK ;
37+ #endif
38+
1039struct packed_ref_store ;
1140
1241struct packed_ref_cache {
@@ -18,6 +47,21 @@ struct packed_ref_cache {
1847
1948 struct ref_cache * cache ;
2049
50+ /* Is the `packed-refs` file currently mmapped? */
51+ int mmapped ;
52+
53+ /*
54+ * The contents of the `packed-refs` file. If the file is
55+ * mmapped, this points at the mmapped contents of the file.
56+ * If not, this points at heap-allocated memory containing the
57+ * contents. If there were no contents (e.g., because the file
58+ * didn't exist), `buf` and `eof` are both NULL.
59+ */
60+ char * buf , * eof ;
61+
62+ /* The size of the header line, if any; otherwise, 0: */
63+ size_t header_len ;
64+
2165 /*
2266 * What is the peeled state of this cache? (This is usually
2367 * determined from the header of the "packed-refs" file.)
@@ -76,6 +120,26 @@ static void acquire_packed_ref_cache(struct packed_ref_cache *packed_refs)
76120 packed_refs -> referrers ++ ;
77121}
78122
123+ /*
124+ * If the buffer in `packed_refs` is active, then either munmap the
125+ * memory and close the file, or free the memory. Then set the buffer
126+ * pointers to NULL.
127+ */
128+ static void release_packed_ref_buffer (struct packed_ref_cache * packed_refs )
129+ {
130+ if (packed_refs -> mmapped ) {
131+ if (munmap (packed_refs -> buf ,
132+ packed_refs -> eof - packed_refs -> buf ))
133+ die_errno ("error ummapping packed-refs file %s" ,
134+ packed_refs -> refs -> path );
135+ packed_refs -> mmapped = 0 ;
136+ } else {
137+ free (packed_refs -> buf );
138+ }
139+ packed_refs -> buf = packed_refs -> eof = NULL ;
140+ packed_refs -> header_len = 0 ;
141+ }
142+
79143/*
80144 * Decrease the reference count of *packed_refs. If it goes to zero,
81145 * free *packed_refs and return true; otherwise return false.
@@ -85,6 +149,7 @@ static int release_packed_ref_cache(struct packed_ref_cache *packed_refs)
85149 if (!-- packed_refs -> referrers ) {
86150 free_ref_cache (packed_refs -> cache );
87151 stat_validity_clear (& packed_refs -> validity );
152+ release_packed_ref_buffer (packed_refs );
88153 free (packed_refs );
89154 return 1 ;
90155 } else {
@@ -284,13 +349,15 @@ static struct ref_iterator_vtable mmapped_ref_iterator_vtable = {
284349};
285350
286351struct ref_iterator * mmapped_ref_iterator_begin (
287- const char * packed_refs_file ,
288352 struct packed_ref_cache * packed_refs ,
289353 const char * pos , const char * eof )
290354{
291355 struct mmapped_ref_iterator * iter = xcalloc (1 , sizeof (* iter ));
292356 struct ref_iterator * ref_iterator = & iter -> base ;
293357
358+ if (!packed_refs -> buf )
359+ return empty_ref_iterator_begin ();
360+
294361 base_ref_iterator_init (ref_iterator , & mmapped_ref_iterator_vtable , 0 );
295362
296363 iter -> packed_refs = packed_refs ;
@@ -304,6 +371,62 @@ struct ref_iterator *mmapped_ref_iterator_begin(
304371 return ref_iterator ;
305372}
306373
374+ /*
375+ * Depending on `mmap_strategy`, either mmap or read the contents of
376+ * the `packed-refs` file into the `packed_refs` instance. Return 1 if
377+ * the file existed and was read, or 0 if the file was absent. Die on
378+ * errors.
379+ */
380+ static int load_contents (struct packed_ref_cache * packed_refs )
381+ {
382+ int fd ;
383+ struct stat st ;
384+ size_t size ;
385+ ssize_t bytes_read ;
386+
387+ fd = open (packed_refs -> refs -> path , O_RDONLY );
388+ if (fd < 0 ) {
389+ if (errno == ENOENT ) {
390+ /*
391+ * This is OK; it just means that no
392+ * "packed-refs" file has been written yet,
393+ * which is equivalent to it being empty,
394+ * which is its state when initialized with
395+ * zeros.
396+ */
397+ return 0 ;
398+ } else {
399+ die_errno ("couldn't read %s" , packed_refs -> refs -> path );
400+ }
401+ }
402+
403+ stat_validity_update (& packed_refs -> validity , fd );
404+
405+ if (fstat (fd , & st ) < 0 )
406+ die_errno ("couldn't stat %s" , packed_refs -> refs -> path );
407+ size = xsize_t (st .st_size );
408+
409+ switch (mmap_strategy ) {
410+ case MMAP_NONE :
411+ case MMAP_TEMPORARY :
412+ packed_refs -> buf = xmalloc (size );
413+ bytes_read = read_in_full (fd , packed_refs -> buf , size );
414+ if (bytes_read < 0 || bytes_read != size )
415+ die_errno ("couldn't read %s" , packed_refs -> refs -> path );
416+ packed_refs -> eof = packed_refs -> buf + size ;
417+ packed_refs -> mmapped = 0 ;
418+ break ;
419+ case MMAP_OK :
420+ packed_refs -> buf = xmmap (NULL , size , PROT_READ , MAP_PRIVATE , fd , 0 );
421+ packed_refs -> eof = packed_refs -> buf + size ;
422+ packed_refs -> mmapped = 1 ;
423+ break ;
424+ }
425+ close (fd );
426+
427+ return 1 ;
428+ }
429+
307430/*
308431 * Read from the `packed-refs` file into a newly-allocated
309432 * `packed_ref_cache` and return it. The return value will already
@@ -336,11 +459,6 @@ struct ref_iterator *mmapped_ref_iterator_begin(
336459static struct packed_ref_cache * read_packed_refs (struct packed_ref_store * refs )
337460{
338461 struct packed_ref_cache * packed_refs = xcalloc (1 , sizeof (* packed_refs ));
339- int fd ;
340- struct stat st ;
341- size_t size ;
342- char * buf ;
343- const char * pos , * eof ;
344462 struct ref_dir * dir ;
345463 struct ref_iterator * iter ;
346464 int ok ;
@@ -351,45 +469,29 @@ static struct packed_ref_cache *read_packed_refs(struct packed_ref_store *refs)
351469 packed_refs -> cache -> root -> flag &= ~REF_INCOMPLETE ;
352470 packed_refs -> peeled = PEELED_NONE ;
353471
354- fd = open (refs -> path , O_RDONLY );
355- if (fd < 0 ) {
356- if (errno == ENOENT ) {
357- /*
358- * This is OK; it just means that no
359- * "packed-refs" file has been written yet,
360- * which is equivalent to it being empty.
361- */
362- return packed_refs ;
363- } else {
364- die_errno ("couldn't read %s" , refs -> path );
365- }
366- }
367-
368- stat_validity_update (& packed_refs -> validity , fd );
369-
370- if (fstat (fd , & st ) < 0 )
371- die_errno ("couldn't stat %s" , refs -> path );
372-
373- size = xsize_t (st .st_size );
374- buf = xmmap (NULL , size , PROT_READ , MAP_PRIVATE , fd , 0 );
375- pos = buf ;
376- eof = buf + size ;
472+ if (!load_contents (packed_refs ))
473+ return packed_refs ;
377474
378475 /* If the file has a header line, process it: */
379- if (pos < eof && * pos == '#' ) {
476+ if (packed_refs -> buf < packed_refs -> eof && * packed_refs -> buf == '#' ) {
380477 struct strbuf tmp = STRBUF_INIT ;
381478 char * p ;
382479 const char * eol ;
383480 struct string_list traits = STRING_LIST_INIT_NODUP ;
384481
385- eol = memchr (pos , '\n' , eof - pos );
482+ eol = memchr (packed_refs -> buf , '\n' ,
483+ packed_refs -> eof - packed_refs -> buf );
386484 if (!eol )
387- die_unterminated_line (refs -> path , pos , eof - pos );
485+ die_unterminated_line (refs -> path ,
486+ packed_refs -> buf ,
487+ packed_refs -> eof - packed_refs -> buf );
388488
389- strbuf_add (& tmp , pos , eol - pos );
489+ strbuf_add (& tmp , packed_refs -> buf , eol - packed_refs -> buf );
390490
391491 if (!skip_prefix (tmp .buf , "# pack-refs with:" , (const char * * )& p ))
392- die_invalid_line (refs -> path , pos , eof - pos );
492+ die_invalid_line (refs -> path ,
493+ packed_refs -> buf ,
494+ packed_refs -> eof - packed_refs -> buf );
393495
394496 string_list_split_in_place (& traits , p , ' ' , -1 );
395497
@@ -400,14 +502,17 @@ static struct packed_ref_cache *read_packed_refs(struct packed_ref_store *refs)
400502 /* perhaps other traits later as well */
401503
402504 /* The "+ 1" is for the LF character. */
403- pos = eol + 1 ;
505+ packed_refs -> header_len = eol + 1 - packed_refs -> buf ;
404506
405507 string_list_clear (& traits , 0 );
406508 strbuf_release (& tmp );
407509 }
408510
409511 dir = get_ref_dir (packed_refs -> cache -> root );
410- iter = mmapped_ref_iterator_begin (refs -> path , packed_refs , pos , eof );
512+ iter = mmapped_ref_iterator_begin (
513+ packed_refs ,
514+ packed_refs -> buf + packed_refs -> header_len ,
515+ packed_refs -> eof );
411516 while ((ok = ref_iterator_advance (iter )) == ITER_OK ) {
412517 struct ref_entry * entry =
413518 create_ref_entry (iter -> refname , iter -> oid , iter -> flags );
@@ -420,11 +525,6 @@ static struct packed_ref_cache *read_packed_refs(struct packed_ref_store *refs)
420525 if (ok != ITER_DONE )
421526 die ("error reading packed-refs file %s" , refs -> path );
422527
423- if (munmap (buf , size ))
424- die_errno ("error ummapping packed-refs file %s" , refs -> path );
425-
426- close (fd );
427-
428528 return packed_refs ;
429529}
430530
@@ -1031,14 +1131,15 @@ static int packed_transaction_finish(struct ref_store *ref_store,
10311131 int ret = TRANSACTION_GENERIC_ERROR ;
10321132 char * packed_refs_path ;
10331133
1134+ clear_packed_ref_cache (refs );
1135+
10341136 packed_refs_path = get_locked_file_path (& refs -> lock );
10351137 if (rename_tempfile (& refs -> tempfile , packed_refs_path )) {
10361138 strbuf_addf (err , "error replacing %s: %s" ,
10371139 refs -> path , strerror (errno ));
10381140 goto cleanup ;
10391141 }
10401142
1041- clear_packed_ref_cache (refs );
10421143 ret = 0 ;
10431144
10441145cleanup :
0 commit comments