odb: get rid of `the_repository` when handling submodule sources

The "--recursive" flag for git-grep(1) allows users to grep for a string across submodule boundaries. To make this work we add each submodule's object sources to our own object database so that the objects can be accessed directly. The infrastructure for this depends on a global string list of submodule paths. The caller is expected to call `add_submodule_odb_by_path()` for each source and the object database will then eventually register all submodule sources via `do_oid_object_info_extended()` in case it isn't able to look up a specific object. This reliance on global state is of course suboptimal with regards to our libification efforts. Refactor the logic so that the list of submodule sources is instead tracked in the object database itself. This allows us to lose the condition of `r == the_repository` before registering submodule sources as we only ever add submodule sources to `the_repository` anyway. As such, behaviour before and after this refactoring should always be the same. Rename the functions accordingly. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jul 1, 2025 at 14:22 UTC fc28a8a856a1e7978794e7dee61c42d7d5740a6b
6 files changed +50 -43
builtin/grep.c
+2 -1
@@ -505,7 +505,8 @@ static int grep_submodule(struct grep_opt *opt,
505 * lazily registered as alternates when needed (and except in an
506 * unexpected code interaction, it won't be needed).
507 */
508 - add_submodule_odb_by_path(subrepo->objects->sources->path);
508 + odb_add_submodule_source_by_path(the_repository->objects,
509 + subrepo->objects->sources->path);
510 obj_read_unlock();
511
512 memcpy(&subopt, opt, sizeof(subopt));
odb.c
+31 -6
@@ -24,6 +24,7 @@
24 #include "strbuf.h"
25 #include "strvec.h"
26 #include "submodule.h"
27 +#include "trace2.h"
28 #include "write-or-die.h"
29
30 KHASH_INIT(odb_path_map, const char * /* key: odb_path */,
@@ -469,6 +470,12 @@ struct odb_source *odb_find_source(struct object_database *odb, const char *obj_
470 return source;
471 }
472
473 +void odb_add_submodule_source_by_path(struct object_database *odb,
474 + const char *path)
475 +{
476 + string_list_insert(&odb->submodule_source_paths, path);
477 +}
478 +
479 static void fill_alternate_refs_command(struct child_process *cmd,
480 const char *repo_path)
481 {
@@ -623,6 +630,23 @@ void disable_obj_read_lock(void)
630
631 int fetch_if_missing = 1;
632
633 +static int register_all_submodule_sources(struct object_database *odb)
634 +{
635 + int ret = odb->submodule_source_paths.nr;
636 +
637 + for (size_t i = 0; i < odb->submodule_source_paths.nr; i++)
638 + odb_add_to_alternates_memory(odb,
639 + odb->submodule_source_paths.items[i].string);
640 + if (ret) {
641 + string_list_clear(&odb->submodule_source_paths, 0);
642 + trace2_data_intmax("submodule", odb->repo,
643 + "register_all_submodule_sources/registered", ret);
644 + if (git_env_bool("GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB", 0))
645 + BUG("register_all_submodule_sources() called");
646 + }
647 + return ret;
648 +}
649 +
650 static int do_oid_object_info_extended(struct repository *r,
651 const struct object_id *oid,
652 struct object_info *oi, unsigned flags)
@@ -676,13 +700,12 @@ static int do_oid_object_info_extended(struct repository *r,
700 }
701
702 /*
679 - * If r is the_repository, this might be an attempt at
680 - * accessing a submodule object as if it were in the_repository
681 - * (having called add_submodule_odb() on that submodule's ODB).
682 - * If any such ODBs exist, register them and try again.
703 + * This might be an attempt at accessing a submodule object as
704 + * if it were in main object store (having called
705 + * `odb_add_submodule_source_by_path()` on that submodule's
706 + * ODB). If any such ODBs exist, register them and try again.
707 */
684 - if (r == the_repository &&
685 - register_all_submodule_odb_as_alternates())
708 + if (register_all_submodule_sources(r->objects))
709 /* We added some alternates; retry */
710 continue;
711
@@ -968,6 +991,7 @@ struct object_database *odb_new(struct repository *repo)
991 INIT_LIST_HEAD(&o->packed_git_mru);
992 hashmap_init(&o->pack_map, pack_map_entry_cmp, NULL, 0);
993 pthread_mutex_init(&o->replace_mutex, NULL);
994 + string_list_init_dup(&o->submodule_source_paths);
995 return o;
996 }
997
@@ -1017,4 +1041,5 @@ void odb_clear(struct object_database *o)
1041 o->packed_git = NULL;
1042
1043 hashmap_clear(&o->pack_map);
1044 + string_list_clear(&o->submodule_source_paths, 0);
1045 }
odb.h
+15
@@ -6,6 +6,7 @@
6 #include "list.h"
7 #include "oidset.h"
8 #include "oidmap.h"
9 +#include "string-list.h"
10 #include "thread-utils.h"
11
12 struct oidmap;
@@ -165,6 +166,12 @@ struct object_database {
166 * packs.
167 */
168 unsigned packed_git_initialized : 1;
169 +
170 + /*
171 + * Submodule source paths that will be added as additional sources to
172 + * allow lookup of submodule objects via the main object database.
173 + */
174 + struct string_list submodule_source_paths;
175 };
176
177 struct object_database *odb_new(struct repository *repo);
@@ -191,6 +198,14 @@ void odb_restore_primary_source(struct object_database *odb,
198 struct odb_source *restore_source,
199 const char *old_path);
200
201 +/*
202 + * Call odb_add_submodule_source_by_path() to add the submodule at the given
203 + * path to a list. The object stores of all submodules in that list will be
204 + * added as additional sources in the object store when looking up objects.
205 + */
206 +void odb_add_submodule_source_by_path(struct object_database *odb,
207 + const char *path);
208 +
209 /*
210 * Iterate through all alternates of the database and execute the provided
211 * callback function for each of them. Stop iterating once the callback
submodule-config.c
+2 -1
@@ -810,7 +810,8 @@ static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void
810 repo_get_oid(repo, GITMODULES_HEAD, &oid) >= 0) {
811 config_source.blob = oidstr = xstrdup(oid_to_hex(&oid));
812 if (repo != the_repository)
813 - add_submodule_odb_by_path(repo->objects->sources->path);
813 + odb_add_submodule_source_by_path(the_repository->objects,
814 + repo->objects->sources->path);
815 } else {
816 goto out;
817 }
submodule.c
-26
@@ -31,7 +31,6 @@
31 #include "commit-reach.h"
32 #include "read-cache-ll.h"
33 #include "setup.h"
34 -#include "trace2.h"
34
35 static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
36 static int initialized_fetch_ref_tips;
@@ -176,31 +175,6 @@ void stage_updated_gitmodules(struct index_state *istate)
175 die(_("staging updated .gitmodules failed"));
176 }
177
179 -static struct string_list added_submodule_odb_paths = STRING_LIST_INIT_DUP;
180 -
181 -void add_submodule_odb_by_path(const char *path)
182 -{
183 - string_list_insert(&added_submodule_odb_paths, path);
184 -}
185 -
186 -int register_all_submodule_odb_as_alternates(void)
187 -{
188 - int i;
189 - int ret = added_submodule_odb_paths.nr;
190 -
191 - for (i = 0; i < added_submodule_odb_paths.nr; i++)
192 - odb_add_to_alternates_memory(the_repository->objects,
193 - added_submodule_odb_paths.items[i].string);
194 - if (ret) {
195 - string_list_clear(&added_submodule_odb_paths, 0);
196 - trace2_data_intmax("submodule", the_repository,
197 - "register_all_submodule_odb_as_alternates/registered", ret);
198 - if (git_env_bool("GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB", 0))
199 - BUG("register_all_submodule_odb_as_alternates() called");
200 - }
201 - return ret;
202 -}
203 -
178 void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
179 const char *path)
180 {
submodule.h
-9
@@ -104,15 +104,6 @@ int submodule_uses_gitfile(const char *path);
104 #define SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED (1<<2)
105 int bad_to_remove_submodule(const char *path, unsigned flags);
106
107 -/*
108 - * Call add_submodule_odb_by_path() to add the submodule at the given
109 - * path to a list. When register_all_submodule_odb_as_alternates() is
110 - * called, the object stores of all submodules in that list will be
111 - * added as alternates in the_repository.
112 - */
113 -void add_submodule_odb_by_path(const char *path);
114 -int register_all_submodule_odb_as_alternates(void);
115 -
107 /*
108 * Checks if there are submodule changes in a..b. If a is the null OID,
109 * checks b and all its ancestors instead.