diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 60869b8b37..b4b99a73da 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -500,7 +500,7 @@ static void batch_object_write(const char *obj_name, data->info.sizep = &data->size; if (pack) - ret = packed_object_info(pack, offset, &data->info); + ret = packed_object_info(NULL, pack, offset, &data->info); else ret = odb_read_object_info_extended(the_repository->objects, &data->oid, &data->info, @@ -837,8 +837,9 @@ static int batch_one_object_oi(const struct object_id *oid, void *_payload) { struct for_each_object_payload *payload = _payload; - if (oi && oi->whence == OI_PACKED) - return payload->callback(oid, oi->u.packed.pack, oi->u.packed.offset, + if (oi && oi->source_infop->source->type == ODB_SOURCE_PACKED) + return payload->callback(oid, oi->source_infop->u.packed.pack, + oi->source_infop->u.packed.offset, payload->payload); return payload->callback(oid, NULL, 0, payload->payload); } @@ -909,7 +910,10 @@ static void batch_each_object(struct batch_options *opt, &payload, flags); } } else { - struct object_info oi = { 0 }; + struct odb_source_info source_info; + struct object_info oi = { + .source_infop = &source_info, + }; for (source = the_repository->objects->sources; source; source = source->next) { struct odb_source_files *files = odb_source_files_downcast(source); diff --git a/builtin/index-pack.c b/builtin/index-pack.c index f396658468..7af1aea6f9 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -1825,11 +1825,16 @@ static void repack_local_links(void) oidset_iter_init(&outgoing_links, &iter); while ((oid = oidset_iter_next(&iter))) { - struct object_info info = OBJECT_INFO_INIT; + struct odb_source_info source_info; + struct object_info info = { + .source_infop = &source_info, + }; + if (odb_read_object_info_extended(the_repository->objects, oid, &info, 0)) /* Missing; assume it is a promisor object */ continue; - if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor) + if (source_info.source->type == ODB_SOURCE_PACKED && + source_info.u.packed.pack->pack_promisor) continue; if (!cmd.args.nr) { diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index e3760b3492..ea5eab4cf8 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -2463,7 +2463,7 @@ static void drop_reused_delta(struct object_entry *entry) oi.sizep = &size; oi.typep = &type; - if (packed_object_info(IN_PACK(entry), entry->in_pack_offset, &oi) < 0) { + if (packed_object_info(NULL, IN_PACK(entry), entry->in_pack_offset, &oi) < 0) { /* * We failed to get the info from this pack for some reason; * fall back to odb_read_object_info, which may find another copy. @@ -3820,7 +3820,7 @@ static int add_object_entry_from_pack(const struct object_id *oid, ofs = nth_packed_object_offset(p, pos); oi.typep = &type; - if (packed_object_info(p, ofs, &oi) < 0) { + if (packed_object_info(NULL, p, ofs, &oi) < 0) { die(_("could not get type of object %s in pack %s"), oid_to_hex(oid), p->pack_name); } else if (type == OBJ_COMMIT) { @@ -4495,8 +4495,9 @@ static int add_object_in_unpacked_pack(const struct object_id *oid, void *data UNUSED) { if (cruft) { - add_cruft_object_entry(oid, OBJ_NONE, oi->u.packed.pack, - oi->u.packed.offset, NULL, *oi->mtimep); + add_cruft_object_entry(oid, OBJ_NONE, oi->source_infop->u.packed.pack, + oi->source_infop->u.packed.offset, NULL, + *oi->mtimep); } else { add_object_entry(oid, OBJ_NONE, "", 0); } @@ -4513,8 +4514,10 @@ static void add_objects_in_unpacked_packs(void) ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS | ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS, }; + struct odb_source_info source_info; struct object_info oi = { .mtimep = &mtime, + .source_infop = &source_info, }; odb_prepare_alternates(to_pack.repo->objects); @@ -5036,10 +5039,14 @@ static int option_parse_cruft_expiration(const struct option *opt UNUSED, static int is_not_in_promisor_pack_obj(struct object *obj, void *data UNUSED) { - struct object_info info = OBJECT_INFO_INIT; + struct odb_source_info source_info; + struct object_info info = { + .source_infop = &source_info, + }; + if (odb_read_object_info_extended(the_repository->objects, &obj->oid, &info, 0)) BUG("should_include_obj should only be called on existing objects"); - return info.whence != OI_PACKED || !info.u.packed.pack->pack_promisor; + return source_info.source->type != ODB_SOURCE_PACKED || !source_info.u.packed.pack->pack_promisor; } static int is_not_in_promisor_pack(struct commit *commit, void *data) { diff --git a/commit-graph.c b/commit-graph.c index c6d9c5c740..9dc8bd5eee 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -1538,7 +1538,7 @@ static int add_packed_commits(const struct object_id *oid, struct object_info oi = OBJECT_INFO_INIT; oi.typep = &type; - if (packed_object_info(pack, offset, &oi) < 0) + if (packed_object_info(NULL, pack, offset, &oi) < 0) die(_("unable to get type of object %s"), oid_to_hex(oid)); return add_packed_commits_oi(oid, &oi, data); diff --git a/odb.c b/odb.c index 68dca6357f..cf6e7938c0 100644 --- a/odb.c +++ b/odb.c @@ -691,8 +691,8 @@ static int oid_object_info_convert(struct repository *r, return -1; } } - input_oi->whence = new_oi.whence; - input_oi->u = new_oi.u; + if (input_oi->source_infop) + *input_oi->source_infop = *new_oi.source_infop; return ret; } diff --git a/odb.h b/odb.h index a194865052..94754643d2 100644 --- a/odb.h +++ b/odb.h @@ -260,33 +260,19 @@ int odb_pretend_object(struct object_database *odb, void *buf, size_t len, enum object_type type, struct object_id *oid); -struct object_info { - /* Request */ - enum object_type *typep; - size_t *sizep; - off_t *disk_sizep; - struct object_id *delta_base_oid; - void **contentp; +/* + * Object database source information that can be used to uniquely identify an + * object and learn more about how exactly it is stored. + */ +struct odb_source_info { + /* The source that this object has been looked up from. */ + struct odb_source *source; /* - * The time the given looked-up object has been last modified. - * - * Note: the mtime may be ambiguous in case the object exists multiple - * times in the object database. It is thus _not_ recommended to use - * this field outside of contexts where you would read every instance - * of the object, like for example with `odb_for_each_object()`. As it - * is impossible to say at the ODB level what the intent of the caller - * is (e.g. whether to find the oldest or newest object), it is the - * responsibility of the caller to disambiguate the mtimes. + * Backend-specific information about the specific object. This can be + * used for example to uniquely identify a given object in case it + * exists multiple times. */ - time_t *mtimep; - - /* Response */ - enum { - OI_CACHED, - OI_LOOSE, - OI_PACKED, - } whence; union { /* * struct { @@ -309,6 +295,52 @@ struct object_info { } u; }; +/* + * The object info contains the query and response that is to be used for + * functions that end up reading object information. Callers are expected to + * populate pointers whose information they want to request. + */ +struct object_info { + /* The object type. */ + enum object_type *typep; + + /* The inflated object size in bytes. */ + size_t *sizep; + + /* The object size as stored on disk. */ + off_t *disk_sizep; + + /* + * The base the object is deltified against, in case it is stored as a + * delta. + */ + struct object_id *delta_base_oid; + + /* The object contents. Ownership of memory goes over to the caller. */ + void **contentp; + + /* + * The time the given looked-up object has been last modified. + * + * Note: the mtime may be ambiguous in case the object exists multiple + * times in the object database. It is thus _not_ recommended to use + * this field outside of contexts where you would read every instance + * of the object, like for example with `odb_for_each_object()`. As it + * is impossible to say at the ODB level what the intent of the caller + * is (e.g. whether to find the oldest or newest object), it is the + * responsibility of the caller to disambiguate the mtimes. + */ + time_t *mtimep; + + /* + * Backend-specific information that tells the caller where exactly an + * object was looked up from. This information should help disambiguate + * object lookups in case the same object exists in multiple sources, + * or multiple times in the same source. + */ + struct odb_source_info *source_infop; +}; + /* * Initializer for a "struct object_info" that wants no items. You may * also memset() the memory to all-zeroes. diff --git a/odb/source-inmemory.c b/odb/source-inmemory.c index 0b51c58238..f41a602e64 100644 --- a/odb/source-inmemory.c +++ b/odb/source-inmemory.c @@ -52,7 +52,8 @@ static void populate_object_info(struct odb_source_inmemory *source, *oi->contentp = xmemdupz(object->buf, object->size); if (oi->mtimep) *oi->mtimep = 0; - oi->whence = OI_CACHED; + if (oi->source_infop) + oi->source_infop->source = &source->base; } static int odb_source_inmemory_read_object_info(struct odb_source *source, diff --git a/odb/source-loose.c b/odb/source-loose.c index a404046d50..091e8e00a7 100644 --- a/odb/source-loose.c +++ b/odb/source-loose.c @@ -196,8 +196,8 @@ out: oi->typep = NULL; if (oi->delta_base_oid) oidclr(oi->delta_base_oid, loose->base.odb->repo->hash_algo); - if (!ret) - oi->whence = OI_LOOSE; + if (oi->source_infop && !ret) + oi->source_infop->source = &loose->base; } return ret; diff --git a/odb/source-packed.c b/odb/source-packed.c index a0259b95bf..647f23cdb9 100644 --- a/odb/source-packed.c +++ b/odb/source-packed.c @@ -59,7 +59,7 @@ static int odb_source_packed_read_object_info(struct odb_source *source, if (!oi) return 0; - ret = packed_object_info(e.p, e.offset, oi); + ret = packed_object_info(packed, e.p, e.offset, oi); if (ret < 0) { mark_bad_packed_object(e.p, oid); return -1; @@ -99,7 +99,7 @@ static int odb_source_packed_for_each_object_wrapper(const struct object_id *oid off_t offset = nth_packed_object_offset(pack, index_pos); struct object_info oi = *data->request; - if (packed_object_info_with_index_pos(pack, offset, + if (packed_object_info_with_index_pos(data->store, pack, offset, &index_pos, &oi) < 0) { mark_bad_packed_object(pack, oid); return -1; diff --git a/pack-bitmap.c b/pack-bitmap.c index 83eb47a28b..35774b6f0c 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -1877,7 +1877,7 @@ static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git, ofs = pack_pos_to_offset(pack, pos); } - if (packed_object_info(pack, ofs, &oi) < 0) { + if (packed_object_info(NULL, pack, ofs, &oi) < 0) { struct object_id oid; nth_bitmap_object_oid(bitmap_git, &oid, pack_pos_to_index(pack, pos)); diff --git a/packfile.c b/packfile.c index 60dd0f286a..0eee45055f 100644 --- a/packfile.c +++ b/packfile.c @@ -1324,7 +1324,8 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset, hashmap_add(&delta_base_cache, &ent->ent); } -int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_offset, +int packed_object_info_with_index_pos(struct odb_source_packed *source, + struct packed_git *p, off_t obj_offset, uint32_t *maybe_index_pos, struct object_info *oi) { struct pack_window *w_curs = NULL; @@ -1420,23 +1421,28 @@ int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_offset, oidclr(oi->delta_base_oid, p->repo->hash_algo); } - oi->whence = OI_PACKED; - oi->u.packed.offset = obj_offset; - oi->u.packed.pack = p; + if (oi->source_infop) { + if (!source) + BUG("cannot request source without an owning source"); + oi->source_infop->source = &source->base; - switch (type) { - case OBJ_NONE: - oi->u.packed.type = PACKED_OBJECT_TYPE_UNKNOWN; - break; - case OBJ_REF_DELTA: - oi->u.packed.type = PACKED_OBJECT_TYPE_REF_DELTA; - break; - case OBJ_OFS_DELTA: - oi->u.packed.type = PACKED_OBJECT_TYPE_OFS_DELTA; - break; - default: - oi->u.packed.type = PACKED_OBJECT_TYPE_FULL; - break; + oi->source_infop->u.packed.offset = obj_offset; + oi->source_infop->u.packed.pack = p; + + switch (type) { + case OBJ_NONE: + oi->source_infop->u.packed.type = PACKED_OBJECT_TYPE_UNKNOWN; + break; + case OBJ_REF_DELTA: + oi->source_infop->u.packed.type = PACKED_OBJECT_TYPE_REF_DELTA; + break; + case OBJ_OFS_DELTA: + oi->source_infop->u.packed.type = PACKED_OBJECT_TYPE_OFS_DELTA; + break; + default: + oi->source_infop->u.packed.type = PACKED_OBJECT_TYPE_FULL; + break; + } } ret = 0; @@ -1446,10 +1452,11 @@ out: return ret; } -int packed_object_info(struct packed_git *p, off_t obj_offset, +int packed_object_info(struct odb_source_packed *source, + struct packed_git *p, off_t obj_offset, struct object_info *oi) { - return packed_object_info_with_index_pos(p, obj_offset, NULL, oi); + return packed_object_info_with_index_pos(source, p, obj_offset, NULL, oi); } static void *unpack_compressed_entry(struct packed_git *p, diff --git a/packfile.h b/packfile.h index 2329a69701..e1f77152b5 100644 --- a/packfile.h +++ b/packfile.h @@ -320,9 +320,11 @@ extern int do_check_packed_object_crc; * Look up the object info for a specific offset in the packfile. * Returns zero on success, a negative error code otherwise. */ -int packed_object_info(struct packed_git *pack, +int packed_object_info(struct odb_source_packed *source, + struct packed_git *pack, off_t offset, struct object_info *); -int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_offset, +int packed_object_info_with_index_pos(struct odb_source_packed *source, + struct packed_git *p, off_t obj_offset, uint32_t *maybe_index_pos, struct object_info *oi); void mark_bad_packed_object(struct packed_git *, const struct object_id *); diff --git a/reachable.c b/reachable.c index 101cfc2727..caadacc02a 100644 --- a/reachable.c +++ b/reachable.c @@ -234,8 +234,9 @@ static int add_recent_object(const struct object_id *oid, add_pending_object(data->revs, obj, ""); if (data->cb) { - if (oi->whence == OI_PACKED) - data->cb(obj, oi->u.packed.pack, oi->u.packed.offset, *oi->mtimep); + if (oi->source_infop->source->type == ODB_SOURCE_PACKED) + data->cb(obj, oi->source_infop->u.packed.pack, + oi->source_infop->u.packed.offset, *oi->mtimep); else data->cb(obj, NULL, 0, *oi->mtimep); } @@ -252,9 +253,11 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs, unsigned flags; enum object_type type; time_t mtime; + struct odb_source_info source_info; struct object_info oi = { .mtimep = &mtime, .typep = &type, + .source_infop = &source_info, }; int r; diff --git a/t/helper/test-bitmap.c b/t/helper/test-bitmap.c index b130832b81..8547ef67e2 100644 --- a/t/helper/test-bitmap.c +++ b/t/helper/test-bitmap.c @@ -52,7 +52,7 @@ static int add_packed_object(const struct object_id *oid, entry = packlist_alloc(packed, oid); entry->idx.offset = nth_packed_object_offset(pack, pos); - if (packed_object_info(pack, entry->idx.offset, &oi) < 0) + if (packed_object_info(NULL, pack, entry->idx.offset, &oi) < 0) die("could not get type of object %s", oid_to_hex(oid)); oe_set_type(entry, type);