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 emptymaint
commit
d8b48af391
|
@ -59,6 +59,12 @@
|
|||
`emptyName`::
|
||||
(WARN) A path contains an empty name.
|
||||
|
||||
`emptyPackedRefsFile`::
|
||||
(INFO) "packed-refs" file is empty. Report to the
|
||||
git@vger.kernel.org mailing list if you see this error. As only
|
||||
very early versions of Git would create such an empty
|
||||
"packed_refs" file, we might tighten this rule in the future.
|
||||
|
||||
`extraHeaderEntry`::
|
||||
(IGNORE) Extra headers found after `tagger`.
|
||||
|
||||
|
|
1
fsck.h
1
fsck.h
|
@ -84,6 +84,7 @@ enum fsck_msg_type {
|
|||
FUNC(LARGE_PATHNAME, WARN) \
|
||||
/* infos (reported as warnings, but ignored by default) */ \
|
||||
FUNC(BAD_FILEMODE, INFO) \
|
||||
FUNC(EMPTY_PACKED_REFS_FILE, INFO) \
|
||||
FUNC(GITMODULES_PARSE, INFO) \
|
||||
FUNC(GITIGNORE_SYMLINK, INFO) \
|
||||
FUNC(GITATTRIBUTES_SYMLINK, INFO) \
|
||||
|
|
|
@ -517,6 +517,32 @@ static int refname_contains_nul(struct strbuf *refname)
|
|||
|
||||
#define SMALL_FILE_SIZE (32*1024)
|
||||
|
||||
static int allocate_snapshot_buffer(struct snapshot *snapshot, int fd, struct stat *st)
|
||||
{
|
||||
ssize_t bytes_read;
|
||||
size_t size;
|
||||
|
||||
size = xsize_t(st->st_size);
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
if (mmap_strategy == MMAP_NONE || size <= SMALL_FILE_SIZE) {
|
||||
snapshot->buf = xmalloc(size);
|
||||
bytes_read = read_in_full(fd, snapshot->buf, size);
|
||||
if (bytes_read < 0 || bytes_read != size)
|
||||
die_errno("couldn't read %s", snapshot->refs->path);
|
||||
snapshot->mmapped = 0;
|
||||
} else {
|
||||
snapshot->buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
snapshot->mmapped = 1;
|
||||
}
|
||||
|
||||
snapshot->start = snapshot->buf;
|
||||
snapshot->eof = snapshot->buf + size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Depending on `mmap_strategy`, either mmap or read the contents of
|
||||
* the `packed-refs` file into the snapshot. Return 1 if the file
|
||||
|
@ -525,10 +551,9 @@ static int refname_contains_nul(struct strbuf *refname)
|
|||
*/
|
||||
static int load_contents(struct snapshot *snapshot)
|
||||
{
|
||||
int fd;
|
||||
struct stat st;
|
||||
size_t size;
|
||||
ssize_t bytes_read;
|
||||
int ret;
|
||||
int fd;
|
||||
|
||||
fd = open(snapshot->refs->path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
|
@ -550,27 +575,11 @@ static int load_contents(struct snapshot *snapshot)
|
|||
|
||||
if (fstat(fd, &st) < 0)
|
||||
die_errno("couldn't stat %s", snapshot->refs->path);
|
||||
size = xsize_t(st.st_size);
|
||||
|
||||
if (!size) {
|
||||
close(fd);
|
||||
return 0;
|
||||
} else if (mmap_strategy == MMAP_NONE || size <= SMALL_FILE_SIZE) {
|
||||
snapshot->buf = xmalloc(size);
|
||||
bytes_read = read_in_full(fd, snapshot->buf, size);
|
||||
if (bytes_read < 0 || bytes_read != size)
|
||||
die_errno("couldn't read %s", snapshot->refs->path);
|
||||
snapshot->mmapped = 0;
|
||||
} else {
|
||||
snapshot->buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
snapshot->mmapped = 1;
|
||||
}
|
||||
ret = allocate_snapshot_buffer(snapshot, fd, &st);
|
||||
|
||||
close(fd);
|
||||
|
||||
snapshot->start = snapshot->buf;
|
||||
snapshot->eof = snapshot->buf + size;
|
||||
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *find_reference_location_1(struct snapshot *snapshot,
|
||||
|
@ -2059,7 +2068,7 @@ static int packed_fsck(struct ref_store *ref_store,
|
|||
{
|
||||
struct packed_ref_store *refs = packed_downcast(ref_store,
|
||||
REF_STORE_READ, "fsck");
|
||||
struct strbuf packed_ref_content = STRBUF_INIT;
|
||||
struct snapshot snapshot = { 0 };
|
||||
unsigned int sorted = 0;
|
||||
struct stat st;
|
||||
int ret = 0;
|
||||
|
@ -2103,21 +2112,25 @@ static int packed_fsck(struct ref_store *ref_store,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
if (strbuf_read(&packed_ref_content, fd, 0) < 0) {
|
||||
ret = error_errno(_("unable to read '%s'"), refs->path);
|
||||
if (!allocate_snapshot_buffer(&snapshot, fd, &st)) {
|
||||
struct fsck_ref_report report = { 0 };
|
||||
report.path = "packed-refs";
|
||||
ret = fsck_report_ref(o, &report,
|
||||
FSCK_MSG_EMPTY_PACKED_REFS_FILE,
|
||||
"file is empty");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = packed_fsck_ref_content(o, ref_store, &sorted, packed_ref_content.buf,
|
||||
packed_ref_content.buf + packed_ref_content.len);
|
||||
ret = packed_fsck_ref_content(o, ref_store, &sorted, snapshot.start,
|
||||
snapshot.eof);
|
||||
if (!ret && sorted)
|
||||
ret = packed_fsck_ref_sorted(o, ref_store, packed_ref_content.buf,
|
||||
packed_ref_content.buf + packed_ref_content.len);
|
||||
ret = packed_fsck_ref_sorted(o, ref_store, snapshot.start,
|
||||
snapshot.eof);
|
||||
|
||||
cleanup:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
strbuf_release(&packed_ref_content);
|
||||
clear_snapshot_buffer(&snapshot);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -647,6 +647,23 @@ test_expect_success SYMLINKS 'the filetype of packed-refs should be checked' '
|
|||
)
|
||||
'
|
||||
|
||||
test_expect_success 'empty packed-refs should be reported' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
git init repo &&
|
||||
(
|
||||
cd repo &&
|
||||
test_commit default &&
|
||||
|
||||
>.git/packed-refs &&
|
||||
git refs verify 2>err &&
|
||||
cat >expect <<-EOF &&
|
||||
warning: packed-refs: emptyPackedRefsFile: file is empty
|
||||
EOF
|
||||
rm .git/packed-refs &&
|
||||
test_cmp expect err
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'packed-refs header should be checked' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
git init repo &&
|
||||
|
|
Loading…
Reference in New Issue