object-name: move logic to iterate through loose prefixed objects

The logic to iterate through loose objects that have a certain prefix is currently hosted in "object-name.c". This logic reaches into specifics of the loose object source, so it breaks once a different backend is used for the object storage. Move the logic to iterate through loose objects with a prefix into "object-file.c". This is done by extending the for-each-object options to support an optional prefix that is then honored by the loose source. Naturally, we'll also have this support in the packfile store. This is done in the next commit. Furthermore, there are no users of the loose cache outside of "object-file.c" anymore. As such, convert `odb_source_loose_cache()` to have file scope. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Mar 20, 2026 at 08:07 UTC 284b7862be735bb47276ac288ace153ae3d06938
4 files changed +40 -13
object-file.c
+27 -2
@@ -33,6 +33,9 @@
33 /* The maximum size for an object header. */
34 #define MAX_HEADER_LEN 32
35
36 +static struct oidtree *odb_source_loose_cache(struct odb_source *source,
37 + const struct object_id *oid);
38 +
39 static int get_conv_flags(unsigned flags)
40 {
41 if (flags & INDEX_RENORMALIZE)
@@ -1845,6 +1848,23 @@ static int for_each_object_wrapper_cb(const struct object_id *oid,
1848 }
1849 }
1850
1851 +static int for_each_prefixed_object_wrapper_cb(const struct object_id *oid,
1852 + void *cb_data)
1853 +{
1854 + struct for_each_object_wrapper_data *data = cb_data;
1855 + if (data->request) {
1856 + struct object_info oi = *data->request;
1857 +
1858 + if (odb_source_loose_read_object_info(data->source,
1859 + oid, &oi, 0) < 0)
1860 + return -1;
1861 +
1862 + return data->cb(oid, &oi, data->cb_data);
1863 + } else {
1864 + return data->cb(oid, NULL, data->cb_data);
1865 + }
1866 +}
1867 +
1868 int odb_source_loose_for_each_object(struct odb_source *source,
1869 const struct object_info *request,
1870 odb_for_each_object_cb cb,
@@ -1864,6 +1884,11 @@ int odb_source_loose_for_each_object(struct odb_source *source,
1884 if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !source->local)
1885 return 0;
1886
1887 + if (opts->prefix)
1888 + return oidtree_each(odb_source_loose_cache(source, opts->prefix),
1889 + opts->prefix, opts->prefix_hex_len,
1890 + for_each_prefixed_object_wrapper_cb, &data);
1891 +
1892 return for_each_loose_file_in_source(source, for_each_object_wrapper_cb,
1893 NULL, NULL, &data);
1894 }
@@ -1935,8 +1960,8 @@ static int append_loose_object(const struct object_id *oid,
1960 return 0;
1961 }
1962
1938 -struct oidtree *odb_source_loose_cache(struct odb_source *source,
1939 - const struct object_id *oid)
1963 +static struct oidtree *odb_source_loose_cache(struct odb_source *source,
1964 + const struct object_id *oid)
1965 {
1966 struct odb_source_files *files = odb_source_files_downcast(source);
1967 int subdir_nr = oid->hash[0];
object-file.h
-7
@@ -74,13 +74,6 @@ int odb_source_loose_write_stream(struct odb_source *source,
74 struct odb_write_stream *stream, size_t len,
75 struct object_id *oid);
76
77 -/*
78 - * Populate and return the loose object cache array corresponding to the
79 - * given object ID.
80 - */
81 -struct oidtree *odb_source_loose_cache(struct odb_source *source,
82 - const struct object_id *oid);
83 -
77 /*
78 * Put in `buf` the name of the file in the local object database that
79 * would be used to store a loose object with the specified oid.
object-name.c
+6 -4
@@ -16,7 +16,6 @@
16 #include "remote.h"
17 #include "dir.h"
18 #include "oid-array.h"
19 -#include "oidtree.h"
19 #include "packfile.h"
20 #include "pretty.h"
21 #include "object-file.h"
@@ -103,7 +102,7 @@ static void update_candidates(struct disambiguate_state *ds, const struct object
102
103 static int match_hash(unsigned, const unsigned char *, const unsigned char *);
104
106 -static int match_prefix(const struct object_id *oid, void *arg)
105 +static int match_prefix(const struct object_id *oid, struct object_info *oi UNUSED, void *arg)
106 {
107 struct disambiguate_state *ds = arg;
108 /* no need to call match_hash, oidtree_each did prefix match */
@@ -113,11 +112,14 @@ static int match_prefix(const struct object_id *oid, void *arg)
112
113 static void find_short_object_filename(struct disambiguate_state *ds)
114 {
115 + struct odb_for_each_object_options opts = {
116 + .prefix = &ds->bin_pfx,
117 + .prefix_hex_len = ds->len,
118 + };
119 struct odb_source *source;
120
121 for (source = ds->repo->objects->sources; source && !ds->ambiguous; source = source->next)
119 - oidtree_each(odb_source_loose_cache(source, &ds->bin_pfx),
120 - &ds->bin_pfx, ds->len, match_prefix, ds);
122 + odb_source_loose_for_each_object(source, NULL, match_prefix, ds, &opts);
123 }
124
125 static int match_hash(unsigned len, const unsigned char *a, const unsigned char *b)
odb.h
+7
@@ -488,6 +488,13 @@ typedef int (*odb_for_each_object_cb)(const struct object_id *oid,
488 struct odb_for_each_object_options {
489 /* A bitfield of `odb_for_each_object_flags`. */
490 enum odb_for_each_object_flags flags;
491 +
492 + /*
493 + * If set, only iterate through objects whose first `prefix_hex_len`
494 + * hex characters matches the given prefix.
495 + */
496 + const struct object_id *prefix;
497 + size_t prefix_hex_len;
498 };
499
500 /*