From: Justin Tobler Date: Thu, 29 Oct 2026 23:22:18 GMT Subject: [PATCH v3 2/4] loose: lift loose object index parsing logic into helper Message-ID: <20261029232220.1245827-3-jltobler@gmail.com> In-Reply-To: <20261029232220.1245827-1-jltobler@gmail.com> Mapping entries from the "loose-object-idx" file are parsed via `loose_object_map_load()` and inserted into the in-memory loose object map of the corresponding object source. In a subsequent commit, a temporary loose object index file must also be parsed and have its contents stored in a map that is not attached to any object source. Extract the logic for parsing a loose object index file into a separate `loose_object_map_read()` helper function that allows callers to explicitly specify the map to insert the entries into. The `insert_loose_map()` helper function is also updated accordingly to explicitly operate on the provided map and optional cache instead of the object source. The cache is made optional for future callers that may only be interested in updating the map. While at it, stop treating all errors related to opening the "loose-object-idx" file as success and instead only ignore ENOENT. It is expected that a mapping file may not always be present, but other errors should be signaled back to callers. Note that this slightly changes the behavior of `repo_read_loose_object_map()`, which now stops loading the mapping files of subsequent object sources when one is unreadable, the same way it already does when one is malformed. Signed-off-by: Justin Tobler --- loose.c | 87 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 33 deletions(-) diff --git a/loose.c b/loose.c index c6f4ee0ec6..5f72c644f9 100644 --- a/loose.c +++ b/loose.c @@ -48,67 +48,88 @@ static int insert_oid_pair(kh_oid_map_t *map, const struct object_id *key, const return 1; } -static int insert_loose_map(struct odb_source_loose *loose, +static int insert_loose_map(struct loose_object_map *map, + struct oidtree *cache, const struct object_id *oid, const struct object_id *compat_oid) { - struct loose_object_map *map = loose->map; int inserted = 0; inserted |= insert_oid_pair(map->to_compat, oid, compat_oid); inserted |= insert_oid_pair(map->to_storage, compat_oid, oid); - if (inserted) - oidtree_insert(loose->cache, compat_oid, NULL); + if (inserted && cache) + oidtree_insert(cache, compat_oid, NULL); return inserted; } -int loose_object_map_load(struct odb_source_loose *loose) +static int loose_object_map_read(struct repository *repo, const char *path, + struct loose_object_map *map, + struct oidtree *cache) { - struct repository *repo = loose->base.odb->repo; struct strbuf buf = STRBUF_INIT; - char *path; FILE *fp; - int ret = -1; - - if (!should_use_loose_object_map(repo)) - return 0; - - if (!loose->map) - loose_object_map_init(&loose->map); - if (!loose->cache) { - ALLOC_ARRAY(loose->cache, 1); - oidtree_init(loose->cache); - } - - insert_loose_map(loose, repo->hash_algo->empty_tree, repo->compat_hash_algo->empty_tree); - insert_loose_map(loose, repo->hash_algo->empty_blob, repo->compat_hash_algo->empty_blob); - insert_loose_map(loose, repo->hash_algo->null_oid, repo->compat_hash_algo->null_oid); + int ret; - path = xstrfmt("%s/loose-object-idx", loose->base.path); fp = fopen(path, "rb"); if (!fp) { - free(path); - return 0; + if (errno == ENOENT) + return 0; + return -1; } - if (strbuf_getwholeline(&buf, fp, '\n') || strcmp(buf.buf, loose_object_header)) - goto err; + if (strbuf_getwholeline(&buf, fp, '\n') || strcmp(buf.buf, loose_object_header)) { + ret = -1; + goto out; + } while (!strbuf_getline_lf(&buf, fp)) { const char *p; struct object_id oid, compat_oid; if (parse_oid_hex_algop(buf.buf, &oid, &p, repo->hash_algo) || *p++ != ' ' || parse_oid_hex_algop(p, &compat_oid, &p, repo->compat_hash_algo) || - p != buf.buf + buf.len) - goto err; - insert_loose_map(loose, &oid, &compat_oid); + p != buf.buf + buf.len) { + ret = -1; + goto out; + } + insert_loose_map(map, cache, &oid, &compat_oid); } ret = ferror(fp) ? -1 : 0; -err: - fclose(fp); + +out: strbuf_release(&buf); + fclose(fp); + + return ret; +} + +int loose_object_map_load(struct odb_source_loose *loose) +{ + struct repository *repo = loose->base.odb->repo; + char *path; + int ret; + + if (!should_use_loose_object_map(repo)) + return 0; + + if (!loose->map) + loose_object_map_init(&loose->map); + if (!loose->cache) { + ALLOC_ARRAY(loose->cache, 1); + oidtree_init(loose->cache); + } + + insert_loose_map(loose->map, loose->cache, repo->hash_algo->empty_tree, + repo->compat_hash_algo->empty_tree); + insert_loose_map(loose->map, loose->cache, repo->hash_algo->empty_blob, + repo->compat_hash_algo->empty_blob); + insert_loose_map(loose->map, loose->cache, repo->hash_algo->null_oid, + repo->compat_hash_algo->null_oid); + + path = xstrfmt("%s/loose-object-idx", loose->base.path); + ret = loose_object_map_read(repo, path, loose->map, loose->cache); + free(path); return ret; } @@ -223,7 +244,7 @@ int repo_add_loose_object_map(struct odb_source_loose *loose, if (!should_use_loose_object_map(loose->base.odb->repo)) return 0; - inserted = insert_loose_map(loose, oid, compat_oid); + inserted = insert_loose_map(loose->map, loose->cache, oid, compat_oid); if (inserted) return write_one_object(loose, oid, compat_oid); return 0; -- 2.56.0.173.gf57c9a7388