* [PATCH 0/6] odb: refactor source-specific information in object info
@ 2026-06-24 12:19 Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 1/6] packfile: thread odb_source_packed through packed_object_info() Patrick Steinhardt
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Patrick Steinhardt @ 2026-06-24 12:19 UTC (permalink / raw)
To: git
Hi,
this patch series refactors `struct object_info` to not contain the
`whence` field anymore.
This field only gave the caller information about the type of source
this was read from, but it didn't allow them to figure out which source
specifically yielded the object. So instead, we replace this information
with a new `struct object_info_source` field that both contains info
about the source, and any backend-specific data.
With this in place we can re-query the same backend for any given
object. More importantly though, we can eventually also use the backend-
specific data to also uniquely identify any given object, e.g. by
recording the packfile and offset, so that we can even yield the same
object in case one source contains the object multiple times.
Furthermore, with this change all information in `struct object_info` is
now following the same request-response-field style.
The series is built on top of 26d8d94e94 (A few more topics before -rc2,
2026-06-21) with ps/odb-source-packed at 1bba3c035d (odb/source-packed:
drop pointer to "files" parent source, 2026-06-17) merged into it.
Thanks!
Patrick
---
Patrick Steinhardt (6):
packfile: thread odb_source_packed through packed_object_info()
odb: make backend-specific fields optional
odb: add `source` field to struct object_info_source
treewide: convert users of `whence` to the new source field
odb: drop `whence` field from object info
odb: document object info fields
builtin/cat-file.c | 12 +++++---
builtin/index-pack.c | 9 ++++--
builtin/pack-objects.c | 19 ++++++++----
commit-graph.c | 2 +-
odb.c | 4 +--
odb.h | 80 +++++++++++++++++++++++++++++++++++---------------
odb/source-inmemory.c | 3 +-
odb/source-loose.c | 4 +--
odb/source-packed.c | 4 +--
pack-bitmap.c | 2 +-
packfile.c | 45 ++++++++++++++++------------
packfile.h | 6 ++--
reachable.c | 7 +++--
t/helper/test-bitmap.c | 2 +-
14 files changed, 130 insertions(+), 69 deletions(-)
---
base-commit: 969dbd51a70f9105ee9965adec5c5a02e75ab5b3
change-id: 20260612-b4-pks-odb-drop-whence-1b0af9ab16f4
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/6] packfile: thread odb_source_packed through packed_object_info()
2026-06-24 12:19 [PATCH 0/6] odb: refactor source-specific information in object info Patrick Steinhardt
@ 2026-06-24 12:19 ` Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 2/6] odb: make backend-specific fields optional Patrick Steinhardt
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Patrick Steinhardt @ 2026-06-24 12:19 UTC (permalink / raw)
To: git
Add an optional `struct odb_source_packed *source` parameter to
`packed_object_info()` and `packed_object_info_with_index_pos()`. This
parameter is unused at this point in time, but it will be used in a
follow-up commit so that we can record the source of a specific object.
Note that callers in "odb/source-packed.c" pass the already-available
source, but all other callers pass `NULL` instead. This is fine though,
as we only care about populating this info when called via the packed
store.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
builtin/cat-file.c | 2 +-
builtin/pack-objects.c | 4 ++--
commit-graph.c | 2 +-
odb/source-packed.c | 4 ++--
pack-bitmap.c | 2 +-
packfile.c | 8 +++++---
packfile.h | 6 ++++--
t/helper/test-bitmap.c | 2 +-
8 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 0f3dbd9850..8726485f1f 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -497,7 +497,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,
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index bc5f9ef321..620d9ce085 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.
@@ -3804,7 +3804,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) {
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/source-packed.c b/odb/source-packed.c
index 42c28fba0e..43fb53b72d 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 1d1b23b6cc..2b741d7a76 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 UNUSED,
+ struct packed_git *p, off_t obj_offset,
uint32_t *maybe_index_pos, struct object_info *oi)
{
struct pack_window *w_curs = NULL;
@@ -1446,10 +1447,11 @@ int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_offset,
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/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);
--
2.55.0.rc1.745.g43192e7977.dirty
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/6] odb: make backend-specific fields optional
2026-06-24 12:19 [PATCH 0/6] odb: refactor source-specific information in object info Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 1/6] packfile: thread odb_source_packed through packed_object_info() Patrick Steinhardt
@ 2026-06-24 12:19 ` Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 3/6] odb: add `source` field to struct object_info_source Patrick Steinhardt
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Patrick Steinhardt @ 2026-06-24 12:19 UTC (permalink / raw)
To: git
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>
---
builtin/cat-file.c | 8 +++++--
builtin/index-pack.c | 8 +++++--
builtin/pack-objects.c | 15 +++++++++----
odb.c | 3 ++-
odb.h | 60 +++++++++++++++++++++++++++++++++-----------------
packfile.c | 33 ++++++++++++++-------------
reachable.c | 5 ++++-
7 files changed, 87 insertions(+), 45 deletions(-)
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 8726485f1f..adc626ce30 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -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);
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index f396658468..77af26db8f 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -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) {
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 620d9ce085..9deb37e9e8 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -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 7d555be09f..99f4e7551c 100644
--- 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 3834a0dcbf..770900289a 100644
--- 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;
};
/*
diff --git a/packfile.c b/packfile.c
index 2b741d7a76..688c410b35 100644
--- a/packfile.c
+++ b/packfile.c
@@ -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;
diff --git a/reachable.c b/reachable.c
index 101cfc2727..2fc5b82d62 100644
--- a/reachable.c
+++ b/reachable.c
@@ -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;
--
2.55.0.rc1.745.g43192e7977.dirty
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/6] odb: add `source` field to struct object_info_source
2026-06-24 12:19 [PATCH 0/6] odb: refactor source-specific information in object info Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 1/6] packfile: thread odb_source_packed through packed_object_info() Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 2/6] odb: make backend-specific fields optional Patrick Steinhardt
@ 2026-06-24 12:19 ` Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 4/6] treewide: convert users of `whence` to the new source field Patrick Steinhardt
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Patrick Steinhardt @ 2026-06-24 12:19 UTC (permalink / raw)
To: git
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>
---
odb.h | 3 +++
odb/source-inmemory.c | 3 +++
odb/source-loose.c | 2 ++
packfile.c | 6 +++++-
4 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/odb.h b/odb.h
index 770900289a..330a55879e 100644
--- a/odb.h
+++ b/odb.h
@@ -253,6 +253,9 @@ int odb_pretend_object(struct object_database *odb,
* more about how exactly it is stored.
*/
struct object_info_source {
+ /* The source that this object has been looked up from. */
+ struct odb_source *source;
+
/*
* Backend-specific information about the specific object. This can be
* used for example to uniquely identify a given object in case it
diff --git a/odb/source-inmemory.c b/odb/source-inmemory.c
index e004566d76..2328e62687 100644
--- a/odb/source-inmemory.c
+++ b/odb/source-inmemory.c
@@ -52,6 +52,9 @@ static void populate_object_info(struct odb_source_inmemory *source,
*oi->contentp = xmemdupz(object->buf, object->size);
if (oi->mtimep)
*oi->mtimep = 0;
+ if (oi->sourcep)
+ oi->sourcep->source = &source->base;
+
oi->whence = OI_CACHED;
}
diff --git a/odb/source-loose.c b/odb/source-loose.c
index 66e6bb8d3f..5c4e9892b5 100644
--- a/odb/source-loose.c
+++ b/odb/source-loose.c
@@ -196,6 +196,8 @@ static int read_object_info_from_path(struct odb_source_loose *loose,
oi->typep = NULL;
if (oi->delta_base_oid)
oidclr(oi->delta_base_oid, loose->base.odb->repo->hash_algo);
+ if (oi->sourcep && !ret)
+ oi->sourcep->source = &loose->base;
if (!ret)
oi->whence = OI_LOOSE;
}
diff --git a/packfile.c b/packfile.c
index 688c410b35..fa22095b75 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1324,7 +1324,7 @@ 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 odb_source_packed *source UNUSED,
+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)
{
@@ -1424,6 +1424,10 @@ int packed_object_info_with_index_pos(struct odb_source_packed *source UNUSED,
oi->whence = OI_PACKED;
if (oi->sourcep) {
+ if (!source)
+ BUG("cannot request source without an owning source");
+ oi->sourcep->source = &source->base;
+
oi->sourcep->u.packed.offset = obj_offset;
oi->sourcep->u.packed.pack = p;
--
2.55.0.rc1.745.g43192e7977.dirty
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/6] treewide: convert users of `whence` to the new source field
2026-06-24 12:19 [PATCH 0/6] odb: refactor source-specific information in object info Patrick Steinhardt
` (2 preceding siblings ...)
2026-06-24 12:19 ` [PATCH 3/6] odb: add `source` field to struct object_info_source Patrick Steinhardt
@ 2026-06-24 12:19 ` Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 5/6] odb: drop `whence` field from object info Patrick Steinhardt
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Patrick Steinhardt @ 2026-06-24 12:19 UTC (permalink / raw)
To: git
The `whence` field has become redundant now that callers can learn about
the exact source an object has been looked up from via the `struct
object_info_source::source` field.
Adapt callers to use the new field. Note that all callsites already set
up the `info.sourcep` request pointer, so the conversion is rather
straight-forward.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
builtin/cat-file.c | 2 +-
builtin/index-pack.c | 3 ++-
builtin/pack-objects.c | 2 +-
reachable.c | 2 +-
4 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index adc626ce30..1b96150e5b 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -834,7 +834,7 @@ 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)
+ if (oi && oi->sourcep->source->type == ODB_SOURCE_PACKED)
return payload->callback(oid, oi->sourcep->u.packed.pack,
oi->sourcep->u.packed.offset,
payload->payload);
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 77af26db8f..1b03b07e5e 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1833,7 +1833,8 @@ static void repack_local_links(void)
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_source.u.packed.pack->pack_promisor)
+ if (info_source.source->type == ODB_SOURCE_PACKED &&
+ info_source.u.packed.pack->pack_promisor)
continue;
if (!cmd.args.nr) {
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 9deb37e9e8..d0fdfad750 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -5010,7 +5010,7 @@ static int is_not_in_promisor_pack_obj(struct object *obj, void *data UNUSED)
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_source.u.packed.pack->pack_promisor;
+ return info_source.source->type != ODB_SOURCE_PACKED || !info_source.u.packed.pack->pack_promisor;
}
static int is_not_in_promisor_pack(struct commit *commit, void *data) {
diff --git a/reachable.c b/reachable.c
index 2fc5b82d62..123a658944 100644
--- a/reachable.c
+++ b/reachable.c
@@ -234,7 +234,7 @@ static int add_recent_object(const struct object_id *oid,
add_pending_object(data->revs, obj, "");
if (data->cb) {
- if (oi->whence == OI_PACKED)
+ if (oi->sourcep->source->type == ODB_SOURCE_PACKED)
data->cb(obj, oi->sourcep->u.packed.pack,
oi->sourcep->u.packed.offset, *oi->mtimep);
else
--
2.55.0.rc1.745.g43192e7977.dirty
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 5/6] odb: drop `whence` field from object info
2026-06-24 12:19 [PATCH 0/6] odb: refactor source-specific information in object info Patrick Steinhardt
` (3 preceding siblings ...)
2026-06-24 12:19 ` [PATCH 4/6] treewide: convert users of `whence` to the new source field Patrick Steinhardt
@ 2026-06-24 12:19 ` Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 6/6] odb: document object info fields Patrick Steinhardt
2026-06-24 17:13 ` [PATCH 0/6] odb: refactor source-specific information in object info Junio C Hamano
6 siblings, 0 replies; 8+ messages in thread
From: Patrick Steinhardt @ 2026-06-24 12:19 UTC (permalink / raw)
To: git
In the preceding commits we have migrated all callers to derive their
information of how a specific object is stored to use the new object
info source instead, and hence the field is now unused. Drop it.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
odb.c | 1 -
odb.h | 7 -------
odb/source-inmemory.c | 2 --
odb/source-loose.c | 2 --
packfile.c | 2 --
5 files changed, 14 deletions(-)
diff --git a/odb.c b/odb.c
index 99f4e7551c..82c41f1793 100644
--- a/odb.c
+++ b/odb.c
@@ -691,7 +691,6 @@ static int oid_object_info_convert(struct repository *r,
return -1;
}
}
- input_oi->whence = new_oi.whence;
if (input_oi->sourcep)
*input_oi->sourcep = *new_oi.sourcep;
return ret;
diff --git a/odb.h b/odb.h
index 330a55879e..e0d05eaf87 100644
--- a/odb.h
+++ b/odb.h
@@ -311,13 +311,6 @@ struct object_info {
* or multiple times in the same source.
*/
struct object_info_source *sourcep;
-
- /* Response */
- enum {
- OI_CACHED,
- OI_LOOSE,
- OI_PACKED,
- } whence;
};
/*
diff --git a/odb/source-inmemory.c b/odb/source-inmemory.c
index 2328e62687..008e49bfe9 100644
--- a/odb/source-inmemory.c
+++ b/odb/source-inmemory.c
@@ -54,8 +54,6 @@ static void populate_object_info(struct odb_source_inmemory *source,
*oi->mtimep = 0;
if (oi->sourcep)
oi->sourcep->source = &source->base;
-
- oi->whence = OI_CACHED;
}
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 5c4e9892b5..e743ccab42 100644
--- a/odb/source-loose.c
+++ b/odb/source-loose.c
@@ -198,8 +198,6 @@ static int read_object_info_from_path(struct odb_source_loose *loose,
oidclr(oi->delta_base_oid, loose->base.odb->repo->hash_algo);
if (oi->sourcep && !ret)
oi->sourcep->source = &loose->base;
- if (!ret)
- oi->whence = OI_LOOSE;
}
return ret;
diff --git a/packfile.c b/packfile.c
index fa22095b75..4a8c108034 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1421,8 +1421,6 @@ int packed_object_info_with_index_pos(struct odb_source_packed *source,
oidclr(oi->delta_base_oid, p->repo->hash_algo);
}
- oi->whence = OI_PACKED;
-
if (oi->sourcep) {
if (!source)
BUG("cannot request source without an owning source");
--
2.55.0.rc1.745.g43192e7977.dirty
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 6/6] odb: document object info fields
2026-06-24 12:19 [PATCH 0/6] odb: refactor source-specific information in object info Patrick Steinhardt
` (4 preceding siblings ...)
2026-06-24 12:19 ` [PATCH 5/6] odb: drop `whence` field from object info Patrick Steinhardt
@ 2026-06-24 12:19 ` Patrick Steinhardt
2026-06-24 17:13 ` [PATCH 0/6] odb: refactor source-specific information in object info Junio C Hamano
6 siblings, 0 replies; 8+ messages in thread
From: Patrick Steinhardt @ 2026-06-24 12:19 UTC (permalink / raw)
To: git
Some of the fields in `struct object_info` are undocumented. Add these
missing comments.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
odb.h | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/odb.h b/odb.h
index e0d05eaf87..a44ec46b08 100644
--- a/odb.h
+++ b/odb.h
@@ -283,12 +283,28 @@ struct object_info_source {
} 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 {
- /* Request */
+ /* 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;
/*
--
2.55.0.rc1.745.g43192e7977.dirty
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 0/6] odb: refactor source-specific information in object info
2026-06-24 12:19 [PATCH 0/6] odb: refactor source-specific information in object info Patrick Steinhardt
` (5 preceding siblings ...)
2026-06-24 12:19 ` [PATCH 6/6] odb: document object info fields Patrick Steinhardt
@ 2026-06-24 17:13 ` Junio C Hamano
6 siblings, 0 replies; 8+ messages in thread
From: Junio C Hamano @ 2026-06-24 17:13 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: git
Patrick Steinhardt <ps@pks.im> writes:
> this patch series refactors `struct object_info` to not contain the
> `whence` field anymore.
>
> This field only gave the caller information about the type of source
> this was read from, but it didn't allow them to figure out which source
> specifically yielded the object. So instead, we replace this information
> with a new `struct object_info_source` field that both contains info
> about the source, and any backend-specific data.
Great.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-06-24 17:13 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-24 12:19 [PATCH 0/6] odb: refactor source-specific information in object info Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 1/6] packfile: thread odb_source_packed through packed_object_info() Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 2/6] odb: make backend-specific fields optional Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 3/6] odb: add `source` field to struct object_info_source Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 4/6] treewide: convert users of `whence` to the new source field Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 5/6] odb: drop `whence` field from object info Patrick Steinhardt
2026-06-24 12:19 ` [PATCH 6/6] odb: document object info fields Patrick Steinhardt
2026-06-24 17:13 ` [PATCH 0/6] odb: refactor source-specific information in object info Junio C Hamano
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox