Merge branch 'jt/avoid-lazy-fetch-commits'
Even in a repository with promisor remote, it is useless to attempt to lazily attempt fetching an object that is expected to be commit, because no "filter" mode omits commit objects. Take advantage of this assumption to fail fast on errors. * jt/avoid-lazy-fetch-commits: commit: don't lazy-fetch commits object-file: emit corruption errors when detected object-file: refactor map_loose_object_1() object-file: remove OBJECT_INFO_IGNORE_LOOSEmaint
commit
1f9b02b970
15
commit.c
15
commit.c
|
@ -508,6 +508,17 @@ int repo_parse_commit_internal(struct repository *r,
|
||||||
enum object_type type;
|
enum object_type type;
|
||||||
void *buffer;
|
void *buffer;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
|
struct object_info oi = {
|
||||||
|
.typep = &type,
|
||||||
|
.sizep = &size,
|
||||||
|
.contentp = &buffer,
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
* Git does not support partial clones that exclude commits, so set
|
||||||
|
* OBJECT_INFO_SKIP_FETCH_OBJECT to fail fast when an object is missing.
|
||||||
|
*/
|
||||||
|
int flags = OBJECT_INFO_LOOKUP_REPLACE | OBJECT_INFO_SKIP_FETCH_OBJECT |
|
||||||
|
OBJECT_INFO_DIE_IF_CORRUPT;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!item)
|
if (!item)
|
||||||
|
@ -516,8 +527,8 @@ int repo_parse_commit_internal(struct repository *r,
|
||||||
return 0;
|
return 0;
|
||||||
if (use_commit_graph && parse_commit_in_graph(r, item))
|
if (use_commit_graph && parse_commit_in_graph(r, item))
|
||||||
return 0;
|
return 0;
|
||||||
buffer = repo_read_object_file(r, &item->object.oid, &type, &size);
|
|
||||||
if (!buffer)
|
if (oid_object_info_extended(r, &item->object.oid, &oi, flags) < 0)
|
||||||
return quiet_on_missing ? -1 :
|
return quiet_on_missing ? -1 :
|
||||||
error("Could not read %s",
|
error("Could not read %s",
|
||||||
oid_to_hex(&item->object.oid));
|
oid_to_hex(&item->object.oid));
|
||||||
|
|
108
object-file.c
108
object-file.c
|
@ -1211,35 +1211,25 @@ static int quick_has_loose(struct repository *r,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Map the loose object at "path" if it is not NULL, or the path found by
|
* Map and close the given loose object fd. The path argument is used for
|
||||||
* searching for a loose object named "oid".
|
* error reporting.
|
||||||
*/
|
*/
|
||||||
static void *map_loose_object_1(struct repository *r, const char *path,
|
static void *map_fd(int fd, const char *path, unsigned long *size)
|
||||||
const struct object_id *oid, unsigned long *size)
|
|
||||||
{
|
{
|
||||||
void *map;
|
void *map = NULL;
|
||||||
int fd;
|
struct stat st;
|
||||||
|
|
||||||
if (path)
|
if (!fstat(fd, &st)) {
|
||||||
fd = git_open(path);
|
*size = xsize_t(st.st_size);
|
||||||
else
|
if (!*size) {
|
||||||
fd = open_loose_object(r, oid, &path);
|
/* mmap() is forbidden on empty files */
|
||||||
map = NULL;
|
error(_("object file %s is empty"), path);
|
||||||
if (fd >= 0) {
|
close(fd);
|
||||||
struct stat st;
|
return NULL;
|
||||||
|
|
||||||
if (!fstat(fd, &st)) {
|
|
||||||
*size = xsize_t(st.st_size);
|
|
||||||
if (!*size) {
|
|
||||||
/* mmap() is forbidden on empty files */
|
|
||||||
error(_("object file %s is empty"), path);
|
|
||||||
close(fd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
||||||
}
|
}
|
||||||
close(fd);
|
map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||||
}
|
}
|
||||||
|
close(fd);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1247,7 +1237,12 @@ void *map_loose_object(struct repository *r,
|
||||||
const struct object_id *oid,
|
const struct object_id *oid,
|
||||||
unsigned long *size)
|
unsigned long *size)
|
||||||
{
|
{
|
||||||
return map_loose_object_1(r, NULL, oid, size);
|
const char *p;
|
||||||
|
int fd = open_loose_object(r, oid, &p);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
return NULL;
|
||||||
|
return map_fd(fd, p, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
|
enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
|
||||||
|
@ -1427,7 +1422,9 @@ static int loose_object_info(struct repository *r,
|
||||||
struct object_info *oi, int flags)
|
struct object_info *oi, int flags)
|
||||||
{
|
{
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
int fd;
|
||||||
unsigned long mapsize;
|
unsigned long mapsize;
|
||||||
|
const char *path;
|
||||||
void *map;
|
void *map;
|
||||||
git_zstream stream;
|
git_zstream stream;
|
||||||
char hdr[MAX_HEADER_LEN];
|
char hdr[MAX_HEADER_LEN];
|
||||||
|
@ -1448,7 +1445,6 @@ static int loose_object_info(struct repository *r,
|
||||||
* object even exists.
|
* object even exists.
|
||||||
*/
|
*/
|
||||||
if (!oi->typep && !oi->type_name && !oi->sizep && !oi->contentp) {
|
if (!oi->typep && !oi->type_name && !oi->sizep && !oi->contentp) {
|
||||||
const char *path;
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (!oi->disk_sizep && (flags & OBJECT_INFO_QUICK))
|
if (!oi->disk_sizep && (flags & OBJECT_INFO_QUICK))
|
||||||
return quick_has_loose(r, oid) ? 0 : -1;
|
return quick_has_loose(r, oid) ? 0 : -1;
|
||||||
|
@ -1459,7 +1455,13 @@ static int loose_object_info(struct repository *r,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
map = map_loose_object(r, oid, &mapsize);
|
fd = open_loose_object(r, oid, &path);
|
||||||
|
if (fd < 0) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
error_errno(_("unable to open loose object %s"), oid_to_hex(oid));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
map = map_fd(fd, path, &mapsize);
|
||||||
if (!map)
|
if (!map)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -1497,6 +1499,10 @@ static int loose_object_info(struct repository *r,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status && (flags & OBJECT_INFO_DIE_IF_CORRUPT))
|
||||||
|
die(_("loose object %s (stored in %s) is corrupt"),
|
||||||
|
oid_to_hex(oid), path);
|
||||||
|
|
||||||
git_inflate_end(&stream);
|
git_inflate_end(&stream);
|
||||||
cleanup:
|
cleanup:
|
||||||
munmap(map, mapsize);
|
munmap(map, mapsize);
|
||||||
|
@ -1575,9 +1581,6 @@ static int do_oid_object_info_extended(struct repository *r,
|
||||||
if (find_pack_entry(r, real, &e))
|
if (find_pack_entry(r, real, &e))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (flags & OBJECT_INFO_IGNORE_LOOSE)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* Most likely it's a loose object. */
|
/* Most likely it's a loose object. */
|
||||||
if (!loose_object_info(r, real, oi, flags))
|
if (!loose_object_info(r, real, oi, flags))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1609,6 +1612,15 @@ static int do_oid_object_info_extended(struct repository *r,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & OBJECT_INFO_DIE_IF_CORRUPT) {
|
||||||
|
const struct packed_git *p;
|
||||||
|
if ((flags & OBJECT_INFO_LOOKUP_REPLACE) && !oideq(real, oid))
|
||||||
|
die(_("replacement %s not found for %s"),
|
||||||
|
oid_to_hex(real), oid_to_hex(oid));
|
||||||
|
if ((p = has_packed_and_bad(r, real)))
|
||||||
|
die(_("packed object %s (stored in %s) is corrupt"),
|
||||||
|
oid_to_hex(real), p->pack_name);
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1661,7 +1673,8 @@ int oid_object_info(struct repository *r,
|
||||||
|
|
||||||
static void *read_object(struct repository *r,
|
static void *read_object(struct repository *r,
|
||||||
const struct object_id *oid, enum object_type *type,
|
const struct object_id *oid, enum object_type *type,
|
||||||
unsigned long *size)
|
unsigned long *size,
|
||||||
|
int die_if_corrupt)
|
||||||
{
|
{
|
||||||
struct object_info oi = OBJECT_INFO_INIT;
|
struct object_info oi = OBJECT_INFO_INIT;
|
||||||
void *content;
|
void *content;
|
||||||
|
@ -1669,7 +1682,8 @@ static void *read_object(struct repository *r,
|
||||||
oi.sizep = size;
|
oi.sizep = size;
|
||||||
oi.contentp = &content;
|
oi.contentp = &content;
|
||||||
|
|
||||||
if (oid_object_info_extended(r, oid, &oi, 0) < 0)
|
if (oid_object_info_extended(r, oid, &oi, die_if_corrupt
|
||||||
|
? OBJECT_INFO_DIE_IF_CORRUPT : 0) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
@ -1705,35 +1719,14 @@ void *read_object_file_extended(struct repository *r,
|
||||||
int lookup_replace)
|
int lookup_replace)
|
||||||
{
|
{
|
||||||
void *data;
|
void *data;
|
||||||
const struct packed_git *p;
|
|
||||||
const char *path;
|
|
||||||
struct stat st;
|
|
||||||
const struct object_id *repl = lookup_replace ?
|
const struct object_id *repl = lookup_replace ?
|
||||||
lookup_replace_object(r, oid) : oid;
|
lookup_replace_object(r, oid) : oid;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
data = read_object(r, repl, type, size);
|
data = read_object(r, repl, type, size, 1);
|
||||||
if (data)
|
if (data)
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
obj_read_lock();
|
|
||||||
if (errno && errno != ENOENT)
|
|
||||||
die_errno(_("failed to read object %s"), oid_to_hex(oid));
|
|
||||||
|
|
||||||
/* die if we replaced an object with one that does not exist */
|
|
||||||
if (repl != oid)
|
|
||||||
die(_("replacement %s not found for %s"),
|
|
||||||
oid_to_hex(repl), oid_to_hex(oid));
|
|
||||||
|
|
||||||
if (!stat_loose_object(r, repl, &st, &path))
|
|
||||||
die(_("loose object %s (stored in %s) is corrupt"),
|
|
||||||
oid_to_hex(repl), path);
|
|
||||||
|
|
||||||
if ((p = has_packed_and_bad(r, repl)))
|
|
||||||
die(_("packed object %s (stored in %s) is corrupt"),
|
|
||||||
oid_to_hex(repl), p->pack_name);
|
|
||||||
obj_read_unlock();
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2269,7 +2262,7 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
|
||||||
|
|
||||||
if (has_loose_object(oid))
|
if (has_loose_object(oid))
|
||||||
return 0;
|
return 0;
|
||||||
buf = read_object(the_repository, oid, &type, &len);
|
buf = read_object(the_repository, oid, &type, &len, 0);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return error(_("cannot read object for %s"), oid_to_hex(oid));
|
return error(_("cannot read object for %s"), oid_to_hex(oid));
|
||||||
hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
|
hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
|
||||||
|
@ -2785,13 +2778,16 @@ int read_loose_object(const char *path,
|
||||||
struct object_info *oi)
|
struct object_info *oi)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
int fd;
|
||||||
void *map = NULL;
|
void *map = NULL;
|
||||||
unsigned long mapsize;
|
unsigned long mapsize;
|
||||||
git_zstream stream;
|
git_zstream stream;
|
||||||
char hdr[MAX_HEADER_LEN];
|
char hdr[MAX_HEADER_LEN];
|
||||||
unsigned long *size = oi->sizep;
|
unsigned long *size = oi->sizep;
|
||||||
|
|
||||||
map = map_loose_object_1(the_repository, path, NULL, &mapsize);
|
fd = git_open(path);
|
||||||
|
if (fd >= 0)
|
||||||
|
map = map_fd(fd, path, &mapsize);
|
||||||
if (!map) {
|
if (!map) {
|
||||||
error_errno(_("unable to mmap %s"), path);
|
error_errno(_("unable to mmap %s"), path);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -434,19 +434,20 @@ struct object_info {
|
||||||
#define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2
|
#define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2
|
||||||
/* Do not retry packed storage after checking packed and loose storage */
|
/* Do not retry packed storage after checking packed and loose storage */
|
||||||
#define OBJECT_INFO_QUICK 8
|
#define OBJECT_INFO_QUICK 8
|
||||||
/* Do not check loose object */
|
|
||||||
#define OBJECT_INFO_IGNORE_LOOSE 16
|
|
||||||
/*
|
/*
|
||||||
* Do not attempt to fetch the object if missing (even if fetch_is_missing is
|
* Do not attempt to fetch the object if missing (even if fetch_is_missing is
|
||||||
* nonzero).
|
* nonzero).
|
||||||
*/
|
*/
|
||||||
#define OBJECT_INFO_SKIP_FETCH_OBJECT 32
|
#define OBJECT_INFO_SKIP_FETCH_OBJECT 16
|
||||||
/*
|
/*
|
||||||
* This is meant for bulk prefetching of missing blobs in a partial
|
* This is meant for bulk prefetching of missing blobs in a partial
|
||||||
* clone. Implies OBJECT_INFO_SKIP_FETCH_OBJECT and OBJECT_INFO_QUICK
|
* clone. Implies OBJECT_INFO_SKIP_FETCH_OBJECT and OBJECT_INFO_QUICK
|
||||||
*/
|
*/
|
||||||
#define OBJECT_INFO_FOR_PREFETCH (OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK)
|
#define OBJECT_INFO_FOR_PREFETCH (OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK)
|
||||||
|
|
||||||
|
/* Die if object corruption (not just an object being missing) was detected. */
|
||||||
|
#define OBJECT_INFO_DIE_IF_CORRUPT 32
|
||||||
|
|
||||||
int oid_object_info_extended(struct repository *r,
|
int oid_object_info_extended(struct repository *r,
|
||||||
const struct object_id *,
|
const struct object_id *,
|
||||||
struct object_info *, unsigned flags);
|
struct object_info *, unsigned flags);
|
||||||
|
|
Loading…
Reference in New Issue