object-file: read objects via the loose object source

When reading an object via `loose_object_info()` or `map_loose_object()`
we hand in the whole repository. We then iterate through each of the
object sources to figure out whether that source has the object in
question.

This logic is reversing responsibility though: a specific backend should
only care about one specific source, where the object sources themselves
are then managed by the object database.

Refactor the code accordingly by passing an object source to both of
these functions instead. The different sources are then handled by
either `do_oid_object_info_extended()`, which sits on the object
database level, and by `open_istream_loose()`. The latter function
arguably is still at the wrong level, but this will be cleaned up at a
later point in time.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt
2025-11-03 08:42:04 +01:00
committed by Junio C Hamano
parent 376016ec71
commit ff7ad5cb39
4 changed files with 50 additions and 53 deletions

View File

@@ -167,25 +167,22 @@ int stream_object_signature(struct repository *r, const struct object_id *oid)
} }
/* /*
* Find "oid" as a loose object in the local repository or in an alternate. * Find "oid" as a loose object in given source.
* Returns 0 on success, negative on failure. * Returns 0 on success, negative on failure.
* *
* The "path" out-parameter will give the path of the object we found (if any). * The "path" out-parameter will give the path of the object we found (if any).
* Note that it may point to static storage and is only valid until another * Note that it may point to static storage and is only valid until another
* call to stat_loose_object(). * call to stat_loose_object().
*/ */
static int stat_loose_object(struct repository *r, const struct object_id *oid, static int stat_loose_object(struct odb_source_loose *loose,
const struct object_id *oid,
struct stat *st, const char **path) struct stat *st, const char **path)
{ {
struct odb_source *source;
static struct strbuf buf = STRBUF_INIT; static struct strbuf buf = STRBUF_INIT;
odb_prepare_alternates(r->objects); *path = odb_loose_path(loose->source, &buf, oid);
for (source = r->objects->sources; source; source = source->next) { if (!lstat(*path, st))
*path = odb_loose_path(source, &buf, oid); return 0;
if (!lstat(*path, st))
return 0;
}
return -1; return -1;
} }
@@ -194,39 +191,24 @@ static int stat_loose_object(struct repository *r, const struct object_id *oid,
* Like stat_loose_object(), but actually open the object and return the * Like stat_loose_object(), but actually open the object and return the
* descriptor. See the caveats on the "path" parameter above. * descriptor. See the caveats on the "path" parameter above.
*/ */
static int open_loose_object(struct repository *r, static int open_loose_object(struct odb_source_loose *loose,
const struct object_id *oid, const char **path) const struct object_id *oid, const char **path)
{ {
int fd;
struct odb_source *source;
int most_interesting_errno = ENOENT;
static struct strbuf buf = STRBUF_INIT; static struct strbuf buf = STRBUF_INIT;
int fd;
odb_prepare_alternates(r->objects); *path = odb_loose_path(loose->source, &buf, oid);
for (source = r->objects->sources; source; source = source->next) { fd = git_open(*path);
*path = odb_loose_path(source, &buf, oid); if (fd >= 0)
fd = git_open(*path); return fd;
if (fd >= 0)
return fd;
if (most_interesting_errno == ENOENT)
most_interesting_errno = errno;
}
errno = most_interesting_errno;
return -1; return -1;
} }
static int quick_has_loose(struct repository *r, static int quick_has_loose(struct odb_source_loose *loose,
const struct object_id *oid) const struct object_id *oid)
{ {
struct odb_source *source; return !!oidtree_contains(odb_source_loose_cache(loose->source, oid), oid);
odb_prepare_alternates(r->objects);
for (source = r->objects->sources; source; source = source->next) {
if (oidtree_contains(odb_source_loose_cache(source, oid), oid))
return 1;
}
return 0;
} }
/* /*
@@ -252,12 +234,12 @@ static void *map_fd(int fd, const char *path, unsigned long *size)
return map; return map;
} }
void *map_loose_object(struct repository *r, void *odb_source_loose_map_object(struct odb_source *source,
const struct object_id *oid, const struct object_id *oid,
unsigned long *size) unsigned long *size)
{ {
const char *p; const char *p;
int fd = open_loose_object(r, oid, &p); int fd = open_loose_object(source->loose, oid, &p);
if (fd < 0) if (fd < 0)
return NULL; return NULL;
@@ -407,9 +389,9 @@ int parse_loose_header(const char *hdr, struct object_info *oi)
return 0; return 0;
} }
int loose_object_info(struct repository *r, int odb_source_loose_read_object_info(struct odb_source *source,
const struct object_id *oid, const struct object_id *oid,
struct object_info *oi, int flags) struct object_info *oi, int flags)
{ {
int status = 0; int status = 0;
int fd; int fd;
@@ -422,7 +404,7 @@ int loose_object_info(struct repository *r,
enum object_type type_scratch; enum object_type type_scratch;
if (oi->delta_base_oid) if (oi->delta_base_oid)
oidclr(oi->delta_base_oid, r->hash_algo); oidclr(oi->delta_base_oid, source->odb->repo->hash_algo);
/* /*
* If we don't care about type or size, then we don't * If we don't care about type or size, then we don't
@@ -435,15 +417,15 @@ int loose_object_info(struct repository *r,
if (!oi->typep && !oi->sizep && !oi->contentp) { if (!oi->typep && !oi->sizep && !oi->contentp) {
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(source->loose, oid) ? 0 : -1;
if (stat_loose_object(r, oid, &st, &path) < 0) if (stat_loose_object(source->loose, oid, &st, &path) < 0)
return -1; return -1;
if (oi->disk_sizep) if (oi->disk_sizep)
*oi->disk_sizep = st.st_size; *oi->disk_sizep = st.st_size;
return 0; return 0;
} }
fd = open_loose_object(r, oid, &path); fd = open_loose_object(source->loose, oid, &path);
if (fd < 0) { if (fd < 0) {
if (errno != ENOENT) if (errno != ENOENT)
error_errno(_("unable to open loose object %s"), oid_to_hex(oid)); error_errno(_("unable to open loose object %s"), oid_to_hex(oid));

View File

@@ -43,6 +43,14 @@ void odb_source_loose_free(struct odb_source_loose *loose);
/* Reprepare the loose source by emptying the loose object cache. */ /* Reprepare the loose source by emptying the loose object cache. */
void odb_source_loose_reprepare(struct odb_source *source); void odb_source_loose_reprepare(struct odb_source *source);
int odb_source_loose_read_object_info(struct odb_source *source,
const struct object_id *oid,
struct object_info *oi, int flags);
void *odb_source_loose_map_object(struct odb_source *source,
const struct object_id *oid,
unsigned long *size);
/* /*
* Populate and return the loose object cache array corresponding to the * Populate and return the loose object cache array corresponding to the
* given object ID. * given object ID.
@@ -66,9 +74,6 @@ const char *odb_loose_path(struct odb_source *source,
int has_loose_object(struct odb_source *source, int has_loose_object(struct odb_source *source,
const struct object_id *oid); const struct object_id *oid);
void *map_loose_object(struct repository *r, const struct object_id *oid,
unsigned long *size);
/* /*
* Iterate over the files in the loose-object parts of the object * Iterate over the files in the loose-object parts of the object
* directory "path", triggering the following callbacks: * directory "path", triggering the following callbacks:
@@ -196,10 +201,6 @@ int check_object_signature(struct repository *r, const struct object_id *oid,
*/ */
int stream_object_signature(struct repository *r, const struct object_id *oid); int stream_object_signature(struct repository *r, const struct object_id *oid);
int loose_object_info(struct repository *r,
const struct object_id *oid,
struct object_info *oi, int flags);
enum finalize_object_file_flags { enum finalize_object_file_flags {
FOF_SKIP_COLLISION_CHECK = 1, FOF_SKIP_COLLISION_CHECK = 1,
}; };

9
odb.c
View File

@@ -697,13 +697,18 @@ static int do_oid_object_info_extended(struct object_database *odb,
return 0; return 0;
} }
odb_prepare_alternates(odb);
while (1) { while (1) {
struct odb_source *source;
if (find_pack_entry(odb->repo, real, &e)) if (find_pack_entry(odb->repo, real, &e))
break; break;
/* Most likely it's a loose object. */ /* Most likely it's a loose object. */
if (!loose_object_info(odb->repo, real, oi, flags)) for (source = odb->sources; source; source = source->next)
return 0; if (!odb_source_loose_read_object_info(source, real, oi, flags))
return 0;
/* Not a loose object; someone else may have just packed it. */ /* Not a loose object; someone else may have just packed it. */
if (!(flags & OBJECT_INFO_QUICK)) { if (!(flags & OBJECT_INFO_QUICK)) {

View File

@@ -230,12 +230,21 @@ static int open_istream_loose(struct git_istream *st, struct repository *r,
enum object_type *type) enum object_type *type)
{ {
struct object_info oi = OBJECT_INFO_INIT; struct object_info oi = OBJECT_INFO_INIT;
struct odb_source *source;
oi.sizep = &st->size; oi.sizep = &st->size;
oi.typep = type; oi.typep = type;
st->u.loose.mapped = map_loose_object(r, oid, &st->u.loose.mapsize); odb_prepare_alternates(r->objects);
for (source = r->objects->sources; source; source = source->next) {
st->u.loose.mapped = odb_source_loose_map_object(source, oid,
&st->u.loose.mapsize);
if (st->u.loose.mapped)
break;
}
if (!st->u.loose.mapped) if (!st->u.loose.mapped)
return -1; return -1;
switch (unpack_loose_header(&st->z, st->u.loose.mapped, switch (unpack_loose_header(&st->z, st->u.loose.mapped,
st->u.loose.mapsize, st->u.loose.hdr, st->u.loose.mapsize, st->u.loose.hdr,
sizeof(st->u.loose.hdr))) { sizeof(st->u.loose.hdr))) {