odb: introduce parent pointers

In subsequent commits we'll get rid of our use of `the_repository` in "odb.c" in favor of explicitly passing in a `struct object_database` or a `struct odb_source`. In some cases though we'll need access to the repository, for example to read a config value from it, but we don't have a way to access the repository owning a specific object database. Introduce parent pointers for `struct object_database` to its owning repository as well as for `struct odb_source` to its owning object database, which will allow us to adapt those use cases. Note that this change requires us to pass through the object database to `link_alt_odb_entry()` so that we can set up the parent pointers for any source there. The callchain is adapted to pass through the object database 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 2f5181fce6c6353f9c743d9d396fbf06527688c7
3 files changed +35 -21
odb.c
+26 -19
@@ -135,11 +135,15 @@ static int alt_odb_usable(struct object_database *o,
135 * of the object ID, an extra slash for the first level indirection, and
136 * the terminating NUL.
137 */
138 -static void read_info_alternates(struct repository *r,
138 +static void read_info_alternates(struct object_database *odb,
139 const char *relative_base,
140 int depth);
141 -static int link_alt_odb_entry(struct repository *r, const struct strbuf *entry,
142 - const char *relative_base, int depth, const char *normalized_objdir)
141 +
142 +static int link_alt_odb_entry(struct object_database *odb,
143 + const struct strbuf *entry,
144 + const char *relative_base,
145 + int depth,
146 + const char *normalized_objdir)
147 {
148 struct odb_source *alternate;
149 struct strbuf pathbuf = STRBUF_INIT;
@@ -167,22 +171,23 @@ static int link_alt_odb_entry(struct repository *r, const struct strbuf *entry,
171 while (pathbuf.len && pathbuf.buf[pathbuf.len - 1] == '/')
172 strbuf_setlen(&pathbuf, pathbuf.len - 1);
173
170 - if (!alt_odb_usable(r->objects, &pathbuf, normalized_objdir, &pos))
174 + if (!alt_odb_usable(odb, &pathbuf, normalized_objdir, &pos))
175 goto error;
176
177 CALLOC_ARRAY(alternate, 1);
178 + alternate->odb = odb;
179 /* pathbuf.buf is already in r->objects->source_by_path */
180 alternate->path = strbuf_detach(&pathbuf, NULL);
181
182 /* add the alternate entry */
178 - *r->objects->sources_tail = alternate;
179 - r->objects->sources_tail = &(alternate->next);
183 + *odb->sources_tail = alternate;
184 + odb->sources_tail = &(alternate->next);
185 alternate->next = NULL;
181 - assert(r->objects->source_by_path);
182 - kh_value(r->objects->source_by_path, pos) = alternate;
186 + assert(odb->source_by_path);
187 + kh_value(odb->source_by_path, pos) = alternate;
188
189 /* recursively add alternates */
185 - read_info_alternates(r, alternate->path, depth + 1);
190 + read_info_alternates(odb, alternate->path, depth + 1);
191 ret = 0;
192 error:
193 strbuf_release(&tmp);
@@ -219,7 +224,7 @@ static const char *parse_alt_odb_entry(const char *string,
224 return end;
225 }
226
222 -static void link_alt_odb_entries(struct repository *r, const char *alt,
227 +static void link_alt_odb_entries(struct object_database *odb, const char *alt,
228 int sep, const char *relative_base, int depth)
229 {
230 struct strbuf objdirbuf = STRBUF_INIT;
@@ -234,20 +239,20 @@ static void link_alt_odb_entries(struct repository *r, const char *alt,
239 return;
240 }
241
237 - strbuf_realpath(&objdirbuf, r->objects->sources->path, 1);
242 + strbuf_realpath(&objdirbuf, odb->sources->path, 1);
243
244 while (*alt) {
245 alt = parse_alt_odb_entry(alt, sep, &entry);
246 if (!entry.len)
247 continue;
243 - link_alt_odb_entry(r, &entry,
248 + link_alt_odb_entry(odb, &entry,
249 relative_base, depth, objdirbuf.buf);
250 }
251 strbuf_release(&entry);
252 strbuf_release(&objdirbuf);
253 }
254
250 -static void read_info_alternates(struct repository *r,
255 +static void read_info_alternates(struct object_database *odb,
256 const char *relative_base,
257 int depth)
258 {
@@ -261,7 +266,7 @@ static void read_info_alternates(struct repository *r,
266 return;
267 }
268
264 - link_alt_odb_entries(r, buf.buf, '\n', relative_base, depth);
269 + link_alt_odb_entries(odb, buf.buf, '\n', relative_base, depth);
270 strbuf_release(&buf);
271 free(path);
272 }
@@ -303,7 +308,7 @@ void add_to_alternates_file(const char *reference)
308 if (commit_lock_file(&lock))
309 die_errno(_("unable to move new alternates file into place"));
310 if (the_repository->objects->loaded_alternates)
306 - link_alt_odb_entries(the_repository, reference,
311 + link_alt_odb_entries(the_repository->objects, reference,
312 '\n', NULL, 0);
313 }
314 free(alts);
@@ -317,7 +322,7 @@ void add_to_alternates_memory(const char *reference)
322 */
323 prepare_alt_odb(the_repository);
324
320 - link_alt_odb_entries(the_repository, reference,
325 + link_alt_odb_entries(the_repository->objects, reference,
326 '\n', NULL, 0);
327 }
328
@@ -336,6 +341,7 @@ struct odb_source *set_temporary_primary_odb(const char *dir, int will_destroy)
341 * alternate
342 */
343 source = xcalloc(1, sizeof(*source));
344 + source->odb = the_repository->objects;
345 source->path = xstrdup(dir);
346
347 /*
@@ -580,9 +586,9 @@ void prepare_alt_odb(struct repository *r)
586 if (r->objects->loaded_alternates)
587 return;
588
583 - link_alt_odb_entries(r, r->objects->alternate_db, PATH_SEP, NULL, 0);
589 + link_alt_odb_entries(r->objects, r->objects->alternate_db, PATH_SEP, NULL, 0);
590
585 - read_info_alternates(r, r->objects->sources->path, 0);
591 + read_info_alternates(r->objects, r->objects->sources->path, 0);
592 r->objects->loaded_alternates = 1;
593 }
594
@@ -950,11 +956,12 @@ void assert_oid_type(const struct object_id *oid, enum object_type expect)
956 type_name(expect));
957 }
958
953 -struct object_database *odb_new(void)
959 +struct object_database *odb_new(struct repository *repo)
960 {
961 struct object_database *o = xmalloc(sizeof(*o));
962
963 memset(o, 0, sizeof(*o));
964 + o->repo = repo;
965 INIT_LIST_HEAD(&o->packed_git_mru);
966 hashmap_init(&o->pack_map, pack_map_entry_cmp, NULL, 0);
967 pthread_mutex_init(&o->replace_mutex, NULL);
odb.h
+7 -1
@@ -28,6 +28,9 @@ struct repository;
28 struct odb_source {
29 struct odb_source *next;
30
31 + /* Object database that owns this object source. */
32 + struct object_database *odb;
33 +
34 /*
35 * Used to store the results of readdir(3) calls when we are OK
36 * sacrificing accuracy due to races for speed. That includes
@@ -105,6 +108,9 @@ struct cached_object_entry;
108 * configured via alternates.
109 */
110 struct object_database {
111 + /* Repository that owns this database. */
112 + struct repository *repo;
113 +
114 /*
115 * Set of all object directories; the main directory is first (and
116 * cannot be NULL after initialization). Subsequent directories are
@@ -186,7 +192,7 @@ struct object_database {
192 unsigned packed_git_initialized : 1;
193 };
194
189 -struct object_database *odb_new(void);
195 +struct object_database *odb_new(struct repository *repo);
196 void odb_clear(struct object_database *o);
197
198 /*
repository.c
+2 -1
@@ -52,7 +52,7 @@ static void set_default_hash_algo(struct repository *repo)
52
53 void initialize_repository(struct repository *repo)
54 {
55 - repo->objects = odb_new();
55 + repo->objects = odb_new(repo);
56 repo->remote_state = remote_state_new();
57 repo->parsed_objects = parsed_object_pool_new(repo);
58 ALLOC_ARRAY(repo->index, 1);
@@ -167,6 +167,7 @@ void repo_set_gitdir(struct repository *repo,
167
168 if (!repo->objects->sources) {
169 CALLOC_ARRAY(repo->objects->sources, 1);
170 + repo->objects->sources->odb = repo->objects;
171 repo->objects->sources_tail = &repo->objects->sources->next;
172 }
173 expand_base_dir(&repo->objects->sources->path, o->object_dir,