]> git.ipfire.org Git - thirdparty/git.git/commitdiff
odb: make backend-specific fields optional
authorPatrick Steinhardt <ps@pks.im>
Wed, 24 Jun 2026 12:19:15 +0000 (14:19 +0200)
committerJunio C Hamano <gitster@pobox.com>
Wed, 24 Jun 2026 17:12:35 +0000 (10:12 -0700)
The `struct object_info` carries two pieces of information
about how an object was looked up:

  - The `whence` enum identifying the backend.

  - The backend-tagged union `u` exposing backend-specific details
    (currently only the packed-source case, which records the owning
    pack, offset and packed object type).

The union is populated unconditionally, even though most callers don't
care about provenance at all.

Split the backend-specific union out into a new public type, `struct
object_info_source`, and make the object info structure carry it via
just another opt-in request pointer. As with all the other requestable
information, callers that need source info allocate a `struct
object_info_source` on the stack and point `sourcep` at it; callers that
don't care about it simply leave the field as a `NULL` pointer. Adapt
callers accordingly.

Note that the `whence` enum is strictly-speaking also backend-specific
information, so it would be another good candidate to be moved into the
`struct object_info_source`. For now though it is left alone, as it will
be replaced by a `struct odb_source` pointer in a subsequent commit.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/cat-file.c
builtin/index-pack.c
builtin/pack-objects.c
odb.c
odb.h
packfile.c
reachable.c

index 8726485f1fef5a3270007a3638f9f11668a4a95d..adc626ce30ee330fcd61f8f85e005f6f697e27fc 100644 (file)
@@ -835,7 +835,8 @@ static int batch_one_object_oi(const struct object_id *oid,
 {
        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,
+               return payload->callback(oid, oi->sourcep->u.packed.pack,
+                                        oi->sourcep->u.packed.offset,
                                         payload->payload);
        return payload->callback(oid, NULL, 0, payload->payload);
 }
@@ -906,7 +907,10 @@ static void batch_each_object(struct batch_options *opt,
                                                &payload, flags);
                }
        } else {
-               struct object_info oi = { 0 };
+               struct object_info_source oi_source;
+               struct object_info oi = {
+                       .sourcep = &oi_source,
+               };
 
                for (source = the_repository->objects->sources; source; source = source->next) {
                        struct odb_source_files *files = odb_source_files_downcast(source);
index f396658468399022095f150d4a50bf225b57cd58..77af26db8fc0f34c6d985795861e20602439c7a3 100644 (file)
@@ -1825,11 +1825,15 @@ 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 object_info_source info_source;
+               struct object_info info = {
+                       .sourcep = &info_source,
+               };
+
                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 (info.whence == OI_PACKED && info_source.u.packed.pack->pack_promisor)
                        continue;
 
                if (!cmd.args.nr) {
index 620d9ce08508ccf94a00a1bc9471ec95dfce3bfa..9deb37e9e87efeeafe53b093c3e8a4d0bc8bec13 100644 (file)
@@ -4491,8 +4491,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->sourcep->u.packed.pack,
+                                      oi->sourcep->u.packed.offset, NULL,
+                                      *oi->mtimep);
        } else {
                add_object_entry(oid, OBJ_NONE, "", 0);
        }
@@ -4509,8 +4510,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 object_info_source oi_source;
        struct object_info oi = {
                .mtimep = &mtime,
+               .sourcep = &oi_source,
        };
 
        odb_prepare_alternates(to_pack.repo->objects);
@@ -5000,10 +5003,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 object_info_source info_source;
+       struct object_info info = {
+               .sourcep = &info_source,
+       };
+
        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 info.whence != OI_PACKED || !info_source.u.packed.pack->pack_promisor;
 }
 
 static int is_not_in_promisor_pack(struct commit *commit, void *data) {
diff --git a/odb.c b/odb.c
index 7d555be09feaea8932a7c58d02885d00f60a7234..99f4e7551c427432041e3f6800b7cda0a8ba296d 100644 (file)
--- a/odb.c
+++ b/odb.c
@@ -692,7 +692,8 @@ static int oid_object_info_convert(struct repository *r,
                }
        }
        input_oi->whence = new_oi.whence;
