streaming: propagate final object type via the stream

When opening the read stream for a specific object the caller is also expected to pass in a pointer to the object type. This type is passed down via multiple levels and will eventually be populated with the type of the looked-up object. The way we propagate down the pointer though is somewhat non-obvious. While `istream_source()` still expects the pointer and looks it up via `odb_read_object_info_extended()`, we also pass it down even further into the format-specific callbacks that perform another lookup. This is quite confusing overall. Refactor the code so that the responsibility to populate the object type rests solely with the format-specific callbacks. This will allow us to drop the call to `odb_read_object_info_extended()` in `istream_source()` entirely in a subsequent patch. Furthermore, instead of propagating the type via an in-pointer, we now propagate the type via a new field in the object stream. It already has a `size` field, so it's only natural to have a second field that contains the object type. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Nov 23, 2025 at 19:59 UTC 3f64deabdf0a2a9664acec61698affc449e07496
1 file changed +15 -15
streaming.c
+15 -15
@@ -33,6 +33,7 @@ struct odb_read_stream {
33 close_istream_fn close;
34 read_istream_fn read;
35
36 + enum object_type type;
37 unsigned long size; /* inflated size of full object */
38 git_zstream z;
39 enum { z_unused, z_used, z_done, z_error } z_state;
@@ -159,6 +160,7 @@ static struct odb_read_stream *attach_stream_filter(struct odb_read_stream *st,
160 fs->o_end = fs->o_ptr = 0;
161 fs->input_finished = 0;
162 ifs->size = -1; /* unknown */
163 + ifs->type = st->type;
164 return ifs;
165 }
166
@@ -221,14 +223,13 @@ static int close_istream_loose(struct odb_read_stream *st)
223 }
224
225 static int open_istream_loose(struct odb_read_stream *st, struct repository *r,
224 - const struct object_id *oid,
225 - enum object_type *type)
226 + const struct object_id *oid)
227 {
228 struct object_info oi = OBJECT_INFO_INIT;
229 struct odb_source *source;
230
231 oi.sizep = &st->size;
231 - oi.typep = type;
232 + oi.typep = &st->type;
233
234 odb_prepare_alternates(r->objects);
235 for (source = r->objects->sources; source; source = source->next) {
@@ -249,7 +250,7 @@ static int open_istream_loose(struct odb_read_stream *st, struct repository *r,
250 case ULHR_TOO_LONG:
251 goto error;
252 }
252 - if (parse_loose_header(st->u.loose.hdr, &oi) < 0 || *type < 0)
253 + if (parse_loose_header(st->u.loose.hdr, &oi) < 0 || st->type < 0)
254 goto error;
255
256 st->u.loose.hdr_used = strlen(st->u.loose.hdr) + 1;
@@ -339,8 +340,7 @@ static int close_istream_pack_non_delta(struct odb_read_stream *st)
340
341 static int open_istream_pack_non_delta(struct odb_read_stream *st,
342 struct repository *r UNUSED,
342 - const struct object_id *oid UNUSED,
343 - enum object_type *type UNUSED)
343 + const struct object_id *oid UNUSED)
344 {
345 struct pack_window *window;
346 enum object_type in_pack_type;
@@ -361,6 +361,7 @@ static int open_istream_pack_non_delta(struct odb_read_stream *st,
361 case OBJ_TAG:
362 break;
363 }
364 + st->type = in_pack_type;
365 st->z_state = z_unused;
366 st->close = close_istream_pack_non_delta;
367 st->read = read_istream_pack_non_delta;
@@ -396,7 +397,7 @@ static ssize_t read_istream_incore(struct odb_read_stream *st, char *buf, size_t
397 }
398
399 static int open_istream_incore(struct odb_read_stream *st, struct repository *r,
399 - const struct object_id *oid, enum object_type *type)
400 + const struct object_id *oid)
401 {
402 struct object_info oi = OBJECT_INFO_INIT;
403
@@ -404,7 +405,7 @@ static int open_istream_incore(struct odb_read_stream *st, struct repository *r,
405 st->close = close_istream_incore;
406 st->read = read_istream_incore;
407
407 - oi.typep = type;
408 + oi.typep = &st->type;
409 oi.sizep = &st->size;
410 oi.contentp = (void **)&st->u.incore.buf;
411 return odb_read_object_info_extended(r->objects, oid, &oi,
@@ -417,14 +418,12 @@ static int open_istream_incore(struct odb_read_stream *st, struct repository *r,
418
419 static int istream_source(struct odb_read_stream *st,
420 struct repository *r,
420 - const struct object_id *oid,
421 - enum object_type *type)
421 + const struct object_id *oid)
422 {
423 unsigned long size;
424 int status;
425 struct object_info oi = OBJECT_INFO_INIT;
426
427 - oi.typep = type;
427 oi.sizep = &size;
428 status = odb_read_object_info_extended(r->objects, oid, &oi, 0);
429 if (status < 0)
@@ -432,7 +431,7 @@ static int istream_source(struct odb_read_stream *st,
431
432 switch (oi.whence) {
433 case OI_LOOSE:
435 - if (open_istream_loose(st, r, oid, type) < 0)
434 + if (open_istream_loose(st, r, oid) < 0)
435 break;
436 return 0;
437 case OI_PACKED:
@@ -442,7 +441,7 @@ static int istream_source(struct odb_read_stream *st,
441
442 st->u.in_pack.pack = oi.u.packed.pack;
443 st->u.in_pack.pos = oi.u.packed.offset;
445 - if (open_istream_pack_non_delta(st, r, oid, type) < 0)
444 + if (open_istream_pack_non_delta(st, r, oid) < 0)
445 break;
446
447 return 0;
@@ -450,7 +449,7 @@ static int istream_source(struct odb_read_stream *st,
449 break;
450 }
451
453 - return open_istream_incore(st, r, oid, type);
452 + return open_istream_incore(st, r, oid);
453 }
454
455 /****************************************************************
@@ -477,7 +476,7 @@ struct odb_read_stream *open_istream(struct repository *r,
476 {
477 struct odb_read_stream *st = xmalloc(sizeof(*st));
478 const struct object_id *real = lookup_replace_object(r, oid);
480 - int ret = istream_source(st, r, real, type);
479 + int ret = istream_source(st, r, real);
480
481 if (ret) {
482 free(st);
@@ -495,6 +494,7 @@ struct odb_read_stream *open_istream(struct repository *r,
494 }
495
496 *size = st->size;
497 + *type = st->type;
498 return st;
499 }
500