object-file: move loose object cache into loose source

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_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_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_source_loose`. This design is similar to how we do it for our ref backends. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Nov 3, 2025 at 08:42 UTC 90a93f9dea88532623ef7422dbc21d8dc70a58dd
6 files changed +39 -36
loose.c
+5 -4
@@ -1,6 +1,7 @@
1 #include "git-compat-util.h"
2 #include "hash.h"
3 #include "path.h"
4 +#include "object-file.h"
5 #include "odb.h"
6 #include "hex.h"
7 #include "repository.h"
@@ -54,7 +55,7 @@ static int insert_loose_map(struct odb_source *source,
55 inserted |= insert_oid_pair(map->to_compat, oid, compat_oid);
56 inserted |= insert_oid_pair(map->to_storage, compat_oid, oid);
57 if (inserted)
57 - oidtree_insert(source->loose_objects_cache, compat_oid);
58 + oidtree_insert(source->loose->cache, compat_oid);
59
60 return inserted;
61 }
@@ -66,9 +67,9 @@ static int load_one_loose_object_map(struct repository *repo, struct odb_source
67
68 if (!source->loose_map)
69 loose_object_map_init(&source->loose_map);
69 - if (!source->loose_objects_cache) {
70 - ALLOC_ARRAY(source->loose_objects_cache, 1);
71 - oidtree_init(source->loose_objects_cache);
70 + if (!source->loose->cache) {
71 + ALLOC_ARRAY(source->loose->cache, 1);
72 + oidtree_init(source->loose->cache);
73 }
74
75 insert_loose_map(source, repo->hash_algo->empty_tree, repo->compat_hash_algo->empty_tree);
object-file.c
+19 -16
@@ -223,7 +223,7 @@ static int quick_has_loose(struct repository *r,
223
224 odb_prepare_alternates(r->objects);
225 for (source = r->objects->sources; source; source = source->next) {
226 - if (oidtree_contains(odb_loose_cache(source, oid), oid))
226 + if (oidtree_contains(odb_source_loose_cache(source, oid), oid))
227 return 1;
228 }
229 return 0;
@@ -1802,44 +1802,44 @@ static int append_loose_object(const struct object_id *oid,
1802 return 0;
1803 }
1804
1805 -struct oidtree *odb_loose_cache(struct odb_source *source,
1806 - const struct object_id *oid)
1805 +struct oidtree *odb_source_loose_cache(struct odb_source *source,
1806 + const struct object_id *oid)
1807 {
1808 int subdir_nr = oid->hash[0];
1809 struct strbuf buf = STRBUF_INIT;
1810 - size_t word_bits = bitsizeof(source->loose_objects_subdir_seen[0]);
1810 + size_t word_bits = bitsizeof(source->loose->subdir_seen[0]);
1811 size_t word_index = subdir_nr / word_bits;
1812 size_t mask = (size_t)1u << (subdir_nr % word_bits);
1813 uint32_t *bitmap;
1814
1815 if (subdir_nr < 0 ||
1816 - (size_t) subdir_nr >= bitsizeof(source->loose_objects_subdir_seen))
1816 + (size_t) subdir_nr >= bitsizeof(source->loose->subdir_seen))
1817 BUG("subdir_nr out of range");
1818
1819 - bitmap = &source->loose_objects_subdir_seen[word_index];
1819 + bitmap = &source->loose->subdir_seen[word_index];
1820 if (*bitmap & mask)
1821 - return source->loose_objects_cache;
1822 - if (!source->loose_objects_cache) {
1823 - ALLOC_ARRAY(source->loose_objects_cache, 1);
1824 - oidtree_init(source->loose_objects_cache);
1821 + return source->loose->cache;
1822 + if (!source->loose->cache) {
1823 + ALLOC_ARRAY(source->loose->cache, 1);
1824 + oidtree_init(source->loose->cache);
1825 }
1826 strbuf_addstr(&buf, source->path);
1827 for_each_file_in_obj_subdir(subdir_nr, &buf,
1828 source->odb->repo->hash_algo,
1829 append_loose_object,
1830 NULL, NULL,
1831 - source->loose_objects_cache);
1831 + source->loose->cache);
1832 *bitmap |= mask;
1833 strbuf_release(&buf);
1834 - return source->loose_objects_cache;
1834 + return source->loose->cache;
1835 }
1836
1837 void odb_clear_loose_cache(struct odb_source *source)
1838 {
1839 - oidtree_clear(source->loose_objects_cache);
1840 - FREE_AND_NULL(source->loose_objects_cache);
1841 - memset(&source->loose_objects_subdir_seen, 0,
1842 - sizeof(source->loose_objects_subdir_seen));
1839 + oidtree_clear(source->loose->cache);
1840 + FREE_AND_NULL(source->loose->cache);
1841 + memset(&source->loose->subdir_seen, 0,
1842 + sizeof(source->loose->subdir_seen));
1843 }
1844
1845 static int check_stream_oid(git_zstream *stream,
@@ -2006,5 +2006,8 @@ struct odb_source_loose *odb_source_loose_new(struct odb_source *source)
2006
2007 void odb_source_loose_free(struct odb_source_loose *loose)
2008 {
2009 + if (!loose)
2010 + return;
2011 + odb_clear_loose_cache(loose->source);
2012 free(loose);
2013 }
object-file.h
+14 -2
@@ -20,6 +20,18 @@ struct odb_source;
20
21 struct odb_source_loose {
22 struct odb_source *source;
23 +
24 + /*
25 + * Used to store the results of readdir(3) calls when we are OK
26 + * sacrificing accuracy due to races for speed. That includes
27 + * object existence with OBJECT_INFO_QUICK, as well as
28 + * our search for unique abbreviated hashes. Don't use it for tasks
29 + * requiring greater accuracy!
30 + *
31 + * Be sure to call odb_load_loose_cache() before using.
32 + */
33 + uint32_t subdir_seen[8]; /* 256 bits */
34 + struct oidtree *cache;
35 };
36
37 struct odb_source_loose *odb_source_loose_new(struct odb_source *source);
@@ -29,8 +41,8 @@ void odb_source_loose_free(struct odb_source_loose *loose);
41 * Populate and return the loose object cache array corresponding to the
42 * given object ID.
43 */
32 -struct oidtree *odb_loose_cache(struct odb_source *source,
33 - const struct object_id *oid);
44 +struct oidtree *odb_source_loose_cache(struct odb_source *source,
45 + const struct object_id *oid);
46
47 /* Empty the loose object cache for the specified object directory. */
48 void odb_clear_loose_cache(struct odb_source *source);
object-name.c
+1 -1
@@ -116,7 +116,7 @@ static void find_short_object_filename(struct disambiguate_state *ds)
116 struct odb_source *source;
117
118 for (source = ds->repo->objects->sources; source && !ds->ambiguous; source = source->next)
119 - oidtree_each(odb_loose_cache(source, &ds->bin_pfx),
119 + oidtree_each(odb_source_loose_cache(source, &ds->bin_pfx),
120 &ds->bin_pfx, ds->len, match_prefix, ds);
121 }
122
odb.c
-1
@@ -370,7 +370,6 @@ static void odb_source_free(struct odb_source *source)
370 {
371 free(source->path);
372 odb_source_loose_free(source->loose);
373 - odb_clear_loose_cache(source);
373 loose_object_map_clear(&source->loose_map);
374 free(source);
375 }
odb.h
-12
@@ -51,18 +51,6 @@ struct odb_source {
51 /* Private state for loose objects. */
52 struct odb_source_loose *loose;
53
54 - /*
55 - * Used to store the results of readdir(3) calls when we are OK
56 - * sacrificing accuracy due to races for speed. That includes
57 - * object existence with OBJECT_INFO_QUICK, as well as
58 - * our search for unique abbreviated hashes. Don't use it for tasks
59 - * requiring greater accuracy!
60 - *
61 - * Be sure to call odb_load_loose_cache() before using.
62 - */
63 - uint32_t loose_objects_subdir_seen[8]; /* 256 bits */
64 - struct oidtree *loose_objects_cache;
65 -
54 /* Map between object IDs for loose objects. */
55 struct loose_object_map *loose_map;
56