From: Patrick Steinhardt Date: Mon, 03 Nov 2025 07:41:55 GMT Subject: [PATCH v3 00/13] Carve out loose object source Message-ID: <20251103-b4-pks-odb-loose-backend-v3-0-6a61ea977393@pks.im> In-Reply-To: <20251024-b4-pks-odb-loose-backend-v1-0-1a4202273c38@pks.im> Hi, this patch series carves out loose object sources. The idea is to store all data that relates to loose objects in a single structure, similar to our `struct packfile_store`. The series is structured as follows: - Patches 1 to 4 perform some cleanups in the vicinity of object databases. - Patches 5 to 8 create a new `struct source_loose` and move all state that is specific to loose objects into it. - Patches 9 to 13 then adjust functions to work on top of that new structure. The motivation here is to make handling of loose objects completely self-contained as a step towards pluggable object databases. Changes in v3: - Rename `struct odb_loose_source` to `odb_source_loose`. Adjust its functions accordingly. - Link to v2: https://lore.kernel.org/r/20251031-b4-pks-odb-loose-backend-v2-0-920f721aef71@pks.im Changes in v2: - Rename `sturct odb_loose_source *` arguments from `source` to `loose`. - Some commit message improvements. - Link to v1: https://lore.kernel.org/r/20251024-b4-pks-odb-loose-backend-v1-0-1a4202273c38@pks.im Thanks! Patrick --- Patrick Steinhardt (13): odb: fix subtle logic to check whether an alternate is usable odb: introduce `odb_source_new()` odb: adjust naming to free object sources object-file: move `fetch_if_missing` object-file: introduce `struct odb_source_loose` object-file: move loose object cache into loose source object-file: hide internals when we need to reprepare loose sources object-file: move loose object map into loose source object-file: read objects via the loose object source object-file: rename `has_loose_object()` object-file: refactor freshening of objects object-file: rename `write_object_file()` object-file: refactor writing objects via a stream builtin/pack-objects.c | 4 +- builtin/unpack-objects.c | 7 +- loose.c | 19 ++--- object-file.c | 175 +++++++++++++++++++++-------------------------- object-file.h | 98 ++++++++++++++------------ object-name.c | 2 +- odb.c | 104 +++++++++++++++++++--------- odb.h | 41 +++++++---- packfile.c | 16 +++++ packfile.h | 3 + repository.c | 14 ++-- streaming.c | 11 ++- 12 files changed, 287 insertions(+), 207 deletions(-) Range-diff versus v2: 1: 330b7c17e6a = 1: ed548a7ee4e odb: fix subtle logic to check whether an alternate is usable 2: 68b2e736d20 = 2: 59d5548ddfa odb: introduce `odb_source_new()` 3: b6f9a3f6d26 = 3: a417bd30153 odb: adjust naming to free object sources 4: fe38c58ab20 = 4: add2b7d112f object-file: move `fetch_if_missing` 5: 5fed6e7c429 ! 5: 5245ba0c6a5 object-file: introduce `struct odb_loose_source` @@ Metadata Author: Patrick Steinhardt ## Commit message ## - object-file: introduce `struct odb_loose_source` + object-file: introduce `struct odb_source_loose` Currently, all state that relates to loose objects is held directly by - the `struct odb_source`. Introduce a new `struct odb_loose_source` to + the `struct odb_source`. Introduce a new `struct odb_source_loose` to hold the state instead so that it is entirely self-contained. This structure will eventually morph into the backend for accessing @@ object-file.c: void object_file_transaction_commit(struct odb_transaction *trans free(transaction); } + -+struct odb_loose_source *odb_loose_source_new(struct odb_source *source) ++struct odb_source_loose *odb_source_loose_new(struct odb_source *source) +{ -+ struct odb_loose_source *loose; ++ struct odb_source_loose *loose; + CALLOC_ARRAY(loose, 1); + loose->source = source; + return loose; +} + -+void odb_loose_source_free(struct odb_loose_source *loose) ++void odb_source_loose_free(struct odb_source_loose *loose) +{ + free(loose); +} @@ object-file.h: int index_path(struct index_state *istate, struct object_id *oid, struct odb_source; -+struct odb_loose_source { ++struct odb_source_loose { + struct odb_source *source; +}; + -+struct odb_loose_source *odb_loose_source_new(struct odb_source *source); -+void odb_loose_source_free(struct odb_loose_source *loose); ++struct odb_source_loose *odb_source_loose_new(struct odb_source *source); ++void odb_source_loose_free(struct odb_source_loose *loose); + /* * Populate and return the loose object cache array corresponding to the @@ odb.c: struct odb_source *odb_source_new(struct object_database *odb, source->odb = odb; source->local = local; source->path = xstrdup(path); -+ source->loose = odb_loose_source_new(source); ++ source->loose = odb_source_loose_new(source); return source; } @@ odb.c: struct odb_source *odb_set_temporary_primary_source(struct object_databas static void odb_source_free(struct odb_source *source) { free(source->path); -+ odb_loose_source_free(source->loose); ++ odb_source_loose_free(source->loose); odb_clear_loose_cache(source); loose_object_map_clear(&source->loose_map); free(source); @@ odb.h: struct odb_source { struct object_database *odb; + /* Private state for loose objects. */ -+ struct odb_loose_source *loose; ++ struct odb_source_loose *loose; + /* * Used to store the results of readdir(3) calls when we are OK 6: a66851a6afd ! 6: 3d931e4929d object-file: move loose object cache into loose source @@ Commit message Our loose objects use a cache that (optionally) stores all objects for each of the opened sharding directories. This cache is located in the - `struct odb_source`, but now that we have `struct odb_loose_source` it + `struct odb_source`, but now that we have `struct odb_source_loose` it makes sense to move it into the latter structure so that all state that relates to loose objects is entirely self-contained. Do so. While at it, rename corresponding functions to have a prefix that - relates to `struct odb_loose_source`. + relates to `struct odb_source_loose`. Note that despite this prefix, the functions still accept a `struct odb_source` as input. This is done intentionally: once we introduce pluggable object databases, we will continue to accept this struct but - then do a cast inside these functions to `struct odb_loose_source`. This + then do a cast inside these functions to `struct odb_source_loose`. This design is similar to how we do it for our ref backends. Signed-off-by: Patrick Steinhardt @@ object-file.c: static int quick_has_loose(struct repository *r, odb_prepare_alternates(r->objects); for (source = r->objects->sources; source; source = source->next) { - if (oidtree_contains(odb_loose_cache(source, oid), oid)) -+ if (oidtree_contains(odb_loose_source_cache(source, oid), oid)) ++ if (oidtree_contains(odb_source_loose_cache(source, oid), oid)) return 1; } return 0; @@ object-file.c: static int append_loose_object(const struct object_id *oid, -struct oidtree *odb_loose_cache(struct odb_source *source, - const struct object_id *oid) -+struct oidtree *odb_loose_source_cache(struct odb_source *source, ++struct oidtree *odb_source_loose_cache(struct odb_source *source, + const struct object_id *oid) { int subdir_nr = oid->hash[0]; @@ object-file.c: static int append_loose_object(const struct object_id *oid, } static int check_stream_oid(git_zstream *stream, -@@ object-file.c: struct odb_loose_source *odb_loose_source_new(struct odb_source *source) +@@ object-file.c: struct odb_source_loose *odb_source_loose_new(struct odb_source *source) - void odb_loose_source_free(struct odb_loose_source *loose) + void odb_source_loose_free(struct odb_source_loose *loose) { + if (!loose) + return; @@ object-file.c: struct odb_loose_source *odb_loose_source_new(struct odb_source * ## object-file.h ## @@ object-file.h: struct odb_source; - struct odb_loose_source { + struct odb_source_loose { struct odb_source *source; + + /* @@ object-file.h: struct odb_source; + struct oidtree *cache; }; - struct odb_loose_source *odb_loose_source_new(struct odb_source *source); -@@ object-file.h: void odb_loose_source_free(struct odb_loose_source *loose); + struct odb_source_loose *odb_source_loose_new(struct odb_source *source); +@@ object-file.h: void odb_source_loose_free(struct odb_source_loose *loose); * Populate and return the loose object cache array corresponding to the * given object ID. */ -struct oidtree *odb_loose_cache(struct odb_source *source, - const struct object_id *oid); -+struct oidtree *odb_loose_source_cache(struct odb_source *source, ++struct oidtree *odb_source_loose_cache(struct odb_source *source, + const struct object_id *oid); /* Empty the loose object cache for the specified object directory. */ @@ object-name.c: static void find_short_object_filename(struct disambiguate_state for (source = ds->repo->objects->sources; source && !ds->ambiguous; source = source->next) - oidtree_each(odb_loose_cache(source, &ds->bin_pfx), -+ oidtree_each(odb_loose_source_cache(source, &ds->bin_pfx), ++ oidtree_each(odb_source_loose_cache(source, &ds->bin_pfx), &ds->bin_pfx, ds->len, match_prefix, ds); } @@ odb.c @@ odb.c: static void odb_source_free(struct odb_source *source) { free(source->path); - odb_loose_source_free(source->loose); + odb_source_loose_free(source->loose); - odb_clear_loose_cache(source); loose_object_map_clear(&source->loose_map); free(source); @@ odb.c: static void odb_source_free(struct odb_source *source) ## odb.h ## @@ odb.h: struct odb_source { /* Private state for loose objects. */ - struct odb_loose_source *loose; + struct odb_source_loose *loose; - /* - * Used to store the results of readdir(3) calls when we are OK 7: ac94974a4b4 ! 7: 6eb525fa775 object-file: hide internals when we need to reprepare loose sources @@ Commit message - When repreparing the loose object source so that any potentially- stale data is getting evicted from the cache. - The former is already handled by `odb_loose_source_free()`. But the + The former is already handled by `odb_source_loose_free()`. But the latter case is still done manually by in `odb_reprepare()`, so we are leaking internals into that code. - Introduce a new `odb_loose_source_reprepare()` function as an equivalent + Introduce a new `odb_source_loose_reprepare()` function as an equivalent to `packfile_store_prepare()` to hide these implementation details. Furthermore, while at it, rename the function `odb_clear_loose_cache()` - to `odb_loose_source_clear()`. + to `odb_source_loose_clear()`. Signed-off-by: Patrick Steinhardt ## object-file.c ## -@@ object-file.c: struct oidtree *odb_loose_source_cache(struct odb_source *source, +@@ object-file.c: struct oidtree *odb_source_loose_cache(struct odb_source *source, return source->loose->cache; } -void odb_clear_loose_cache(struct odb_source *source) -+static void odb_loose_source_clear_cache(struct odb_loose_source *loose) ++static void odb_source_loose_clear_cache(struct odb_source_loose *loose) { - oidtree_clear(source->loose->cache); - FREE_AND_NULL(source->loose->cache); @@ object-file.c: struct oidtree *odb_loose_source_cache(struct odb_source *source, + sizeof(loose->subdir_seen)); +} + -+void odb_loose_source_reprepare(struct odb_source *source) ++void odb_source_loose_reprepare(struct odb_source *source) +{ -+ odb_loose_source_clear_cache(source->loose); ++ odb_source_loose_clear_cache(source->loose); } static int check_stream_oid(git_zstream *stream, -@@ object-file.c: void odb_loose_source_free(struct odb_loose_source *loose) +@@ object-file.c: void odb_source_loose_free(struct odb_source_loose *loose) { if (!loose) return; - odb_clear_loose_cache(loose->source); -+ odb_loose_source_clear_cache(loose); ++ odb_source_loose_clear_cache(loose); free(loose); } ## object-file.h ## -@@ object-file.h: struct odb_loose_source { - struct odb_loose_source *odb_loose_source_new(struct odb_source *source); - void odb_loose_source_free(struct odb_loose_source *loose); +@@ object-file.h: struct odb_source_loose { + struct odb_source_loose *odb_source_loose_new(struct odb_source *source); + void odb_source_loose_free(struct odb_source_loose *loose); +/* Reprepare the loose source by emptying the loose object cache. */ -+void odb_loose_source_reprepare(struct odb_source *source); ++void odb_source_loose_reprepare(struct odb_source *source); + /* * Populate and return the loose object cache array corresponding to the * given object ID. -@@ object-file.h: void odb_loose_source_free(struct odb_loose_source *loose); - struct oidtree *odb_loose_source_cache(struct odb_source *source, +@@ object-file.h: void odb_source_loose_free(struct odb_source_loose *loose); + struct oidtree *odb_source_loose_cache(struct odb_source *source, const struct object_id *oid); -/* Empty the loose object cache for the specified object directory. */ @@ odb.c: void odb_reprepare(struct object_database *o) for (source = o->sources; source; source = source->next) - odb_clear_loose_cache(source); -+ odb_loose_source_reprepare(source); ++ odb_source_loose_reprepare(source); o->approximate_object_count_valid = 0; 8: 8820c59b0d1 ! 8: f5aff5356f1 object-file: move loose object map into loose source @@ loose.c: int repo_loose_object_map_oid(struct repository *repo, map = (to == repo->compat_hash_algo) ? ## object-file.c ## -@@ object-file.c: void odb_loose_source_free(struct odb_loose_source *loose) +@@ object-file.c: void odb_source_loose_free(struct odb_source_loose *loose) if (!loose) return; - odb_loose_source_clear_cache(loose); + odb_source_loose_clear_cache(loose); + loose_object_map_clear(&loose->map); free(loose); } ## object-file.h ## -@@ object-file.h: struct odb_loose_source { +@@ object-file.h: struct odb_source_loose { */ uint32_t subdir_seen[8]; /* 256 bits */ struct oidtree *cache; @@ object-file.h: struct odb_loose_source { + struct loose_object_map *map; }; - struct odb_loose_source *odb_loose_source_new(struct odb_source *source); + struct odb_source_loose *odb_source_loose_new(struct odb_source *source); ## odb.c ## @@ odb.c: static void odb_source_free(struct odb_source *source) { free(source->path); - odb_loose_source_free(source->loose); + odb_source_loose_free(source->loose); - loose_object_map_clear(&source->loose_map); free(source); } @@ odb.c: static void odb_source_free(struct odb_source *source) ## odb.h ## @@ odb.h: struct odb_source { /* Private state for loose objects. */ - struct odb_loose_source *loose; + struct odb_source_loose *loose; - /* Map between object IDs for loose objects. */ - struct loose_object_map *loose_map; 9: 0a549d59861 ! 9: 2e328d81928 object-file: read objects via the loose object source @@ object-file.c: int stream_object_signature(struct repository *r, const struct ob * call to stat_loose_object(). */ -static int stat_loose_object(struct repository *r, const struct object_id *oid, -+static int stat_loose_object(struct odb_loose_source *loose, ++static int stat_loose_object(struct odb_source_loose *loose, + const struct object_id *oid, struct stat *st, const char **path) { @@ object-file.c: static int stat_loose_object(struct repository *r, const struct o * descriptor. See the caveats on the "path" parameter above. */ -static int open_loose_object(struct repository *r, -+static int open_loose_object(struct odb_loose_source *loose, ++static int open_loose_object(struct odb_source_loose *loose, const struct object_id *oid, const char **path) { - int fd; @@ object-file.c: static int stat_loose_object(struct repository *r, const struct o } -static int quick_has_loose(struct repository *r, -+static int quick_has_loose(struct odb_loose_source *loose, ++static int quick_has_loose(struct odb_source_loose *loose, const struct object_id *oid) { - struct odb_source *source; - - odb_prepare_alternates(r->objects); - for (source = r->objects->sources; source; source = source->next) { -- if (oidtree_contains(odb_loose_source_cache(source, oid), oid)) +- if (oidtree_contains(odb_source_loose_cache(source, oid), oid)) - return 1; - } - return 0; -+ return !!oidtree_contains(odb_loose_source_cache(loose->source, oid), oid); ++ return !!oidtree_contains(odb_source_loose_cache(loose->source, oid), oid); } /* @@ object-file.c: static void *map_fd(int fd, const char *path, unsigned long *size -void *map_loose_object(struct repository *r, - const struct object_id *oid, - unsigned long *size) -+void *odb_loose_source_map_object(struct odb_source *source, ++void *odb_source_loose_map_object(struct odb_source *source, + const struct object_id *oid, + unsigned long *size) { @@ object-file.c: int parse_loose_header(const char *hdr, struct object_info *oi) -int loose_object_info(struct repository *r, - const struct object_id *oid, - struct object_info *oi, int flags) -+int odb_loose_source_read_object_info(struct odb_source *source, ++int odb_source_loose_read_object_info(struct odb_source *source, + const struct object_id *oid, + struct object_info *oi, int flags) { @@ object-file.c: int loose_object_info(struct repository *r, error_errno(_("unable to open loose object %s"), oid_to_hex(oid)); ## object-file.h ## -@@ object-file.h: void odb_loose_source_free(struct odb_loose_source *loose); +@@ object-file.h: void odb_source_loose_free(struct odb_source_loose *loose); /* Reprepare the loose source by emptying the loose object cache. */ - void odb_loose_source_reprepare(struct odb_source *source); + void odb_source_loose_reprepare(struct odb_source *source); -+int odb_loose_source_read_object_info(struct odb_source *source, ++int odb_source_loose_read_object_info(struct odb_source *source, + const struct object_id *oid, + struct object_info *oi, int flags); + -+void *odb_loose_source_map_object(struct odb_source *source, ++void *odb_source_loose_map_object(struct odb_source *source, + const struct object_id *oid, + unsigned long *size); + @@ odb.c: static int do_oid_object_info_extended(struct object_database *odb, - if (!loose_object_info(odb->repo, real, oi, flags)) - return 0; + for (source = odb->sources; source; source = source->next) -+ if (!odb_loose_source_read_object_info(source, real, oi, flags)) ++ if (!odb_source_loose_read_object_info(source, real, oi, flags)) + return 0; /* Not a loose object; someone else may have just packed it. */ @@ streaming.c: static int open_istream_loose(struct git_istream *st, struct reposi - st->u.loose.mapped = map_loose_object(r, oid, &st->u.loose.mapsize); + odb_prepare_alternates(r->objects); + for (source = r->objects->sources; source; source = source->next) { -+ st->u.loose.mapped = odb_loose_source_map_object(source, oid, ++ st->u.loose.mapped = odb_source_loose_map_object(source, oid, + &st->u.loose.mapsize); + if (st->u.loose.mapped) + break; 10: bcc58f6f7e5 ! 10: 29787a709b3 object-file: rename `has_loose_object()` @@ Metadata ## Commit message ## object-file: rename `has_loose_object()` - Rename `has_loose_object()` to `odb_loose_source_has_object()` so that + Rename `has_loose_object()` to `odb_source_loose_has_object()` so that it becomes clear that this is tied to a specific loose object source. This matches our modern naming schema for functions. @@ builtin/pack-objects.c: static int want_object_in_pack_mtime(const struct object struct odb_source *source = the_repository->objects->sources->next; for (; source; source = source->next) - if (has_loose_object(source, oid)) -+ if (odb_loose_source_has_object(source, oid)) ++ if (odb_source_loose_has_object(source, oid)) return 0; } @@ builtin/pack-objects.c: static void add_cruft_object_entry(const struct object_i for (; !found && source; source = source->next) - if (has_loose_object(source, oid)) -+ if (odb_loose_source_has_object(source, oid)) ++ if (odb_source_loose_has_object(source, oid)) found = 1; /* @@ object-file.c: static int check_and_freshen_source(struct odb_source *source, -int has_loose_object(struct odb_source *source, - const struct object_id *oid) -+int odb_loose_source_has_object(struct odb_source *source, ++int odb_source_loose_has_object(struct odb_source *source, + const struct object_id *oid) { return check_and_freshen_source(source, oid, 0); @@ object-file.c: int force_object_loose(struct odb_source *source, for (struct odb_source *s = source->odb->sources; s; s = s->next) - if (has_loose_object(s, oid)) -+ if (odb_loose_source_has_object(s, oid)) ++ if (odb_source_loose_has_object(s, oid)) return 0; oi.typep = &type; ## object-file.h ## -@@ object-file.h: void *odb_loose_source_map_object(struct odb_source *source, +@@ object-file.h: void *odb_source_loose_map_object(struct odb_source *source, const struct object_id *oid, unsigned long *size); @@ object-file.h: void *odb_loose_source_map_object(struct odb_source *source, + * with the specified name. This function does not respect replace + * references. + */ -+int odb_loose_source_has_object(struct odb_source *source, ++int odb_source_loose_has_object(struct odb_source *source, + const struct object_id *oid); + /* 11: 60a5e4882cd ! 11: 3b95f712fb4 object-file: refactor freshening of objects @@ Commit message Introduce a new `odb_freshen_object()` function that sits on the object database level and two functions `packfile_store_freshen_object()` and - `odb_loose_source_freshen_object()`. Like this, the format-specific + `odb_source_loose_freshen_object()`. Like this, the format-specific functions can be part of their respective subsystems, while the backend agnostic function to freshen an object sits at the object database layer. @@ object-file.c: static int write_loose_object(struct odb_source *source, -static int freshen_loose_object(struct object_database *odb, - const struct object_id *oid) -+int odb_loose_source_freshen_object(struct odb_source *source, ++int odb_source_loose_freshen_object(struct odb_source *source, + const struct object_id *oid) { - odb_prepare_alternates(odb); @@ object-file.c: int write_object_file(struct odb_source *source, return -1; ## object-file.h ## -@@ object-file.h: void *odb_loose_source_map_object(struct odb_source *source, - int odb_loose_source_has_object(struct odb_source *source, +@@ object-file.h: void *odb_source_loose_map_object(struct odb_source *source, + int odb_source_loose_has_object(struct odb_source *source, const struct object_id *oid); -+int odb_loose_source_freshen_object(struct odb_source *source, ++int odb_source_loose_freshen_object(struct odb_source *source, + const struct object_id *oid); + /* @@ odb.c: int odb_has_object(struct object_database *odb, const struct object_id *o + + odb_prepare_alternates(odb); + for (source = odb->sources; source; source = source->next) -+ if (odb_loose_source_freshen_object(source, oid)) ++ if (odb_source_loose_freshen_object(source, oid)) + return 1; + + return 0; 12: d31eec55aec ! 12: 31970221960 object-file: rename `write_object_file()` @@ Metadata ## Commit message ## object-file: rename `write_object_file()` - Rename `write_object_file()` to `odb_loose_source_write_object()` so + Rename `write_object_file()` to `odb_source_loose_write_object()` so that it becomes clear that this is tied to a specific loose object source. This matches our modern naming schema for functions. @@ object-file.c: int stream_loose_object(struct odb_source *source, - const void *buf, unsigned long len, - enum object_type type, struct object_id *oid, - struct object_id *compat_oid_in, unsigned flags) -+int odb_loose_source_write_object(struct odb_source *source, ++int odb_source_loose_write_object(struct odb_source *source, + const void *buf, unsigned long len, + enum object_type type, struct object_id *oid, + struct object_id *compat_oid_in, unsigned flags) @@ object-file.c: int stream_loose_object(struct odb_source *source, const struct git_hash_algo *compat = source->odb->repo->compat_hash_algo; ## object-file.h ## -@@ object-file.h: int odb_loose_source_has_object(struct odb_source *source, - int odb_loose_source_freshen_object(struct odb_source *source, +@@ object-file.h: int odb_source_loose_has_object(struct odb_source *source, + int odb_source_loose_freshen_object(struct odb_source *source, const struct object_id *oid); -+int odb_loose_source_write_object(struct odb_source *source, ++int odb_source_loose_write_object(struct odb_source *source, + const void *buf, unsigned long len, + enum object_type type, struct object_id *oid, + struct object_id *compat_oid_in, unsigned flags); @@ odb.c: int odb_write_object_ext(struct object_database *odb, unsigned flags) { - return write_object_file(odb->sources, buf, len, type, oid, compat_oid, flags); -+ return odb_loose_source_write_object(odb->sources, buf, len, type, ++ return odb_source_loose_write_object(odb->sources, buf, len, type, + oid, compat_oid, flags); } 13: 84fbe7758d0 ! 13: cec069fd2df object-file: refactor writing objects via a stream @@ Commit message have to be aware of the inner workings of how to stream an object to disk with a specific object source. - Rename `stream_loose_object()` to `odb_loose_source_write_stream()` to + Rename `stream_loose_object()` to `odb_source_loose_write_stream()` to clarify its scope. This matches our modern best practices around how to name functions. @@ builtin/unpack-objects.c: static void stream_blob(unsigned long size, unsigned n if (data.status != Z_STREAM_END) ## object-file.c ## -@@ object-file.c: int odb_loose_source_freshen_object(struct odb_source *source, +@@ object-file.c: int odb_source_loose_freshen_object(struct odb_source *source, return !!check_and_freshen_source(source, oid, 1); } -int stream_loose_object(struct odb_source *source, - struct input_stream *in_stream, size_t len, - struct object_id *oid) -+int odb_loose_source_write_stream(struct odb_source *source, ++int odb_source_loose_write_stream(struct odb_source *source, + struct odb_write_stream *in_stream, size_t len, + struct object_id *oid) { @@ object-file.c: int odb_loose_source_freshen_object(struct odb_source *source, struct object_id compat_oid; ## object-file.h ## -@@ object-file.h: int odb_loose_source_write_object(struct odb_source *source, +@@ object-file.h: int odb_source_loose_write_object(struct odb_source *source, enum object_type type, struct object_id *oid, struct object_id *compat_oid_in, unsigned flags); -+int odb_loose_source_write_stream(struct odb_source *source, ++int odb_source_loose_write_stream(struct odb_source *source, + struct odb_write_stream *stream, size_t len, + struct object_id *oid); + @@ odb.c: int odb_write_object_ext(struct object_database *odb, + struct odb_write_stream *stream, size_t len, + struct object_id *oid) +{ -+ return odb_loose_source_write_stream(odb->sources, stream, len, oid); ++ return odb_source_loose_write_stream(odb->sources, stream, len, oid); +} + struct object_database *odb_new(struct repository *repo) --- base-commit: c54a18ef67e59cdbcd77d6294916d42c98c62d1d change-id: 20251017-b4-pks-odb-loose-backend-b1e003c41107