-       input_oi->u = new_oi.u;
+       if (input_oi->sourcep)
+               *input_oi->sourcep = *new_oi.sourcep;
        return ret;
 }
 
diff --git a/odb.h b/odb.h
index 3834a0dcbf033b576a13eb041439d7727329c890..770900289ab2170fe11357e363eab2078b97a065 100644 (file)
--- a/odb.h
+++ b/odb.h
@@ -248,6 +248,38 @@ int odb_pretend_object(struct object_database *odb,
                       void *buf, size_t len, enum object_type type,
                       struct object_id *oid);
 
+/*
+ * Object information that can be used to uniquely identify an object and learn
+ * more about how exactly it is stored.
+ */
+struct object_info_source {
+       /*
+        * 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.
+        */
+       union {
+               /*
+                * struct {
+                *      ... Nothing to expose in this case
+                * } cached;
+                * struct {
+                *      ... Nothing to expose in this case
+                * } loose;
+                */
+               struct {
+                       struct packed_git *pack;
+                       off_t offset;
+                       enum packed_object_type {
+                               PACKED_OBJECT_TYPE_UNKNOWN,
+                               PACKED_OBJECT_TYPE_FULL,
+                               PACKED_OBJECT_TYPE_OFS_DELTA,
+                               PACKED_OBJECT_TYPE_REF_DELTA,
+                       } type;
+               } packed;
+       } u;
+};
+
 struct object_info {
        /* Request */
        enum object_type *typep;
@@ -269,32 +301,20 @@ struct object_info {
         */
        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 object_info_source *sourcep;
+
        /* Response */
        enum {
                OI_CACHED,
                OI_LOOSE,
                OI_PACKED,
        } whence;
-       union {
-               /*
-                * struct {
-                *      ... Nothing to expose in this case
-                * } cached;
-                * struct {
-                *      ... Nothing to expose in this case
-                * } loose;
-                */
-               struct {
-                       struct packed_git *pack;
-                       off_t offset;
-                       enum packed_object_type {
-                               PACKED_OBJECT_TYPE_UNKNOWN,
-                               PACKED_OBJECT_TYPE_FULL,
-                               PACKED_OBJECT_TYPE_OFS_DELTA,
-                               PACKED_OBJECT_TYPE_REF_DELTA,
-                       } type;
-               } packed;
-       } u;
 };
 
 /*
index 2b741d7a7665e9804c13baf626edefeedf6618a5..688c410b35fc251dce7d679453ebdcab73cb95ea 100644 (file)
@@ -1422,22 +1422,25 @@ int packed_object_info_with_index_pos(struct odb_source_packed *source UNUSED,
        }
 
        oi->whence = OI_PACKED;
-       oi->u.packed.offset = obj_offset;
-       oi->u.packed.pack = p;
 
-       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;
+       if (oi->sourcep) {
+               oi->sourcep->u.packed.offset = obj_offset;
+               oi->sourcep->u.packed.pack = p;
+
+               switch (type) {
+               case OBJ_NONE:
+                       oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_UNKNOWN;
+                       break;
+               case OBJ_REF_DELTA:
+                       oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_REF_DELTA;
+                       break;
+               case OBJ_OFS_DELTA:
+                       oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_OFS_DELTA;
+                       break;
+               default:
+                       oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_FULL;
+                       break;
+               }
        }
 
        ret = 0;
index 101cfc272715fb5f2ace4cfc15bcbc3e2acb5903..2fc5b82d62658b66491a8189b535f53b2c172226 100644 (file)
@@ -235,7 +235,8 @@ 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);
+                       data->cb(obj, oi->sourcep->u.packed.pack,
+                                oi->sourcep->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 object_info_source oi_source;
        struct object_info oi = {
                .mtimep = &mtime,
                .typep = &type,
+               .sourcep = &oi_source,
        };
        int r;