Skip to content

Commit d8b48af

Browse files
committed
Merge branch 'sj/use-mmap-to-check-packed-refs'
The code path to access the "packed-refs" file while "fsck" is taught to mmap the file, instead of reading the whole file in the memory. * sj/use-mmap-to-check-packed-refs: packed-backend: mmap large "packed-refs" file during fsck packed-backend: extract snapshot allocation in `load_contents` packed-backend: fsck should warn when "packed-refs" file is empty
2 parents 3950f8f + 86ddd58 commit d8b48af

File tree

4 files changed

+67
-30
lines changed

4 files changed

+67
-30
lines changed

Documentation/fsck-msgids.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@
5959
`emptyName`::
6060
(WARN) A path contains an empty name.
6161

62+
`emptyPackedRefsFile`::
63+
(INFO) "packed-refs" file is empty. Report to the
64+
[email protected] mailing list if you see this error. As only
65+
very early versions of Git would create such an empty
66+
"packed_refs" file, we might tighten this rule in the future.
67+
6268
`extraHeaderEntry`::
6369
(IGNORE) Extra headers found after `tagger`.
6470

fsck.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ enum fsck_msg_type {
8484
FUNC(LARGE_PATHNAME, WARN) \
8585
/* infos (reported as warnings, but ignored by default) */ \
8686
FUNC(BAD_FILEMODE, INFO) \
87+
FUNC(EMPTY_PACKED_REFS_FILE, INFO) \
8788
FUNC(GITMODULES_PARSE, INFO) \
8889
FUNC(GITIGNORE_SYMLINK, INFO) \
8990
FUNC(GITATTRIBUTES_SYMLINK, INFO) \

refs/packed-backend.c

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,32 @@ static int refname_contains_nul(struct strbuf *refname)
517517

518518
#define SMALL_FILE_SIZE (32*1024)
519519

520+
static int allocate_snapshot_buffer(struct snapshot *snapshot, int fd, struct stat *st)
521+
{
522+
ssize_t bytes_read;
523+
size_t size;
524+
525+
size = xsize_t(st->st_size);
526+
if (!size)
527+
return 0;
528+
529+
if (mmap_strategy == MMAP_NONE || size <= SMALL_FILE_SIZE) {
530+
snapshot->buf = xmalloc(size);
531+
bytes_read = read_in_full(fd, snapshot->buf, size);
532+
if (bytes_read < 0 || bytes_read != size)
533+
die_errno("couldn't read %s", snapshot->refs->path);
534+
snapshot->mmapped = 0;
535+
} else {
536+
snapshot->buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
537+
snapshot->mmapped = 1;
538+
}
539+
540+
snapshot->start = snapshot->buf;
541+
snapshot->eof = snapshot->buf + size;
542+
543+
return 1;
544+
}
545+
520546
/*
521547
* Depending on `mmap_strategy`, either mmap or read the contents of
522548
* the `packed-refs` file into the snapshot. Return 1 if the file
@@ -525,10 +551,9 @@ static int refname_contains_nul(struct strbuf *refname)
525551
*/
526552
static int load_contents(struct snapshot *snapshot)
527553
{
528-
int fd;
529554
struct stat st;
530-
size_t size;
531-
ssize_t bytes_read;
555+
int ret;
556+
int fd;
532557

533558
fd = open(snapshot->refs->path, O_RDONLY);
534559
if (fd < 0) {
@@ -550,27 +575,11 @@ static int load_contents(struct snapshot *snapshot)
550575

551576
if (fstat(fd, &st) < 0)
552577
die_errno("couldn't stat %s", snapshot->refs->path);
553-
size = xsize_t(st.st_size);
554-
555-
if (!size) {
556-
close(fd);
557-
return 0;
558-
} else if (mmap_strategy == MMAP_NONE || size <= SMALL_FILE_SIZE) {
559-
snapshot->buf = xmalloc(size);
560-
bytes_read = read_in_full(fd, snapshot->buf, size);
561-
if (bytes_read < 0 || bytes_read != size)
562-
die_errno("couldn't read %s", snapshot->refs->path);
563-
snapshot->mmapped = 0;
564-
} else {
565-
snapshot->buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
566-
snapshot->mmapped = 1;
567-
}
568-
close(fd);
569578

570-
snapshot->start = snapshot->buf;
571-
snapshot->eof = snapshot->buf + size;
579+
ret = allocate_snapshot_buffer(snapshot, fd, &st);
572580

573-
return 1;
581+
close(fd);
582+
return ret;
574583
}
575584

576585
static const char *find_reference_location_1(struct snapshot *snapshot,
@@ -2059,7 +2068,7 @@ static int packed_fsck(struct ref_store *ref_store,
20592068
{
20602069
struct packed_ref_store *refs = packed_downcast(ref_store,
20612070
REF_STORE_READ, "fsck");
2062-
struct strbuf packed_ref_content = STRBUF_INIT;
2071+
struct snapshot snapshot = { 0 };
20632072
unsigned int sorted = 0;
20642073
struct stat st;
20652074
int ret = 0;
@@ -2103,21 +2112,25 @@ static int packed_fsck(struct ref_store *ref_store,
21032112
goto cleanup;
21042113
}
21052114

2106-
if (strbuf_read(&packed_ref_content, fd, 0) < 0) {
2107-
ret = error_errno(_("unable to read '%s'"), refs->path);
2115+
if (!allocate_snapshot_buffer(&snapshot, fd, &st)) {
2116+
struct fsck_ref_report report = { 0 };
2117+
report.path = "packed-refs";
2118+
ret = fsck_report_ref(o, &report,
2119+
FSCK_MSG_EMPTY_PACKED_REFS_FILE,
2120+
"file is empty");
21082121
goto cleanup;
21092122
}
21102123

2111-
ret = packed_fsck_ref_content(o, ref_store, &sorted, packed_ref_content.buf,
2112-
packed_ref_content.buf + packed_ref_content.len);
2124+
ret = packed_fsck_ref_content(o, ref_store, &sorted, snapshot.start,
2125+
snapshot.eof);
21132126
if (!ret && sorted)
2114-
ret = packed_fsck_ref_sorted(o, ref_store, packed_ref_content.buf,
2115-
packed_ref_content.buf + packed_ref_content.len);
2127+
ret = packed_fsck_ref_sorted(o, ref_store, snapshot.start,
2128+
snapshot.eof);
21162129

21172130
cleanup:
21182131
if (fd >= 0)
21192132
close(fd);
2120-
strbuf_release(&packed_ref_content);
2133+
clear_snapshot_buffer(&snapshot);
21212134
return ret;
21222135
}
21232136

t/t0602-reffiles-fsck.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,23 @@ test_expect_success SYMLINKS 'the filetype of packed-refs should be checked' '
647647
)
648648
'
649649

650+
test_expect_success 'empty packed-refs should be reported' '
651+
test_when_finished "rm -rf repo" &&
652+
git init repo &&
653+
(
654+
cd repo &&
655+
test_commit default &&
656+
657+
>.git/packed-refs &&
658+
git refs verify 2>err &&
659+
cat >expect <<-EOF &&
660+
warning: packed-refs: emptyPackedRefsFile: file is empty
661+
EOF
662+
rm .git/packed-refs &&
663+
test_cmp expect err
664+
)
665+
'
666+
650667
test_expect_success 'packed-refs header should be checked' '
651668
test_when_finished "rm -rf repo" &&
652669
git init repo &&

0 commit comments

Comments
 (0)