Skip to content

Commit 5de2e33

Browse files
committed
Merge branch 'sj/use-mmap-to-check-packed-refs' into jch
* sj/use-mmap-to-check-packed-refs: packed-backend: mmap large "packed-refs" file during fsck packed-backend: extract munmap operation for `MMAP_TEMPORARY` packed-backend: extract snapshot allocation in `load_contents` packed-backend: fsck should allow an empty "packed-refs" file
2 parents a1c08e6 + bb42969 commit 5de2e33

File tree

2 files changed

+82
-44
lines changed

2 files changed

+82
-44
lines changed

refs/packed-backend.c

Lines changed: 69 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,53 @@ 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+
546+
static void munmap_temporary_snapshot(struct snapshot *snapshot)
547+
{
548+
char *buf_copy;
549+
size_t size;
550+
551+
if (!snapshot)
552+
return;
553+
554+
/*
555+
* We don't want to leave the file mmapped, so we are
556+
* forced to make a copy now:
557+
*/
558+
size = snapshot->eof - snapshot->start;
559+
buf_copy = xmalloc(size);
560+
561+
memcpy(buf_copy, snapshot->start, size);
562+
clear_snapshot_buffer(snapshot);
563+
snapshot->buf = snapshot->start = buf_copy;
564+
snapshot->eof = buf_copy + size;
565+
}
566+
520567
/*
521568
* Depending on `mmap_strategy`, either mmap or read the contents of
522569
* the `packed-refs` file into the snapshot. Return 1 if the file
@@ -525,10 +572,9 @@ static int refname_contains_nul(struct strbuf *refname)
525572
*/
526573
static int load_contents(struct snapshot *snapshot)
527574
{
528-
int fd;
529575
struct stat st;
530-
size_t size;
531-
ssize_t bytes_read;
576+
int ret = 1;
577+
int fd;
532578

533579
fd = open(snapshot->refs->path, O_RDONLY);
534580
if (fd < 0) {
@@ -550,27 +596,12 @@ static int load_contents(struct snapshot *snapshot)
550596

551597
if (fstat(fd, &st) < 0)
552598
die_errno("couldn't stat %s", snapshot->refs->path);
553-
size = xsize_t(st.st_size);
554599

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);
600+
if (!allocate_snapshot_buffer(snapshot, fd, &st))
601+
ret = 0;
569602

570-
snapshot->start = snapshot->buf;
571-
snapshot->eof = snapshot->buf + size;
572-
573-
return 1;
603+
close(fd);
604+
return ret;
574605
}
575606

576607
static const char *find_reference_location_1(struct snapshot *snapshot,
@@ -751,19 +782,8 @@ static struct snapshot *create_snapshot(struct packed_ref_store *refs)
751782
verify_buffer_safe(snapshot);
752783
}
753784

754-
if (mmap_strategy != MMAP_OK && snapshot->mmapped) {
755-
/*
756-
* We don't want to leave the file mmapped, so we are
757-
* forced to make a copy now:
758-
*/
759-
size_t size = snapshot->eof - snapshot->start;
760-
char *buf_copy = xmalloc(size);
761-
762-
memcpy(buf_copy, snapshot->start, size);
763-
clear_snapshot_buffer(snapshot);
764-
snapshot->buf = snapshot->start = buf_copy;
765-
snapshot->eof = buf_copy + size;
766-
}
785+
if (mmap_strategy == MMAP_TEMPORARY && snapshot->mmapped)
786+
munmap_temporary_snapshot(snapshot);
767787

768788
return snapshot;
769789
}
@@ -2059,7 +2079,7 @@ static int packed_fsck(struct ref_store *ref_store,
20592079
{
20602080
struct packed_ref_store *refs = packed_downcast(ref_store,
20612081
REF_STORE_READ, "fsck");
2062-
struct strbuf packed_ref_content = STRBUF_INIT;
2082+
struct snapshot *snapshot = xcalloc(1, sizeof(*snapshot));
20632083
unsigned int sorted = 0;
20642084
struct stat st;
20652085
int ret = 0;
@@ -2103,21 +2123,26 @@ static int packed_fsck(struct ref_store *ref_store,
21032123
goto cleanup;
21042124
}
21052125

2106-
if (strbuf_read(&packed_ref_content, fd, 0) < 0) {
2107-
ret = error_errno(_("unable to read '%s'"), refs->path);
2126+
if (!st.st_size)
21082127
goto cleanup;
2109-
}
21102128

2111-
ret = packed_fsck_ref_content(o, ref_store, &sorted, packed_ref_content.buf,
2112-
packed_ref_content.buf + packed_ref_content.len);
2129+
if (!allocate_snapshot_buffer(snapshot, fd, &st))
2130+
goto cleanup;
2131+
2132+
if (mmap_strategy == MMAP_TEMPORARY && snapshot->mmapped)
2133+
munmap_temporary_snapshot(snapshot);
2134+
2135+
ret = packed_fsck_ref_content(o, ref_store, &sorted, snapshot->start,
2136+
snapshot->eof);
21132137
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);
2138+
ret = packed_fsck_ref_sorted(o, ref_store, snapshot->start,
2139+
snapshot->eof);
21162140

21172141
cleanup:
21182142
if (fd >= 0)
21192143
close(fd);
2120-
strbuf_release(&packed_ref_content);
2144+
clear_snapshot_buffer(snapshot);
2145+
free(snapshot);
21212146
return ret;
21222147
}
21232148

t/t0602-reffiles-fsck.sh

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

650+
test_expect_success 'empty packed-refs should not 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+
test_must_be_empty err
660+
)
661+
'
662+
650663
test_expect_success 'packed-refs header should be checked' '
651664
test_when_finished "rm -rf repo" &&
652665
git init repo &&

0 commit comments

Comments
 (0)