odb: add `source` field to struct object_info_source

The previous commit introduced `struct object_info_source` as an opt-in container for backend-specific information, but for now we only moved preexisting data into this structure. Most importantly, the caller has no way yet to learn about which source an object was actually looked up from. Instead, callers have to rely on the `whence` enum to distinguish the object type, but cannot use that enum to tell the object source. Add a `struct odb_source *source` field to the structure and populate it from each backend's lookup path. The `whence` enum is still set and used by callers; it will be removed in a subsequent commit now that `sourcep->source` can identify the backend on its own. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jul 2, 2026 at 14:02 UTC 32a95be604e710d38e05d0013fbb2a64257c4014
9 files changed +44 -32
builtin/cat-file.c
+4 -4
@@ -835,8 +835,8 @@ static int batch_one_object_oi(const struct object_id *oid,
835 {
836 struct for_each_object_payload *payload = _payload;
837 if (oi && oi->whence == OI_PACKED)
838 - return payload->callback(oid, oi->sourcep->u.packed.pack,
839 - oi->sourcep->u.packed.offset,
838 + return payload->callback(oid, oi->source_infop->u.packed.pack,
839 + oi->source_infop->u.packed.offset,
840 payload->payload);
841 return payload->callback(oid, NULL, 0, payload->payload);
842 }
@@ -907,9 +907,9 @@ static void batch_each_object(struct batch_options *opt,
907 &payload, flags);
908 }
909 } else {
910 - struct object_info_source oi_source;
910 + struct odb_source_info source_info;
911 struct object_info oi = {
912 - .sourcep = &oi_source,
912 + .source_infop = &source_info,
913 };
914
915 for (source = the_repository->objects->sources; source; source = source->next) {
builtin/index-pack.c
+3 -3
@@ -1825,15 +1825,15 @@ static void repack_local_links(void)
1825
1826 oidset_iter_init(&outgoing_links, &iter);
1827 while ((oid = oidset_iter_next(&iter))) {
1828 - struct object_info_source info_source;
1828 + struct odb_source_info source_info;
1829 struct object_info info = {
1830 - .sourcep = &info_source,
1830 + .source_infop = &source_info,
1831 };
1832
1833 if (odb_read_object_info_extended(the_repository->objects, oid, &info, 0))
1834 /* Missing; assume it is a promisor object */
1835 continue;
1836 - if (info.whence == OI_PACKED && info_source.u.packed.pack->pack_promisor)
1836 + if (info.whence == OI_PACKED && source_info.u.packed.pack->pack_promisor)
1837 continue;
1838
1839 if (!cmd.args.nr) {
builtin/pack-objects.c
+7 -7
@@ -4491,8 +4491,8 @@ static int add_object_in_unpacked_pack(const struct object_id *oid,
4491 void *data UNUSED)
4492 {
4493 if (cruft) {
4494 - add_cruft_object_entry(oid, OBJ_NONE, oi->sourcep->u.packed.pack,
4495 - oi->sourcep->u.packed.offset, NULL,
4494 + add_cruft_object_entry(oid, OBJ_NONE, oi->source_infop->u.packed.pack,
4495 + oi->source_infop->u.packed.offset, NULL,
4496 *oi->mtimep);
4497 } else {
4498 add_object_entry(oid, OBJ_NONE, "", 0);
@@ -4510,10 +4510,10 @@ static void add_objects_in_unpacked_packs(void)
4510 ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS |
4511 ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS,
4512 };
4513 - struct object_info_source oi_source;
4513 + struct odb_source_info source_info;
4514 struct object_info oi = {
4515 .mtimep = &mtime,
4516 - .sourcep = &oi_source,
4516 + .source_infop = &source_info,
4517 };
4518
4519 odb_prepare_alternates(to_pack.repo->objects);
@@ -5003,14 +5003,14 @@ static int option_parse_cruft_expiration(const struct option *opt UNUSED,
5003
5004 static int is_not_in_promisor_pack_obj(struct object *obj, void *data UNUSED)
5005 {
5006 - struct object_info_source info_source;
5006 + struct odb_source_info source_info;
5007 struct object_info info = {
5008 - .sourcep = &info_source,
5008 + .source_infop = &source_info,
5009 };
5010
5011 if (odb_read_object_info_extended(the_repository->objects, &obj->oid, &info, 0))
5012 BUG("should_include_obj should only be called on existing objects");
5013 - return info.whence != OI_PACKED || !info_source.u.packed.pack->pack_promisor;
5013 + return info.whence != OI_PACKED || !source_info.u.packed.pack->pack_promisor;
5014 }
5015
5016 static int is_not_in_promisor_pack(struct commit *commit, void *data) {
odb.c
+2 -2
@@ -692,8 +692,8 @@ static int oid_object_info_convert(struct repository *r,
692 }
693 }
694 input_oi->whence = new_oi.whence;
695 - if (input_oi->sourcep)
696 - *input_oi->sourcep = *new_oi.sourcep;
695 + if (input_oi->source_infop)
696 + *input_oi->source_infop = *new_oi.source_infop;
697 return ret;
698 }
699
odb.h
+7 -4
@@ -249,10 +249,13 @@ int odb_pretend_object(struct object_database *odb,
249 struct object_id *oid);
250
251 /*
252 - * Object information that can be used to uniquely identify an object and learn
253 - * more about how exactly it is stored.
252 + * Object database source information that can be used to uniquely identify an
253 + * object and learn more about how exactly it is stored.
254 */
255 -struct object_info_source {
255 +struct odb_source_info {
256 + /* The source that this object has been looked up from. */
257 + struct odb_source *source;
258 +
259 /*
260 * Backend-specific information about the specific object. This can be
261 * used for example to uniquely identify a given object in case it
@@ -307,7 +310,7 @@ struct object_info {
310 * object lookups in case the same object exists in multiple sources,
311 * or multiple times in the same source.
312 */
310 - struct object_info_source *sourcep;
313 + struct odb_source_info *source_infop;
314
315 /* Response */
316 enum {
odb/source-inmemory.c
+3
@@ -52,6 +52,9 @@ static void populate_object_info(struct odb_source_inmemory *source,
52 *oi->contentp = xmemdupz(object->buf, object->size);
53 if (oi->mtimep)
54 *oi->mtimep = 0;
55 + if (oi->source_infop)
56 + oi->source_infop->source = &source->base;
57 +
58 oi->whence = OI_CACHED;
59 }
60
odb/source-loose.c
+2
@@ -196,6 +196,8 @@ out:
196 oi->typep = NULL;
197 if (oi->delta_base_oid)
198 oidclr(oi->delta_base_oid, loose->base.odb->repo->hash_algo);
199 + if (oi->source_infop && !ret)
200 + oi->source_infop->source = &loose->base;
201 if (!ret)
202 oi->whence = OI_LOOSE;
203 }
packfile.c
+12 -8
@@ -1324,7 +1324,7 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
1324 hashmap_add(&delta_base_cache, &ent->ent);
1325 }
1326
1327 -int packed_object_info_with_index_pos(struct odb_source_packed *source UNUSED,
1327 +int packed_object_info_with_index_pos(struct odb_source_packed *source,
1328 struct packed_git *p, off_t obj_offset,
1329 uint32_t *maybe_index_pos, struct object_info *oi)
1330 {
@@ -1423,22 +1423,26 @@ int packed_object_info_with_index_pos(struct odb_source_packed *source UNUSED,
1423
1424 oi->whence = OI_PACKED;
1425
1426 - if (oi->sourcep) {
1427 - oi->sourcep->u.packed.offset = obj_offset;
1428 - oi->sourcep->u.packed.pack = p;
1426 + if (oi->source_infop) {
1427 + if (!source)
1428 + BUG("cannot request source without an owning source");
1429 + oi->source_infop->source = &source->base;
1430 +
1431 + oi->source_infop->u.packed.offset = obj_offset;
1432 + oi->source_infop->u.packed.pack = p;
1433
1434 switch (type) {
1435 case OBJ_NONE:
1432 - oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_UNKNOWN;
1436 + oi->source_infop->u.packed.type = PACKED_OBJECT_TYPE_UNKNOWN;
1437 break;
1438 case OBJ_REF_DELTA:
1435 - oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_REF_DELTA;
1439 + oi->source_infop->u.packed.type = PACKED_OBJECT_TYPE_REF_DELTA;
1440 break;
1441 case OBJ_OFS_DELTA:
1438 - oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_OFS_DELTA;
1442 + oi->source_infop->u.packed.type = PACKED_OBJECT_TYPE_OFS_DELTA;
1443 break;
1444 default:
1441 - oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_FULL;
1445 + oi->source_infop->u.packed.type = PACKED_OBJECT_TYPE_FULL;
1446 break;
1447 }
1448 }
reachable.c
+4 -4
@@ -235,8 +235,8 @@ static int add_recent_object(const struct object_id *oid,
235 add_pending_object(data->revs, obj, "");
236 if (data->cb) {
237 if (oi->whence == OI_PACKED)
238 - data->cb(obj, oi->sourcep->u.packed.pack,
239 - oi->sourcep->u.packed.offset, *oi->mtimep);
238 + data->cb(obj, oi->source_infop->u.packed.pack,
239 + oi->source_infop->u.packed.offset, *oi->mtimep);
240 else
241 data->cb(obj, NULL, 0, *oi->mtimep);
242 }
@@ -253,11 +253,11 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,
253 unsigned flags;
254 enum object_type type;
255 time_t mtime;
256 - struct object_info_source oi_source;
256 + struct odb_source_info source_info;
257 struct object_info oi = {
258 .mtimep = &mtime,
259 .typep = &type,
260 - .sourcep = &oi_source,
260 + .source_infop = &source_info,
261 };
262 int r;
263