{"thread":{"id":"65850","subject":"[PATCH 0/2] odb: generalize `reprepare()` callback","startedAt":"2026-06-22T08:48:05Z","lastAt":"2026-06-30T08:31:31Z","messageCount":10,"participants":["Patrick Steinhardt","Toon Claes","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"546142","messageId":"20260622-b4-pks-odb-generalize-prepare-v1-0-d2a5c5d13144@pks.im","threadId":"65850","inReplyTo":null,"subject":"[PATCH 0/2] odb: generalize `reprepare()` callback","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-06-22T08:47:53Z","receivedAt":"2026-06-22T08:48:05Z","isPatch":true,"body":"Hi,\n\nthis small patch series generalizes the `reprepare()` callback into a\n`prepare()` callback that accepts an optional flag to also discard any\ncaches. This is required so that we can make git-grep(1) become fully\ngeneric.\n\nThe series is built on top of 8d96f09e92 (Merge branch\n'js/objects-larger-than-4gb-on-windows', 2026-06-19) with\nps/odb-source-packed at 1bba3c035d (odb/source-packed: drop pointer to\n\"files\" parent source, 2026-06-17) merged into it.\n\nThanks!\n\nPatrick\n\n---\nPatrick Steinhardt (2):\n      odb/source: generalize `reprepare()` callback\n      odb: introduce `odb_prepare()`\n\n builtin/grep.c        | 14 +++-----------\n midx.c                |  2 +-\n odb.c                 | 18 ++++++++++++------\n odb.h                 | 16 ++++++++++++++--\n odb/source-files.c    |  9 +++++----\n odb/source-inmemory.c |  5 +++--\n odb/source-loose.c    |  8 +++++---\n odb/source-packed.c   | 34 ++++++++++++++++------------------\n odb/source-packed.h   |  9 ---------\n odb/source.h          | 16 +++++++++-------\n packfile.c            |  2 +-\n 11 files changed, 69 insertions(+), 64 deletions(-)\n\n\n---\nbase-commit: 4a8e7a446f41435e157131162dfe901eca9250fe\nchange-id: 20260612-b4-pks-odb-generalize-prepare-509ffc18f502\n\n"},{"id":"546143","messageId":"20260622-b4-pks-odb-generalize-prepare-v1-1-d2a5c5d13144@pks.im","threadId":"65850","inReplyTo":"20260622-b4-pks-odb-generalize-prepare-v1-0-d2a5c5d13144@pks.im","subject":"[PATCH 1/2] odb/source: generalize `reprepare()` callback","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-06-22T08:47:54Z","receivedAt":"2026-06-22T08:48:06Z","isPatch":true,"body":"The `reprepare()` callback function can be used to flush caches of a\ngiven object source and then prepare it anew. This is for example used\nwhen a concurrent process may have written new objects. Ultimately, this\ncan be seen as doing two separate steps:\n\n  1. We drop any caches.\n\n  2. We prepare the source.\n\nWe have one callsite in git-grep(1) though that really only want to do\n(2). This is done by reaching into the \"files\" backend directly and then\ncalling `odb_source_packed_prepare()`, which of course may not work with\nalternate backends.\n\nWe could in theory just call `reprepare()` here, and that would likely\nnot have any significant downside. But this would certainly feel like a\ncode smell.\n\nInstead, generalize the `reprepare()` callback to `prepare()` with a\nflag that optionally instructs the backend to also flush the caches,\nwhich allows us to drop the external `odb_source_packed_prepare()`\ndeclaration.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/grep.c        |  9 +++------\n midx.c                |  2 +-\n odb.c                 |  2 +-\n odb.h                 |  8 ++++++++\n odb/source-files.c    |  9 +++++----\n odb/source-inmemory.c |  5 +++--\n odb/source-loose.c    |  8 +++++---\n odb/source-packed.c   | 34 ++++++++++++++++------------------\n odb/source-packed.h   |  9 ---------\n odb/source.h          | 16 +++++++++-------\n packfile.c            |  2 +-\n 11 files changed, 52 insertions(+), 52 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 8080d1bf5e..7361bf071e 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -25,12 +25,11 @@\n #include \"setup.h\"\n #include \"submodule.h\"\n #include \"submodule-config.h\"\n-#include \"object-file.h\"\n #include \"object-name.h\"\n #include \"odb.h\"\n+#include \"odb/source.h\"\n #include \"oid-array.h\"\n #include \"oidset.h\"\n-#include \"packfile.h\"\n #include \"pager.h\"\n #include \"path.h\"\n #include \"promisor-remote.h\"\n@@ -1361,10 +1360,8 @@ int cmd_grep(int argc,\n \t\t\tstruct odb_source *source;\n \n \t\t\todb_prepare_alternates(the_repository->objects);\n-\t\t\tfor (source = the_repository->objects->sources; source; source = source->next) {\n-\t\t\t\tstruct odb_source_files *files = odb_source_files_downcast(source);\n-\t\t\t\todb_source_packed_prepare(files->packed);\n-\t\t\t}\n+\t\t\tfor (source = the_repository->objects->sources; source; source = source->next)\n+\t\t\t\todb_source_prepare(source, 0);\n \t\t}\n \n \t\tstart_threads(&opt);\ndiff --git a/midx.c b/midx.c\nindex cc6b94f9dd..76c3f92cc3 100644\n--- a/midx.c\n+++ b/midx.c\n@@ -101,7 +101,7 @@ static int midx_read_object_offsets(const unsigned char *chunk_start,\n \n struct multi_pack_index *get_multi_pack_index(struct odb_source_packed *source)\n {\n-\todb_source_packed_prepare(source);\n+\todb_source_prepare(&source->base, 0);\n \treturn source->midx;\n }\n \ndiff --git a/odb.c b/odb.c\nindex 965ef68e4e..7b45390e12 100644\n--- a/odb.c\n+++ b/odb.c\n@@ -1086,7 +1086,7 @@ void odb_reprepare(struct object_database *o)\n \todb_prepare_alternates(o);\n \n \tfor (source = o->sources; source; source = source->next)\n-\t\todb_source_reprepare(source);\n+\t\todb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);\n \n \to->object_count_valid = 0;\n \ndiff --git a/odb.h b/odb.h\nindex 0030467a52..c14c9030e4 100644\n--- a/odb.h\n+++ b/odb.h\n@@ -124,6 +124,14 @@ void odb_free(struct object_database *o);\n  */\n void odb_close(struct object_database *o);\n \n+enum odb_prepare_flags {\n+\t/*\n+\t * Flush caches, reload alternates and then re-prepare each object\n+\t * source so that new objects may become accessible.\n+\t */\n+\tODB_PREPARE_FLUSH_CACHES = (1 << 0),\n+};\n+\n /*\n  * Clear caches, reload alternates and then reload object sources so that new\n  * objects may become accessible.\ndiff --git a/odb/source-files.c b/odb/source-files.c\nindex 3bc6419dd7..ad9e0b52f9 100644\n--- a/odb/source-files.c\n+++ b/odb/source-files.c\n@@ -41,11 +41,12 @@ static void odb_source_files_close(struct odb_source *source)\n \todb_source_close(&files->packed->base);\n }\n \n-static void odb_source_files_reprepare(struct odb_source *source)\n+static void odb_source_files_prepare(struct odb_source *source,\n+\t\t\t\t     enum odb_prepare_flags flags)\n {\n \tstruct odb_source_files *files = odb_source_files_downcast(source);\n-\todb_source_reprepare(&files->loose->base);\n-\todb_source_reprepare(&files->packed->base);\n+\todb_source_prepare(&files->loose->base, flags);\n+\todb_source_prepare(&files->packed->base, flags);\n }\n \n static int odb_source_files_read_object_info(struct odb_source *source,\n@@ -273,7 +274,7 @@ struct odb_source_files *odb_source_files_new(struct object_database *odb,\n \n \tfiles->base.free = odb_source_files_free;\n \tfiles->base.close = odb_source_files_close;\n-\tfiles->base.reprepare = odb_source_files_reprepare;\n+\tfiles->base.prepare = odb_source_files_prepare;\n \tfiles->base.read_object_info = odb_source_files_read_object_info;\n \tfiles->base.read_object_stream = odb_source_files_read_object_stream;\n \tfiles->base.for_each_object = odb_source_files_for_each_object;\ndiff --git a/odb/source-inmemory.c b/odb/source-inmemory.c\nindex e004566d76..cc5e9e62cb 100644\n--- a/odb/source-inmemory.c\n+++ b/odb/source-inmemory.c\n@@ -325,7 +325,8 @@ static void odb_source_inmemory_close(struct odb_source *source UNUSED)\n {\n }\n \n-static void odb_source_inmemory_reprepare(struct odb_source *source UNUSED)\n+static void odb_source_inmemory_prepare(struct odb_source *source UNUSED,\n+\t\t\t\t\tenum odb_prepare_flags flags UNUSED)\n {\n }\n \n@@ -365,7 +366,7 @@ struct odb_source_inmemory *odb_source_inmemory_new(struct object_database *odb)\n \n \tsource->base.free = odb_source_inmemory_free;\n \tsource->base.close = odb_source_inmemory_close;\n-\tsource->base.reprepare = odb_source_inmemory_reprepare;\n+\tsource->base.prepare = odb_source_inmemory_prepare;\n \tsource->base.read_object_info = odb_source_inmemory_read_object_info;\n \tsource->base.read_object_stream = odb_source_inmemory_read_object_stream;\n \tsource->base.for_each_object = odb_source_inmemory_for_each_object;\ndiff --git a/odb/source-loose.c b/odb/source-loose.c\nindex 7d7ea2fb84..af46316e35 100644\n--- a/odb/source-loose.c\n+++ b/odb/source-loose.c\n@@ -672,10 +672,12 @@ static void odb_source_loose_clear_cache(struct odb_source_loose *loose)\n \t       sizeof(loose->subdir_seen));\n }\n \n-static void odb_source_loose_reprepare(struct odb_source *source)\n+static void odb_source_loose_prepare(struct odb_source *source,\n+\t\t\t\t     enum odb_prepare_flags flags)\n {\n \tstruct odb_source_loose *loose = odb_source_loose_downcast(source);\n-\todb_source_loose_clear_cache(loose);\n+\tif (flags & ODB_PREPARE_FLUSH_CACHES)\n+\t\todb_source_loose_clear_cache(loose);\n }\n \n static void odb_source_loose_close(struct odb_source *source UNUSED)\n@@ -716,7 +718,7 @@ struct odb_source_loose *odb_source_loose_new(struct object_database *odb,\n \n \tloose->base.free = odb_source_loose_free;\n \tloose->base.close = odb_source_loose_close;\n-\tloose->base.reprepare = odb_source_loose_reprepare;\n+\tloose->base.prepare = odb_source_loose_prepare;\n \tloose->base.read_object_info = odb_source_loose_read_object_info;\n \tloose->base.read_object_stream = odb_source_loose_read_object_stream;\n \tloose->base.for_each_object = odb_source_loose_for_each_object;\ndiff --git a/odb/source-packed.c b/odb/source-packed.c\nindex 42c28fba0e..fa5a072488 100644\n--- a/odb/source-packed.c\n+++ b/odb/source-packed.c\n@@ -15,7 +15,7 @@ static int find_pack_entry(struct odb_source_packed *store,\n {\n \tstruct packfile_list_entry *l;\n \n-\todb_source_packed_prepare(store);\n+\todb_source_prepare(&store->base, 0);\n \tif (store->midx && fill_midx_entry(store->midx, oid, e))\n \t\treturn 1;\n \n@@ -47,7 +47,7 @@ static int odb_source_packed_read_object_info(struct odb_source *source,\n \t * been added since the last time we have prepared the packfile store.\n \t */\n \tif (flags & OBJECT_INFO_SECOND_READ)\n-\t\todb_source_reprepare(source);\n+\t\todb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);\n \n \tif (!find_pack_entry(packed, oid, &e))\n \t\treturn 1;\n@@ -668,27 +668,25 @@ static int sort_pack(const struct packfile_list_entry *a,\n \treturn -1;\n }\n \n-void odb_source_packed_prepare(struct odb_source_packed *source)\n+static void odb_source_packed_prepare(struct odb_source *source,\n+\t\t\t\t      enum odb_prepare_flags flags)\n {\n-\tif (source->initialized)\n+\tstruct odb_source_packed *packed = odb_source_packed_downcast(source);\n+\n+\tif (flags & ODB_PREPARE_FLUSH_CACHES)\n+\t\tpacked->initialized = false;\n+\tif (packed->initialized)\n \t\treturn;\n \n-\tprepare_multi_pack_index_one(source);\n-\tprepare_packed_git_one(source);\n+\tprepare_multi_pack_index_one(packed);\n+\tprepare_packed_git_one(packed);\n \n-\tsort_packs(&source->packs.head, sort_pack);\n-\tfor (struct packfile_list_entry *e = source->packs.head; e; e = e->next)\n+\tsort_packs(&packed->packs.head, sort_pack);\n+\tfor (struct packfile_list_entry *e = packed->packs.head; e; e = e->next)\n \t\tif (!e->next)\n-\t\t\tsource->packs.tail = e;\n+\t\t\tpacked->packs.tail = e;\n \n-\tsource->initialized = true;\n-}\n-\n-static void odb_source_packed_reprepare(struct odb_source *source)\n-{\n-\tstruct odb_source_packed *packed = odb_source_packed_downcast(source);\n-\tpacked->initialized = false;\n-\todb_source_packed_prepare(packed);\n+\tpacked->initialized = true;\n }\n \n static void odb_source_packed_reparent(const char *name UNUSED,\n@@ -744,7 +742,7 @@ struct odb_source_packed *odb_source_packed_new(struct object_database *odb,\n \n \tpacked->base.free = odb_source_packed_free;\n \tpacked->base.close = odb_source_packed_close;\n-\tpacked->base.reprepare = odb_source_packed_reprepare;\n+\tpacked->base.prepare = odb_source_packed_prepare;\n \tpacked->base.read_object_info = odb_source_packed_read_object_info;\n \tpacked->base.read_object_stream = odb_source_packed_read_object_stream;\n \tpacked->base.for_each_object = odb_source_packed_for_each_object;\ndiff --git a/odb/source-packed.h b/odb/source-packed.h\nindex 88994098c1..d5230ac68c 100644\n--- a/odb/source-packed.h\n+++ b/odb/source-packed.h\n@@ -82,13 +82,4 @@ static inline struct odb_source_packed *odb_source_packed_downcast(struct odb_so\n \treturn container_of(source, struct odb_source_packed, base);\n }\n \n-/*\n- * Prepare the source by loading packfiles and multi-pack indices for\n- * all alternates. This becomes a no-op if the source is already prepared.\n- *\n- * It shouldn't typically be necessary to call this function directly, as\n- * functions that access the source know to prepare it.\n- */\n-void odb_source_packed_prepare(struct odb_source_packed *source);\n-\n #endif\ndiff --git a/odb/source.h b/odb/source.h\nindex b9a7642b2c..bbf1da3819 100644\n--- a/odb/source.h\n+++ b/odb/source.h\n@@ -83,11 +83,12 @@ struct odb_source {\n \tvoid (*close)(struct odb_source *source);\n \n \t/*\n-\t * This callback is expected to clear underlying caches of the object\n-\t * database source. The function is called when the repository has for\n-\t * example just been repacked so that new objects will become visible.\n+\t * This callback is expected to prepare the source so that it becomes\n+\t * ready for use. It optionally clears underlying caches of the object\n+\t * database source.\n \t */\n-\tvoid (*reprepare)(struct odb_source *source);\n+\tvoid (*prepare)(struct odb_source *source,\n+\t\t\tenum odb_prepare_flags flags);\n \n \t/*\n \t * This callback is expected to read object information from the object\n@@ -308,13 +309,14 @@ static inline void odb_source_close(struct odb_source *source)\n }\n \n /*\n- * Reprepare the object database source and clear any caches. Depending on the\n+ * Prepare the object database source and clear any caches. Depending on the\n  * backend used this may have the effect that concurrently-written objects\n  * become visible.\n  */\n-static inline void odb_source_reprepare(struct odb_source *source)\n+static inline void odb_source_prepare(struct odb_source *source,\n+\t\t\t\t      enum odb_prepare_flags flags)\n {\n-\tsource->reprepare(source);\n+\tsource->prepare(source, flags);\n }\n \n /*\ndiff --git a/packfile.c b/packfile.c\nindex 59cee7925d..d78fae981a 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -855,7 +855,7 @@ void for_each_file_in_pack_dir(const char *objdir,\n \n struct packfile_list_entry *packfile_store_get_packs(struct odb_source_packed *store)\n {\n-\todb_source_packed_prepare(store);\n+\todb_source_prepare(&store->base, 0);\n \n \tif (store->midx) {\n \t\tstruct multi_pack_index *m = store->midx;\n\n-- \n2.55.0.rc1.745.g43192e7977.dirty\n\n"},{"id":"546144","messageId":"20260622-b4-pks-odb-generalize-prepare-v1-2-d2a5c5d13144@pks.im","threadId":"65850","inReplyTo":"20260622-b4-pks-odb-generalize-prepare-v1-0-d2a5c5d13144@pks.im","subject":"[PATCH 2/2] odb: introduce `odb_prepare()`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-06-22T08:47:55Z","receivedAt":"2026-06-22T08:48:09Z","isPatch":true,"body":"Introduce `odb_prepare()` as a simple wrapper to prepare alternates and\nthen prepare each individual source. Adapt git-grep(1) to use it.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/grep.c |  9 ++-------\n odb.c          | 18 ++++++++++++------\n odb.h          |  8 ++++++--\n 3 files changed, 20 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 7361bf071e..a7252d56a1 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -1356,13 +1356,8 @@ int cmd_grep(int argc,\n \t\tif (recurse_submodules)\n \t\t\trepo_read_gitmodules(the_repository, 1);\n \n-\t\tif (startup_info->have_repository) {\n-\t\t\tstruct odb_source *source;\n-\n-\t\t\todb_prepare_alternates(the_repository->objects);\n-\t\t\tfor (source = the_repository->objects->sources; source; source = source->next)\n-\t\t\t\todb_source_prepare(source, 0);\n-\t\t}\n+\t\tif (startup_info->have_repository)\n+\t\t\todb_prepare(the_repository->objects, 0);\n \n \t\tstart_threads(&opt);\n \t} else {\ndiff --git a/odb.c b/odb.c\nindex 7b45390e12..11414c49a8 100644\n--- a/odb.c\n+++ b/odb.c\n@@ -1070,7 +1070,7 @@ void odb_free(struct object_database *o)\n \tfree(o);\n }\n \n-void odb_reprepare(struct object_database *o)\n+void odb_prepare(struct object_database *o, enum odb_prepare_flags flags)\n {\n \tstruct odb_source *source;\n \n@@ -1082,13 +1082,19 @@ void odb_reprepare(struct object_database *o)\n \t * the linked list, so existing odbs will continue to exist for\n \t * the lifetime of the process.\n \t */\n-\to->loaded_alternates = 0;\n-\todb_prepare_alternates(o);\n+\tif (flags & ODB_PREPARE_FLUSH_CACHES) {\n+\t\to->loaded_alternates = 0;\n+\t\to->object_count_valid = 0;\n+\t}\n \n+\todb_prepare_alternates(o);\n \tfor (source = o->sources; source; source = source->next)\n-\t\todb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);\n-\n-\to->object_count_valid = 0;\n+\t\todb_source_prepare(source, flags);\n \n \tobj_read_unlock();\n }\n+\n+void odb_reprepare(struct object_database *o)\n+{\n+\todb_prepare(o, ODB_PREPARE_FLUSH_CACHES);\n+}\ndiff --git a/odb.h b/odb.h\nindex c14c9030e4..b1c0f3767b 100644\n--- a/odb.h\n+++ b/odb.h\n@@ -133,9 +133,13 @@ enum odb_prepare_flags {\n };\n \n /*\n- * Clear caches, reload alternates and then reload object sources so that new\n- * objects may become accessible.\n+ * Prepare the object database for use. Calling this function is generally not\n+ * needed, but can be useful in case the caller wants to pre-open individual\n+ * sources.\n  */\n+void odb_prepare(struct object_database *o, enum odb_prepare_flags flags);\n+\n+/* Equivalent to `odb_prepare(o, ODB_PREPARE_FLUSH_CACHES)`. */\n void odb_reprepare(struct object_database *o);\n \n /*\n\n-- \n2.55.0.rc1.745.g43192e7977.dirty\n\n"},{"id":"546455","messageId":"87o6gx4i5w.fsf@emacs.iotcl.com","threadId":"65850","inReplyTo":"20260622-b4-pks-odb-generalize-prepare-v1-2-d2a5c5d13144@pks.im","subject":"Re: [PATCH 2/2] odb: introduce `odb_prepare()`","fromName":"Toon Claes","fromEmail":"toon@iotcl.com","sentAt":"2026-06-26T12:09:47Z","receivedAt":"2026-06-26T12:09:53Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> Introduce `odb_prepare()` as a simple wrapper to prepare alternates and\n> then prepare each individual source. Adapt git-grep(1) to use it.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  builtin/grep.c |  9 ++-------\n>  odb.c          | 18 ++++++++++++------\n>  odb.h          |  8 ++++++--\n>  3 files changed, 20 insertions(+), 15 deletions(-)\n>\n> diff --git a/builtin/grep.c b/builtin/grep.c\n> index 7361bf071e..a7252d56a1 100644\n> --- a/builtin/grep.c\n> +++ b/builtin/grep.c\n> @@ -1356,13 +1356,8 @@ int cmd_grep(int argc,\n>  \t\tif (recurse_submodules)\n>  \t\t\trepo_read_gitmodules(the_repository, 1);\n>  \n> -\t\tif (startup_info->have_repository) {\n> -\t\t\tstruct odb_source *source;\n> -\n> -\t\t\todb_prepare_alternates(the_repository->objects);\n> -\t\t\tfor (source = the_repository->objects->sources; source; source = source->next)\n> -\t\t\t\todb_source_prepare(source, 0);\n> -\t\t}\n> +\t\tif (startup_info->have_repository)\n> +\t\t\todb_prepare(the_repository->objects, 0);\n>  \n>  \t\tstart_threads(&opt);\n>  \t} else {\n> diff --git a/odb.c b/odb.c\n> index 7b45390e12..11414c49a8 100644\n> --- a/odb.c\n> +++ b/odb.c\n> @@ -1070,7 +1070,7 @@ void odb_free(struct object_database *o)\n>  \tfree(o);\n>  }\n>  \n> -void odb_reprepare(struct object_database *o)\n> +void odb_prepare(struct object_database *o, enum odb_prepare_flags flags)\n>  {\n>  \tstruct odb_source *source;\n>  \n> @@ -1082,13 +1082,19 @@ void odb_reprepare(struct object_database *o)\n>  \t * the linked list, so existing odbs will continue to exist for\n>  \t * the lifetime of the process.\n>  \t */\n> -\to->loaded_alternates = 0;\n> -\todb_prepare_alternates(o);\n> +\tif (flags & ODB_PREPARE_FLUSH_CACHES) {\n> +\t\to->loaded_alternates = 0;\n> +\t\to->object_count_valid = 0;\n> +\t}\n>  \n> +\todb_prepare_alternates(o);\n>  \tfor (source = o->sources; source; source = source->next)\n> -\t\todb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);\n> -\n> -\to->object_count_valid = 0;\n> +\t\todb_source_prepare(source, flags);\n>  \n>  \tobj_read_unlock();\n>  }\n> +\n> +void odb_reprepare(struct object_database *o)\n> +{\n> +\todb_prepare(o, ODB_PREPARE_FLUSH_CACHES);\n> +}\n> diff --git a/odb.h b/odb.h\n> index c14c9030e4..b1c0f3767b 100644\n> --- a/odb.h\n> +++ b/odb.h\n> @@ -133,9 +133,13 @@ enum odb_prepare_flags {\n>  };\n>  \n>  /*\n> - * Clear caches, reload alternates and then reload object sources so that new\n> - * objects may become accessible.\n> + * Prepare the object database for use. Calling this function is generally not\n> + * needed, but can be useful in case the caller wants to pre-open individual\n> + * sources.\n>   */\n> +void odb_prepare(struct object_database *o, enum odb_prepare_flags flags);\n> +\n> +/* Equivalent to `odb_prepare(o, ODB_PREPARE_FLUSH_CACHES)`. */\n>  void odb_reprepare(struct object_database *o);\n\nAccording to my grep results are there 17 callsites for odb_reprepare(),\nthen I agree it makes sense to create this wrapper.\n\n-- \nCheers,\nToon\n"},{"id":"546456","messageId":"87ldc14i4n.fsf@emacs.iotcl.com","threadId":"65850","inReplyTo":"20260622-b4-pks-odb-generalize-prepare-v1-1-d2a5c5d13144@pks.im","subject":"Re: [PATCH 1/2] odb/source: generalize `reprepare()` callback","fromName":"Toon Claes","fromEmail":"toon@iotcl.com","sentAt":"2026-06-26T12:10:32Z","receivedAt":"2026-06-26T12:10:38Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> The `reprepare()` callback function can be used to flush caches of a\n> given object source and then prepare it anew. This is for example used\n> when a concurrent process may have written new objects. Ultimately, this\n> can be seen as doing two separate steps:\n>\n>   1. We drop any caches.\n>\n>   2. We prepare the source.\n>\n> We have one callsite in git-grep(1) though that really only want to do\n> (2). This is done by reaching into the \"files\" backend directly and then\n> calling `odb_source_packed_prepare()`, which of course may not work with\n> alternate backends.\n>\n> We could in theory just call `reprepare()` here, and that would likely\n> not have any significant downside. But this would certainly feel like a\n> code smell.\n>\n> Instead, generalize the `reprepare()` callback to `prepare()` with a\n> flag that optionally instructs the backend to also flush the caches,\n> which allows us to drop the external `odb_source_packed_prepare()`\n> declaration.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  builtin/grep.c        |  9 +++------\n>  midx.c                |  2 +-\n>  odb.c                 |  2 +-\n>  odb.h                 |  8 ++++++++\n>  odb/source-files.c    |  9 +++++----\n>  odb/source-inmemory.c |  5 +++--\n>  odb/source-loose.c    |  8 +++++---\n>  odb/source-packed.c   | 34 ++++++++++++++++------------------\n>  odb/source-packed.h   |  9 ---------\n>  odb/source.h          | 16 +++++++++-------\n>  packfile.c            |  2 +-\n>  11 files changed, 52 insertions(+), 52 deletions(-)\n>\n> diff --git a/builtin/grep.c b/builtin/grep.c\n> index 8080d1bf5e..7361bf071e 100644\n> --- a/builtin/grep.c\n> +++ b/builtin/grep.c\n> @@ -25,12 +25,11 @@\n>  #include \"setup.h\"\n>  #include \"submodule.h\"\n>  #include \"submodule-config.h\"\n> -#include \"object-file.h\"\n>  #include \"object-name.h\"\n>  #include \"odb.h\"\n> +#include \"odb/source.h\"\n>  #include \"oid-array.h\"\n>  #include \"oidset.h\"\n> -#include \"packfile.h\"\n>  #include \"pager.h\"\n>  #include \"path.h\"\n>  #include \"promisor-remote.h\"\n> @@ -1361,10 +1360,8 @@ int cmd_grep(int argc,\n>  \t\t\tstruct odb_source *source;\n>  \n>  \t\t\todb_prepare_alternates(the_repository->objects);\n> -\t\t\tfor (source = the_repository->objects->sources; source; source = source->next) {\n> -\t\t\t\tstruct odb_source_files *files = odb_source_files_downcast(source);\n\nSo you're downcasting inside the implementation by the backends itself.\nThat makes sense, but would it be worth to say something about that in\nthe commit message?\n\n> -\t\t\t\todb_source_packed_prepare(files->packed);\n> -\t\t\t}\n> +\t\t\tfor (source = the_repository->objects->sources; source; source = source->next)\n> +\t\t\t\todb_source_prepare(source, 0);\n>  \t\t}\n>  \n>  \t\tstart_threads(&opt);\n> diff --git a/midx.c b/midx.c\n> index cc6b94f9dd..76c3f92cc3 100644\n> --- a/midx.c\n> +++ b/midx.c\n> @@ -101,7 +101,7 @@ static int midx_read_object_offsets(const unsigned char *chunk_start,\n>  \n>  struct multi_pack_index *get_multi_pack_index(struct odb_source_packed *source)\n>  {\n> -\todb_source_packed_prepare(source);\n> +\todb_source_prepare(&source->base, 0);\n>  \treturn source->midx;\n>  }\n>  \n> diff --git a/odb.c b/odb.c\n> index 965ef68e4e..7b45390e12 100644\n> --- a/odb.c\n> +++ b/odb.c\n> @@ -1086,7 +1086,7 @@ void odb_reprepare(struct object_database *o)\n>  \todb_prepare_alternates(o);\n>  \n>  \tfor (source = o->sources; source; source = source->next)\n> -\t\todb_source_reprepare(source);\n> +\t\todb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);\n>  \n>  \to->object_count_valid = 0;\n>  \n> diff --git a/odb.h b/odb.h\n> index 0030467a52..c14c9030e4 100644\n> --- a/odb.h\n> +++ b/odb.h\n> @@ -124,6 +124,14 @@ void odb_free(struct object_database *o);\n>   */\n>  void odb_close(struct object_database *o);\n>  \n> +enum odb_prepare_flags {\n> +\t/*\n> +\t * Flush caches, reload alternates and then re-prepare each object\n> +\t * source so that new objects may become accessible.\n> +\t */\n> +\tODB_PREPARE_FLUSH_CACHES = (1 << 0),\n> +};\n> +\n>  /*\n>   * Clear caches, reload alternates and then reload object sources so that new\n>   * objects may become accessible.\n> diff --git a/odb/source-files.c b/odb/source-files.c\n> index 3bc6419dd7..ad9e0b52f9 100644\n> --- a/odb/source-files.c\n> +++ b/odb/source-files.c\n> @@ -41,11 +41,12 @@ static void odb_source_files_close(struct odb_source *source)\n>  \todb_source_close(&files->packed->base);\n>  }\n>  \n> -static void odb_source_files_reprepare(struct odb_source *source)\n> +static void odb_source_files_prepare(struct odb_source *source,\n> +\t\t\t\t     enum odb_prepare_flags flags)\n>  {\n>  \tstruct odb_source_files *files = odb_source_files_downcast(source);\n> -\todb_source_reprepare(&files->loose->base);\n> -\todb_source_reprepare(&files->packed->base);\n> +\todb_source_prepare(&files->loose->base, flags);\n> +\todb_source_prepare(&files->packed->base, flags);\n>  }\n>  \n>  static int odb_source_files_read_object_info(struct odb_source *source,\n> @@ -273,7 +274,7 @@ struct odb_source_files *odb_source_files_new(struct object_database *odb,\n>  \n>  \tfiles->base.free = odb_source_files_free;\n>  \tfiles->base.close = odb_source_files_close;\n> -\tfiles->base.reprepare = odb_source_files_reprepare;\n> +\tfiles->base.prepare = odb_source_files_prepare;\n>  \tfiles->base.read_object_info = odb_source_files_read_object_info;\n>  \tfiles->base.read_object_stream = odb_source_files_read_object_stream;\n>  \tfiles->base.for_each_object = odb_source_files_for_each_object;\n> diff --git a/odb/source-inmemory.c b/odb/source-inmemory.c\n> index e004566d76..cc5e9e62cb 100644\n> --- a/odb/source-inmemory.c\n> +++ b/odb/source-inmemory.c\n> @@ -325,7 +325,8 @@ static void odb_source_inmemory_close(struct odb_source *source UNUSED)\n>  {\n>  }\n>  \n> -static void odb_source_inmemory_reprepare(struct odb_source *source UNUSED)\n> +static void odb_source_inmemory_prepare(struct odb_source *source UNUSED,\n> +\t\t\t\t\tenum odb_prepare_flags flags UNUSED)\n>  {\n>  }\n>  \n> @@ -365,7 +366,7 @@ struct odb_source_inmemory *odb_source_inmemory_new(struct object_database *odb)\n>  \n>  \tsource->base.free = odb_source_inmemory_free;\n>  \tsource->base.close = odb_source_inmemory_close;\n> -\tsource->base.reprepare = odb_source_inmemory_reprepare;\n> +\tsource->base.prepare = odb_source_inmemory_prepare;\n>  \tsource->base.read_object_info = odb_source_inmemory_read_object_info;\n>  \tsource->base.read_object_stream = odb_source_inmemory_read_object_stream;\n>  \tsource->base.for_each_object = odb_source_inmemory_for_each_object;\n> diff --git a/odb/source-loose.c b/odb/source-loose.c\n> index 7d7ea2fb84..af46316e35 100644\n> --- a/odb/source-loose.c\n> +++ b/odb/source-loose.c\n> @@ -672,10 +672,12 @@ static void odb_source_loose_clear_cache(struct odb_source_loose *loose)\n>  \t       sizeof(loose->subdir_seen));\n>  }\n>  \n> -static void odb_source_loose_reprepare(struct odb_source *source)\n> +static void odb_source_loose_prepare(struct odb_source *source,\n> +\t\t\t\t     enum odb_prepare_flags flags)\n>  {\n>  \tstruct odb_source_loose *loose = odb_source_loose_downcast(source);\n> -\todb_source_loose_clear_cache(loose);\n> +\tif (flags & ODB_PREPARE_FLUSH_CACHES)\n> +\t\todb_source_loose_clear_cache(loose);\n>  }\n>  \n>  static void odb_source_loose_close(struct odb_source *source UNUSED)\n> @@ -716,7 +718,7 @@ struct odb_source_loose *odb_source_loose_new(struct object_database *odb,\n>  \n>  \tloose->base.free = odb_source_loose_free;\n>  \tloose->base.close = odb_source_loose_close;\n> -\tloose->base.reprepare = odb_source_loose_reprepare;\n> +\tloose->base.prepare = odb_source_loose_prepare;\n>  \tloose->base.read_object_info = odb_source_loose_read_object_info;\n>  \tloose->base.read_object_stream = odb_source_loose_read_object_stream;\n>  \tloose->base.for_each_object = odb_source_loose_for_each_object;\n> diff --git a/odb/source-packed.c b/odb/source-packed.c\n> index 42c28fba0e..fa5a072488 100644\n> --- a/odb/source-packed.c\n> +++ b/odb/source-packed.c\n> @@ -15,7 +15,7 @@ static int find_pack_entry(struct odb_source_packed *store,\n>  {\n>  \tstruct packfile_list_entry *l;\n>  \n> -\todb_source_packed_prepare(store);\n> +\todb_source_prepare(&store->base, 0);\n\nWhy are you not using ODB_PREPARE_FLUSH_CACHES here? It used to do\nbefore?\n\n>  \tif (store->midx && fill_midx_entry(store->midx, oid, e))\n>  \t\treturn 1;\n>  \n> @@ -47,7 +47,7 @@ static int odb_source_packed_read_object_info(struct odb_source *source,\n>  \t * been added since the last time we have prepared the packfile store.\n>  \t */\n>  \tif (flags & OBJECT_INFO_SECOND_READ)\n> -\t\todb_source_reprepare(source);\n> +\t\todb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);\n\nI think the new code is correct, but why wasn't `packed` used here in\nthe past? The old odb_source_reprepare() expected a downcasted, didn't\nit?\n\n>  \n>  \tif (!find_pack_entry(packed, oid, &e))\n>  \t\treturn 1;\n> @@ -668,27 +668,25 @@ static int sort_pack(const struct packfile_list_entry *a,\n>  \treturn -1;\n>  }\n>  \n> -void odb_source_packed_prepare(struct odb_source_packed *source)\n> +static void odb_source_packed_prepare(struct odb_source *source,\n> +\t\t\t\t      enum odb_prepare_flags flags)\n>  {\n> -\tif (source->initialized)\n> +\tstruct odb_source_packed *packed = odb_source_packed_downcast(source);\n> +\n> +\tif (flags & ODB_PREPARE_FLUSH_CACHES)\n> +\t\tpacked->initialized = false;\n> +\tif (packed->initialized)\n>  \t\treturn;\n>  \n> -\tprepare_multi_pack_index_one(source);\n> -\tprepare_packed_git_one(source);\n> +\tprepare_multi_pack_index_one(packed);\n> +\tprepare_packed_git_one(packed);\n>  \n> -\tsort_packs(&source->packs.head, sort_pack);\n> -\tfor (struct packfile_list_entry *e = source->packs.head; e; e = e->next)\n> +\tsort_packs(&packed->packs.head, sort_pack);\n> +\tfor (struct packfile_list_entry *e = packed->packs.head; e; e = e->next)\n>  \t\tif (!e->next)\n> -\t\t\tsource->packs.tail = e;\n> +\t\t\tpacked->packs.tail = e;\n>  \n> -\tsource->initialized = true;\n> -}\n> -\n> -static void odb_source_packed_reprepare(struct odb_source *source)\n> -{\n> -\tstruct odb_source_packed *packed = odb_source_packed_downcast(source);\n> -\tpacked->initialized = false;\n> -\todb_source_packed_prepare(packed);\n> +\tpacked->initialized = true;\n>  }\n>  \n>  static void odb_source_packed_reparent(const char *name UNUSED,\n> @@ -744,7 +742,7 @@ struct odb_source_packed *odb_source_packed_new(struct object_database *odb,\n>  \n>  \tpacked->base.free = odb_source_packed_free;\n>  \tpacked->base.close = odb_source_packed_close;\n> -\tpacked->base.reprepare = odb_source_packed_reprepare;\n> +\tpacked->base.prepare = odb_source_packed_prepare;\n>  \tpacked->base.read_object_info = odb_source_packed_read_object_info;\n>  \tpacked->base.read_object_stream = odb_source_packed_read_object_stream;\n>  \tpacked->base.for_each_object = odb_source_packed_for_each_object;\n> diff --git a/odb/source-packed.h b/odb/source-packed.h\n> index 88994098c1..d5230ac68c 100644\n> --- a/odb/source-packed.h\n> +++ b/odb/source-packed.h\n> @@ -82,13 +82,4 @@ static inline struct odb_source_packed *odb_source_packed_downcast(struct odb_so\n>  \treturn container_of(source, struct odb_source_packed, base);\n>  }\n>  \n> -/*\n> - * Prepare the source by loading packfiles and multi-pack indices for\n> - * all alternates. This becomes a no-op if the source is already prepared.\n> - *\n> - * It shouldn't typically be necessary to call this function directly, as\n> - * functions that access the source know to prepare it.\n> - */\n> -void odb_source_packed_prepare(struct odb_source_packed *source);\n> -\n>  #endif\n> diff --git a/odb/source.h b/odb/source.h\n> index b9a7642b2c..bbf1da3819 100644\n> --- a/odb/source.h\n> +++ b/odb/source.h\n> @@ -83,11 +83,12 @@ struct odb_source {\n>  \tvoid (*close)(struct odb_source *source);\n>  \n>  \t/*\n> -\t * This callback is expected to clear underlying caches of the object\n> -\t * database source. The function is called when the repository has for\n> -\t * example just been repacked so that new objects will become visible.\n> +\t * This callback is expected to prepare the source so that it becomes\n> +\t * ready for use. It optionally clears underlying caches of the object\n> +\t * database source.\n>  \t */\n> -\tvoid (*reprepare)(struct odb_source *source);\n> +\tvoid (*prepare)(struct odb_source *source,\n> +\t\t\tenum odb_prepare_flags flags);\n>  \n>  \t/*\n>  \t * This callback is expected to read object information from the object\n> @@ -308,13 +309,14 @@ static inline void odb_source_close(struct odb_source *source)\n>  }\n>  \n>  /*\n> - * Reprepare the object database source and clear any caches. Depending on the\n> + * Prepare the object database source and clear any caches. Depending on the\n>   * backend used this may have the effect that concurrently-written objects\n>   * become visible.\n>   */\n> -static inline void odb_source_reprepare(struct odb_source *source)\n> +static inline void odb_source_prepare(struct odb_source *source,\n> +\t\t\t\t      enum odb_prepare_flags flags)\n>  {\n> -\tsource->reprepare(source);\n> +\tsource->prepare(source, flags);\n>  }\n>  \n>  /*\n> diff --git a/packfile.c b/packfile.c\n> index 59cee7925d..d78fae981a 100644\n> --- a/packfile.c\n> +++ b/packfile.c\n> @@ -855,7 +855,7 @@ void for_each_file_in_pack_dir(const char *objdir,\n>  \n>  struct packfile_list_entry *packfile_store_get_packs(struct odb_source_packed *store)\n>  {\n> -\todb_source_packed_prepare(store);\n> +\todb_source_prepare(&store->base, 0);\n>  \n>  \tif (store->midx) {\n>  \t\tstruct multi_pack_index *m = store->midx;\n>\n> -- \n> 2.55.0.rc1.745.g43192e7977.dirty\n>\n>\n\n-- \nCheers,\nToon\n"},{"id":"546625","messageId":"akINy-hP5EPD4Y4e@pks.im","threadId":"65850","inReplyTo":"87ldc14i4n.fsf@emacs.iotcl.com","subject":"Re: [PATCH 1/2] odb/source: generalize `reprepare()` callback","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-06-29T06:16:43Z","receivedAt":"2026-06-29T06:16:49Z","isPatch":true,"body":"On Fri, Jun 26, 2026 at 02:10:32PM +0200, Toon Claes wrote:\n> > diff --git a/builtin/grep.c b/builtin/grep.c\n> > index 8080d1bf5e..7361bf071e 100644\n> > --- a/builtin/grep.c\n> > +++ b/builtin/grep.c\n> > @@ -1361,10 +1360,8 @@ int cmd_grep(int argc,\n> >  \t\t\tstruct odb_source *source;\n> >  \n> >  \t\t\todb_prepare_alternates(the_repository->objects);\n> > -\t\t\tfor (source = the_repository->objects->sources; source; source = source->next) {\n> > -\t\t\t\tstruct odb_source_files *files = odb_source_files_downcast(source);\n> \n> So you're downcasting inside the implementation by the backends itself.\n> That makes sense, but would it be worth to say something about that in\n> the commit message?\n\nHm. Would that provide much value? I'm probably quite a bit biased here,\nbut I think that it's implicit that the backends have to eventually cast\nthe generic structure to their own backend.\n\nSo I wouldn't really know how to clarify this. Did you have anything\nspecific in mind?\n\n> > diff --git a/odb/source-packed.c b/odb/source-packed.c\n> > index 42c28fba0e..fa5a072488 100644\n> > --- a/odb/source-packed.c\n> > +++ b/odb/source-packed.c\n> > @@ -15,7 +15,7 @@ static int find_pack_entry(struct odb_source_packed *store,\n> >  {\n> >  \tstruct packfile_list_entry *l;\n> >  \n> > -\todb_source_packed_prepare(store);\n> > +\todb_source_prepare(&store->base, 0);\n> \n> Why are you not using ODB_PREPARE_FLUSH_CACHES here? It used to do\n> before?\n\nBecause this was calling `odb_source_packed_prepare()` before, not\n`odb_source_reprepare()`. So this was calling the non-flushing variant.\n\n> >  \tif (store->midx && fill_midx_entry(store->midx, oid, e))\n> >  \t\treturn 1;\n> >  \n> > @@ -47,7 +47,7 @@ static int odb_source_packed_read_object_info(struct odb_source *source,\n> >  \t * been added since the last time we have prepared the packfile store.\n> >  \t */\n> >  \tif (flags & OBJECT_INFO_SECOND_READ)\n> > -\t\todb_source_reprepare(source);\n> > +\t\todb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);\n> \n> I think the new code is correct, but why wasn't `packed` used here in\n> the past? The old odb_source_reprepare() expected a downcasted, didn't\n> it?\n\nNo, `odb_source_reprepare()` is the generic variant. The naming schema\nis typically:\n\n  - `odb_source_frobnicate()` for the generic variants, which receive a\n    `struct odb_source` as input.\n\n  - `odb_source_<type>_frobnitcate()` for their backend-specific\n    implementations, which cast down the generic `struct odb_source` to\n    their backend-specific struct.\n\nThanks!\n\nPatrick\n"},{"id":"546626","messageId":"akIN0CxVxhaHnvJ0@pks.im","threadId":"65850","inReplyTo":"87o6gx4i5w.fsf@emacs.iotcl.com","subject":"Re: [PATCH 2/2] odb: introduce `odb_prepare()`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-06-29T06:16:48Z","receivedAt":"2026-06-29T06:16:52Z","isPatch":true,"body":"On Fri, Jun 26, 2026 at 02:09:47PM +0200, Toon Claes wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> > diff --git a/odb.h b/odb.h\n> > index c14c9030e4..b1c0f3767b 100644\n> > --- a/odb.h\n> > +++ b/odb.h\n> > @@ -133,9 +133,13 @@ enum odb_prepare_flags {\n> >  };\n> >  \n> >  /*\n> > - * Clear caches, reload alternates and then reload object sources so that new\n> > - * objects may become accessible.\n> > + * Prepare the object database for use. Calling this function is generally not\n> > + * needed, but can be useful in case the caller wants to pre-open individual\n> > + * sources.\n> >   */\n> > +void odb_prepare(struct object_database *o, enum odb_prepare_flags flags);\n> > +\n> > +/* Equivalent to `odb_prepare(o, ODB_PREPARE_FLUSH_CACHES)`. */\n> >  void odb_reprepare(struct object_database *o);\n> \n> According to my grep results are there 17 callsites for odb_reprepare(),\n> then I agree it makes sense to create this wrapper.\n\nYeah, I was a bit torn myself whether or not to keep the wrapper. I\neventually decided to just keep it because it reduces churn, and it's a\ntrivial wrapper anyway.\n\nThanks!\n\nPatrick\n"},{"id":"546721","messageId":"xmqqa4sdt3e6.fsf@gitster.g","threadId":"65850","inReplyTo":"akIN0CxVxhaHnvJ0@pks.im","subject":"Re: [PATCH 2/2] odb: introduce `odb_prepare()`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-29T21:58:41Z","receivedAt":"2026-06-29T21:58:44Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n>> According to my grep results are there 17 callsites for odb_reprepare(),\n>> then I agree it makes sense to create this wrapper.\n>\n> Yeah, I was a bit torn myself whether or not to keep the wrapper. I\n> eventually decided to just keep it because it reduces churn, and it's a\n> trivial wrapper anyway.\n\nThat sounds OK.  Are we all happy with the current shape of the\ntopic?  I myself did not find anything iffy in these two patches.\n\nThanks.\n"},{"id":"546738","messageId":"87ik704f1j.fsf@emacs.iotcl.com","threadId":"65850","inReplyTo":"akINy-hP5EPD4Y4e@pks.im","subject":"Re: [PATCH 1/2] odb/source: generalize `reprepare()` callback","fromName":"Toon Claes","fromEmail":"toon@iotcl.com","sentAt":"2026-06-30T08:18:32Z","receivedAt":"2026-06-30T08:18:41Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> On Fri, Jun 26, 2026 at 02:10:32PM +0200, Toon Claes wrote:\n>> > diff --git a/builtin/grep.c b/builtin/grep.c\n>> > index 8080d1bf5e..7361bf071e 100644\n>> > --- a/builtin/grep.c\n>> > +++ b/builtin/grep.c\n>> > @@ -1361,10 +1360,8 @@ int cmd_grep(int argc,\n>> >  \t\t\tstruct odb_source *source;\n>> >  \n>> >  \t\t\todb_prepare_alternates(the_repository->objects);\n>> > -\t\t\tfor (source = the_repository->objects->sources; source; source = source->next) {\n>> > -\t\t\t\tstruct odb_source_files *files = odb_source_files_downcast(source);\n>> > -\t\t\t\todb_source_packed_prepare(files->packed);\n>> > +\t\t\tfor (source = the_repository->objects->sources; source; source = source->next)\n>> > +\t\t\t\todb_source_prepare(source, 0);\n>> \n>> So you're downcasting inside the implementation by the backends itself.\n>> That makes sense, but would it be worth to say something about that in\n>> the commit message?\n>\n> Hm. Would that provide much value? I'm probably quite a bit biased here,\n> but I think that it's implicit that the backends have to eventually cast\n> the generic structure to their own backend.\n>\n> So I wouldn't really know how to clarify this. Did you have anything\n> specific in mind?\n\nAh, I'm sorry, I misread that. I thought you changed the vtable function\nto do the downcasting, but you're simply changing from calling a \n`*_packed_*()` to the generic variant that goes through the vtable.\n\nAnyhow, not worth mentioning in the commit message.\n\n>> > diff --git a/odb/source-packed.c b/odb/source-packed.c\n>> > index 42c28fba0e..fa5a072488 100644\n>> > --- a/odb/source-packed.c\n>> > +++ b/odb/source-packed.c\n>> > @@ -15,7 +15,7 @@ static int find_pack_entry(struct odb_source_packed *store,\n>> >  {\n>> >  \tstruct packfile_list_entry *l;\n>> >  \n>> > -\todb_source_packed_prepare(store);\n>> > +\todb_source_prepare(&store->base, 0);\n>> \n>> Why are you not using ODB_PREPARE_FLUSH_CACHES here? It used to do\n>> before?\n>\n> Because this was calling `odb_source_packed_prepare()` before, not\n> `odb_source_reprepare()`. So this was calling the non-flushing\n> variant.\n\nAgain, confusion on my end.\n\n>> >  \tif (store->midx && fill_midx_entry(store->midx, oid, e))\n>> >  \t\treturn 1;\n>> >  \n>> > @@ -47,7 +47,7 @@ static int odb_source_packed_read_object_info(struct odb_source *source,\n>> >  \t * been added since the last time we have prepared the packfile store.\n>> >  \t */\n>> >  \tif (flags & OBJECT_INFO_SECOND_READ)\n>> > -\t\todb_source_reprepare(source);\n>> > +\t\todb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);\n>> \n>> I think the new code is correct, but why wasn't `packed` used here in\n>> the past? The old odb_source_reprepare() expected a downcasted, didn't\n>> it?\n>\n> No, `odb_source_reprepare()` is the generic variant. The naming schema\n> is typically:\n>\n>   - `odb_source_frobnicate()` for the generic variants, which receive a\n>     `struct odb_source` as input.\n>\n>   - `odb_source_<type>_frobnitcate()` for their backend-specific\n>     implementations, which cast down the generic `struct odb_source` to\n>     their backend-specific struct.\n\nYeah, I understand things better now. Thanks for clarifying.\n\n-- \nCheers,\nToon\n"},{"id":"546740","messageId":"akN-3GYpI7OmkBuO@pks.im","threadId":"65850","inReplyTo":"xmqqa4sdt3e6.fsf@gitster.g","subject":"Re: [PATCH 2/2] odb: introduce `odb_prepare()`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-06-30T08:31:24Z","receivedAt":"2026-06-30T08:31:31Z","isPatch":true,"body":"On Mon, Jun 29, 2026 at 02:58:41PM -0700, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> >> According to my grep results are there 17 callsites for odb_reprepare(),\n> >> then I agree it makes sense to create this wrapper.\n> >\n> > Yeah, I was a bit torn myself whether or not to keep the wrapper. I\n> > eventually decided to just keep it because it reduces churn, and it's a\n> > trivial wrapper anyway.\n> \n> That sounds OK.  Are we all happy with the current shape of the\n> topic?  I myself did not find anything iffy in these two patches.\n\nBased on Toon's reply [1] it seems like this series is ready to go.\nThanks!\n\nPatrick\n\n[1]: <87ik704f1j.fsf@emacs.iotcl.com>\n"}]}