odb/source: generalize `reprepare()` callback

The `reprepare()` callback function can be used to flush caches of a given object source and then prepare it anew. This is for example used when a concurrent process may have written new objects. Ultimately, this can be seen as doing two separate steps: 1. We drop any caches. 2. We prepare the source. We have one callsite in git-grep(1) though that really only want to do (2). This is done by reaching into the "files" backend directly and then calling `odb_source_packed_prepare()`, which of course may not work with alternate backends. We could in theory just call `reprepare()` here, and that would likely not have any significant downside. But this would certainly feel like a code smell. Instead, generalize the `reprepare()` callback to `prepare()` with a flag that optionally instructs the backend to also flush the caches, which allows us to drop the external `odb_source_packed_prepare()` declaration. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jun 22, 2026 at 10:47 UTC 27bba4258b9e4bd7a0313e3bb4cce8aeba268712
11 files changed +52 -52
builtin/grep.c
+3 -6
@@ -25,12 +25,11 @@
25 #include "setup.h"
26 #include "submodule.h"
27 #include "submodule-config.h"
28 -#include "object-file.h"
28 #include "object-name.h"
29 #include "odb.h"
30 +#include "odb/source.h"
31 #include "oid-array.h"
32 #include "oidset.h"
33 -#include "packfile.h"
33 #include "pager.h"
34 #include "path.h"
35 #include "promisor-remote.h"
@@ -1361,10 +1360,8 @@ int cmd_grep(int argc,
1360 struct odb_source *source;
1361
1362 odb_prepare_alternates(the_repository->objects);
1364 - for (source = the_repository->objects->sources; source; source = source->next) {
1365 - struct odb_source_files *files = odb_source_files_downcast(source);
1366 - odb_source_packed_prepare(files->packed);
1367 - }
1363 + for (source = the_repository->objects->sources; source; source = source->next)
1364 + odb_source_prepare(source, 0);
1365 }
1366
1367 start_threads(&opt);
midx.c
+1 -1
@@ -101,7 +101,7 @@ static int midx_read_object_offsets(const unsigned char *chunk_start,
101
102 struct multi_pack_index *get_multi_pack_index(struct odb_source_packed *source)
103 {
104 - odb_source_packed_prepare(source);
104 + odb_source_prepare(&source->base, 0);
105 return source->midx;
106 }
107
odb.c
+1 -1
@@ -1086,7 +1086,7 @@ void odb_reprepare(struct object_database *o)
1086 odb_prepare_alternates(o);
1087
1088 for (source = o->sources; source; source = source->next)
1089 - odb_source_reprepare(source);
1089 + odb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);
1090
1091 o->object_count_valid = 0;
1092
odb.h
+8
@@ -124,6 +124,14 @@ void odb_free(struct object_database *o);
124 */
125 void odb_close(struct object_database *o);
126
127 +enum odb_prepare_flags {
128 + /*
129 + * Flush caches, reload alternates and then re-prepare each object
130 + * source so that new objects may become accessible.
131 + */
132 + ODB_PREPARE_FLUSH_CACHES = (1 << 0),
133 +};
134 +
135 /*
136 * Clear caches, reload alternates and then reload object sources so that new
137 * objects may become accessible.
odb/source-files.c
+5 -4
@@ -41,11 +41,12 @@ static void odb_source_files_close(struct odb_source *source)
41 odb_source_close(&files->packed->base);
42 }
43
44 -static void odb_source_files_reprepare(struct odb_source *source)
44 +static void odb_source_files_prepare(struct odb_source *source,
45 + enum odb_prepare_flags flags)
46 {
47 struct odb_source_files *files = odb_source_files_downcast(source);
47 - odb_source_reprepare(&files->loose->base);
48 - odb_source_reprepare(&files->packed->base);
48 + odb_source_prepare(&files->loose->base, flags);
49 + odb_source_prepare(&files->packed->base, flags);
50 }
51
52 static int odb_source_files_read_object_info(struct odb_source *source,
@@ -273,7 +274,7 @@ struct odb_source_files *odb_source_files_new(struct object_database *odb,
274
275 files->base.free = odb_source_files_free;
276 files->base.close = odb_source_files_close;
276 - files->base.reprepare = odb_source_files_reprepare;
277 + files->base.prepare = odb_source_files_prepare;
278 files->base.read_object_info = odb_source_files_read_object_info;
279 files->base.read_object_stream = odb_source_files_read_object_stream;
280 files->base.for_each_object = odb_source_files_for_each_object;
odb/source-inmemory.c
+3 -2
@@ -325,7 +325,8 @@ static void odb_source_inmemory_close(struct odb_source *source UNUSED)
325 {
326 }
327
328 -static void odb_source_inmemory_reprepare(struct odb_source *source UNUSED)
328 +static void odb_source_inmemory_prepare(struct odb_source *source UNUSED,
329 + enum odb_prepare_flags flags UNUSED)
330 {
331 }
332
@@ -365,7 +366,7 @@ struct odb_source_inmemory *odb_source_inmemory_new(struct object_database *odb)
366
367 source->base.free = odb_source_inmemory_free;
368 source->base.close = odb_source_inmemory_close;
368 - source->base.reprepare = odb_source_inmemory_reprepare;
369 + source->base.prepare = odb_source_inmemory_prepare;
370 source->base.read_object_info = odb_source_inmemory_read_object_info;
371 source->base.read_object_stream = odb_source_inmemory_read_object_stream;
372 source->base.for_each_object = odb_source_inmemory_for_each_object;
odb/source-loose.c
+5 -3
@@ -672,10 +672,12 @@ static void odb_source_loose_clear_cache(struct odb_source_loose *loose)
672 sizeof(loose->subdir_seen));
673 }
674
675 -static void odb_source_loose_reprepare(struct odb_source *source)
675 +static void odb_source_loose_prepare(struct odb_source *source,
676 + enum odb_prepare_flags flags)
677 {
678 struct odb_source_loose *loose = odb_source_loose_downcast(source);
678 - odb_source_loose_clear_cache(loose);
679 + if (flags & ODB_PREPARE_FLUSH_CACHES)
680 + odb_source_loose_clear_cache(loose);
681 }
682
683 static void odb_source_loose_close(struct odb_source *source UNUSED)
@@ -716,7 +718,7 @@ struct odb_source_loose *odb_source_loose_new(struct object_database *odb,
718
719 loose->base.free = odb_source_loose_free;
720 loose->base.close = odb_source_loose_close;
719 - loose->base.reprepare = odb_source_loose_reprepare;
721 + loose->base.prepare = odb_source_loose_prepare;
722 loose->base.read_object_info = odb_source_loose_read_object_info;
723 loose->base.read_object_stream = odb_source_loose_read_object_stream;
724 loose->base.for_each_object = odb_source_loose_for_each_object;
odb/source-packed.c
+16 -18
@@ -15,7 +15,7 @@ static int find_pack_entry(struct odb_source_packed *store,
15 {
16 struct packfile_list_entry *l;
17
18 - odb_source_packed_prepare(store);
18 + odb_source_prepare(&store->base, 0);
19 if (store->midx && fill_midx_entry(store->midx, oid, e))
20 return 1;
21
@@ -47,7 +47,7 @@ static int odb_source_packed_read_object_info(struct odb_source *source,
47 * been added since the last time we have prepared the packfile store.
48 */
49 if (flags & OBJECT_INFO_SECOND_READ)
50 - odb_source_reprepare(source);
50 + odb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);
51
52 if (!find_pack_entry(packed, oid, &e))
53 return 1;
@@ -668,27 +668,25 @@ static int sort_pack(const struct packfile_list_entry *a,
668 return -1;
669 }
670
671 -void odb_source_packed_prepare(struct odb_source_packed *source)
671 +static void odb_source_packed_prepare(struct odb_source *source,
672 + enum odb_prepare_flags flags)
673 {
673 - if (source->initialized)
674 + struct odb_source_packed *packed = odb_source_packed_downcast(source);
675 +
676 + if (flags & ODB_PREPARE_FLUSH_CACHES)
677 + packed->initialized = false;
678 + if (packed->initialized)
679 return;
680
676 - prepare_multi_pack_index_one(source);
677 - prepare_packed_git_one(source);
681 + prepare_multi_pack_index_one(packed);
682 + prepare_packed_git_one(packed);
683
679 - sort_packs(&source->packs.head, sort_pack);
680 - for (struct packfile_list_entry *e = source->packs.head; e; e = e->next)
684 + sort_packs(&packed->packs.head, sort_pack);
685 + for (struct packfile_list_entry *e = packed->packs.head; e; e = e->next)
686 if (!e->next)
682 - source->packs.tail = e;
687 + packed->packs.tail = e;
688
684 - source->initialized = true;
685 -}
686 -
687 -static void odb_source_packed_reprepare(struct odb_source *source)
688 -{
689 - struct odb_source_packed *packed = odb_source_packed_downcast(source);
690 - packed->initialized = false;
691 - odb_source_packed_prepare(packed);
689 + packed->initialized = true;
690 }
691
692 static void odb_source_packed_reparent(const char *name UNUSED,
@@ -744,7 +742,7 @@ struct odb_source_packed *odb_source_packed_new(struct object_database *odb,
742
743 packed->base.free = odb_source_packed_free;
744 packed->base.close = odb_source_packed_close;
747 - packed->base.reprepare = odb_source_packed_reprepare;
745 + packed->base.prepare = odb_source_packed_prepare;
746 packed->base.read_object_info = odb_source_packed_read_object_info;
747 packed->base.read_object_stream = odb_source_packed_read_object_stream;
748 packed->base.for_each_object = odb_source_packed_for_each_object;
odb/source-packed.h
-9
@@ -82,13 +82,4 @@ static inline struct odb_source_packed *odb_source_packed_downcast(struct odb_so
82 return container_of(source, struct odb_source_packed, base);
83 }
84
85 -/*
86 - * Prepare the source by loading packfiles and multi-pack indices for
87 - * all alternates. This becomes a no-op if the source is already prepared.
88 - *
89 - * It shouldn't typically be necessary to call this function directly, as
90 - * functions that access the source know to prepare it.
91 - */
92 -void odb_source_packed_prepare(struct odb_source_packed *source);
93 -
85 #endif
odb/source.h
+9 -7
@@ -83,11 +83,12 @@ struct odb_source {
83 void (*close)(struct odb_source *source);
84
85 /*
86 - * This callback is expected to clear underlying caches of the object
87 - * database source. The function is called when the repository has for
88 - * example just been repacked so that new objects will become visible.
86 + * This callback is expected to prepare the source so that it becomes
87 + * ready for use. It optionally clears underlying caches of the object
88 + * database source.
89 */
90 - void (*reprepare)(struct odb_source *source);
90 + void (*prepare)(struct odb_source *source,
91 + enum odb_prepare_flags flags);
92
93 /*
94 * This callback is expected to read object information from the object
@@ -308,13 +309,14 @@ static inline void odb_source_close(struct odb_source *source)
309 }
310
311 /*
311 - * Reprepare the object database source and clear any caches. Depending on the
312 + * Prepare the object database source and clear any caches. Depending on the
313 * backend used this may have the effect that concurrently-written objects
314 * become visible.
315 */
315 -static inline void odb_source_reprepare(struct odb_source *source)
316 +static inline void odb_source_prepare(struct odb_source *source,
317 + enum odb_prepare_flags flags)
318 {
317 - source->reprepare(source);
319 + source->prepare(source, flags);
320 }
321
322 /*
packfile.c
+1 -1
@@ -855,7 +855,7 @@ void for_each_file_in_pack_dir(const char *objdir,
855
856 struct packfile_list_entry *packfile_store_get_packs(struct odb_source_packed *store)
857 {
858 - odb_source_packed_prepare(store);
858 + odb_source_prepare(&store->base, 0);
859
860 if (store->midx) {
861 struct multi_pack_index *m = store->midx;