Git development
 help / color / mirror / Atom feed
* [PATCH 0/2] odb: generalize `reprepare()` callback
@ 2026-06-22  8:47 Patrick Steinhardt
  2026-06-22  8:47 ` [PATCH 1/2] odb/source: " Patrick Steinhardt
  2026-06-22  8:47 ` [PATCH 2/2] odb: introduce `odb_prepare()` Patrick Steinhardt
  0 siblings, 2 replies; 5+ messages in thread
From: Patrick Steinhardt @ 2026-06-22  8:47 UTC (permalink / raw)
  To: git

Hi,

this small patch series generalizes the `reprepare()` callback into a
`prepare()` callback that accepts an optional flag to also discard any
caches. This is required so that we can make git-grep(1) become fully
generic.

The series is built on top of 8d96f09e92 (Merge branch
'js/objects-larger-than-4gb-on-windows', 2026-06-19) with
ps/odb-source-packed at 1bba3c035d (odb/source-packed: drop pointer to
"files" parent source, 2026-06-17) merged into it.

Thanks!

Patrick

---
Patrick Steinhardt (2):
      odb/source: generalize `reprepare()` callback
      odb: introduce `odb_prepare()`

 builtin/grep.c        | 14 +++-----------
 midx.c                |  2 +-
 odb.c                 | 18 ++++++++++++------
 odb.h                 | 16 ++++++++++++++--
 odb/source-files.c    |  9 +++++----
 odb/source-inmemory.c |  5 +++--
 odb/source-loose.c    |  8 +++++---
 odb/source-packed.c   | 34 ++++++++++++++++------------------
 odb/source-packed.h   |  9 ---------
 odb/source.h          | 16 +++++++++-------
 packfile.c            |  2 +-
 11 files changed, 69 insertions(+), 64 deletions(-)


---
base-commit: 4a8e7a446f41435e157131162dfe901eca9250fe
change-id: 20260612-b4-pks-odb-generalize-prepare-509ffc18f502


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] odb/source: generalize `reprepare()` callback
  2026-06-22  8:47 [PATCH 0/2] odb: generalize `reprepare()` callback Patrick Steinhardt
@ 2026-06-22  8:47 ` Patrick Steinhardt
  2026-06-26 12:10   ` Toon Claes
  2026-06-22  8:47 ` [PATCH 2/2] odb: introduce `odb_prepare()` Patrick Steinhardt
  1 sibling, 1 reply; 5+ messages in thread
From: Patrick Steinhardt @ 2026-06-22  8:47 UTC (permalink / raw)
  To: git

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>
---
 builtin/grep.c        |  9 +++------
 midx.c                |  2 +-
 odb.c                 |  2 +-
 odb.h                 |  8 ++++++++
 odb/source-files.c    |  9 +++++----
 odb/source-inmemory.c |  5 +++--
 odb/source-loose.c    |  8 +++++---
 odb/source-packed.c   | 34 ++++++++++++++++------------------
 odb/source-packed.h   |  9 ---------
 odb/source.h          | 16 +++++++++-------
 packfile.c            |  2 +-
 11 files changed, 52 insertions(+), 52 deletions(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 8080d1bf5e..7361bf071e 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -25,12 +25,11 @@
 #include "setup.h"
 #include "submodule.h"
 #include "submodule-config.h"
-#include "object-file.h"
 #include "object-name.h"
 #include "odb.h"
+#include "odb/source.h"
 #include "oid-array.h"
 #include "oidset.h"
-#include "packfile.h"
 #include "pager.h"
 #include "path.h"
 #include "promisor-remote.h"
@@ -1361,10 +1360,8 @@ int cmd_grep(int argc,
 			struct odb_source *source;
 
 			odb_prepare_alternates(the_repository->objects);
-			for (source = the_repository->objects->sources; source; source = source->next) {
-				struct odb_source_files *files = odb_source_files_downcast(source);
-				odb_source_packed_prepare(files->packed);
-			}
+			for (source = the_repository->objects->sources; source; source = source->next)
+				odb_source_prepare(source, 0);
 		}
 
 		start_threads(&opt);
diff --git a/midx.c b/midx.c
index cc6b94f9dd..76c3f92cc3 100644
--- a/midx.c
+++ b/midx.c
@@ -101,7 +101,7 @@ static int midx_read_object_offsets(const unsigned char *chunk_start,
 
 struct multi_pack_index *get_multi_pack_index(struct odb_source_packed *source)
 {
-	odb_source_packed_prepare(source);
+	odb_source_prepare(&source->base, 0);
 	return source->midx;
 }
 
diff --git a/odb.c b/odb.c
index 965ef68e4e..7b45390e12 100644
--- a/odb.c
+++ b/odb.c
@@ -1086,7 +1086,7 @@ void odb_reprepare(struct object_database *o)
 	odb_prepare_alternates(o);
 
 	for (source = o->sources; source; source = source->next)
-		odb_source_reprepare(source);
+		odb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);
 
 	o->object_count_valid = 0;
 
diff --git a/odb.h b/odb.h
index 0030467a52..c14c9030e4 100644
--- a/odb.h
+++ b/odb.h
@@ -124,6 +124,14 @@ void odb_free(struct object_database *o);
  */
 void odb_close(struct object_database *o);
 
+enum odb_prepare_flags {
+	/*
+	 * Flush caches, reload alternates and then re-prepare each object
+	 * source so that new objects may become accessible.
+	 */
+	ODB_PREPARE_FLUSH_CACHES = (1 << 0),
+};
+
 /*
  * Clear caches, reload alternates and then reload object sources so that new
  * objects may become accessible.
diff --git a/odb/source-files.c b/odb/source-files.c
index 3bc6419dd7..ad9e0b52f9 100644
--- a/odb/source-files.c
+++ b/odb/source-files.c
@@ -41,11 +41,12 @@ static void odb_source_files_close(struct odb_source *source)
 	odb_source_close(&files->packed->base);
 }
 
-static void odb_source_files_reprepare(struct odb_source *source)
+static void odb_source_files_prepare(struct odb_source *source,
+				     enum odb_prepare_flags flags)
 {
 	struct odb_source_files *files = odb_source_files_downcast(source);
-	odb_source_reprepare(&files->loose->base);
-	odb_source_reprepare(&files->packed->base);
+	odb_source_prepare(&files->loose->base, flags);
+	odb_source_prepare(&files->packed->base, flags);
 }
 
 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,
 
 	files->base.free = odb_source_files_free;
 	files->base.close = odb_source_files_close;
-	files->base.reprepare = odb_source_files_reprepare;
+	files->base.prepare = odb_source_files_prepare;
 	files->base.read_object_info = odb_source_files_read_object_info;
 	files->base.read_object_stream = odb_source_files_read_object_stream;
 	files->base.for_each_object = odb_source_files_for_each_object;
diff --git a/odb/source-inmemory.c b/odb/source-inmemory.c
index e004566d76..cc5e9e62cb 100644
--- a/odb/source-inmemory.c
+++ b/odb/source-inmemory.c
@@ -325,7 +325,8 @@ static void odb_source_inmemory_close(struct odb_source *source UNUSED)
 {
 }
 
-static void odb_source_inmemory_reprepare(struct odb_source *source UNUSED)
+static void odb_source_inmemory_prepare(struct odb_source *source UNUSED,
+					enum odb_prepare_flags flags UNUSED)
 {
 }
 
@@ -365,7 +366,7 @@ struct odb_source_inmemory *odb_source_inmemory_new(struct object_database *odb)
 
 	source->base.free = odb_source_inmemory_free;
 	source->base.close = odb_source_inmemory_close;
-	source->base.reprepare = odb_source_inmemory_reprepare;
+	source->base.prepare = odb_source_inmemory_prepare;
 	source->base.read_object_info = odb_source_inmemory_read_object_info;
 	source->base.read_object_stream = odb_source_inmemory_read_object_stream;
 	source->base.for_each_object = odb_source_inmemory_for_each_object;
diff --git a/odb/source-loose.c b/odb/source-loose.c
index 7d7ea2fb84..af46316e35 100644
--- a/odb/source-loose.c
+++ b/odb/source-loose.c
@@ -672,10 +672,12 @@ static void odb_source_loose_clear_cache(struct odb_source_loose *loose)
 	       sizeof(loose->subdir_seen));
 }
 
-static void odb_source_loose_reprepare(struct odb_source *source)
+static void odb_source_loose_prepare(struct odb_source *source,
+				     enum odb_prepare_flags flags)
 {
 	struct odb_source_loose *loose = odb_source_loose_downcast(source);
-	odb_source_loose_clear_cache(loose);
+	if (flags & ODB_PREPARE_FLUSH_CACHES)
+		odb_source_loose_clear_cache(loose);
 }
 
 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,
 
 	loose->base.free = odb_source_loose_free;
 	loose->base.close = odb_source_loose_close;
-	loose->base.reprepare = odb_source_loose_reprepare;
+	loose->base.prepare = odb_source_loose_prepare;
 	loose->base.read_object_info = odb_source_loose_read_object_info;
 	loose->base.read_object_stream = odb_source_loose_read_object_stream;
 	loose->base.for_each_object = odb_source_loose_for_each_object;
diff --git a/odb/source-packed.c b/odb/source-packed.c
index 42c28fba0e..fa5a072488 100644
--- a/odb/source-packed.c
+++ b/odb/source-packed.c
@@ -15,7 +15,7 @@ static int find_pack_entry(struct odb_source_packed *store,
 {
 	struct packfile_list_entry *l;
 
-	odb_source_packed_prepare(store);
+	odb_source_prepare(&store->base, 0);
 	if (store->midx && fill_midx_entry(store->midx, oid, e))
 		return 1;
 
@@ -47,7 +47,7 @@ static int odb_source_packed_read_object_info(struct odb_source *source,
 	 * been added since the last time we have prepared the packfile store.
 	 */
 	if (flags & OBJECT_INFO_SECOND_READ)
-		odb_source_reprepare(source);
+		odb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);
 
 	if (!find_pack_entry(packed, oid, &e))
 		return 1;
@@ -668,27 +668,25 @@ static int sort_pack(const struct packfile_list_entry *a,
 	return -1;
 }
 
-void odb_source_packed_prepare(struct odb_source_packed *source)
+static void odb_source_packed_prepare(struct odb_source *source,
+				      enum odb_prepare_flags flags)
 {
-	if (source->initialized)
+	struct odb_source_packed *packed = odb_source_packed_downcast(source);
+
+	if (flags & ODB_PREPARE_FLUSH_CACHES)
+		packed->initialized = false;
+	if (packed->initialized)
 		return;
 
-	prepare_multi_pack_index_one(source);
-	prepare_packed_git_one(source);
+	prepare_multi_pack_index_one(packed);
+	prepare_packed_git_one(packed);
 
-	sort_packs(&source->packs.head, sort_pack);
-	for (struct packfile_list_entry *e = source->packs.head; e; e = e->next)
+	sort_packs(&packed->packs.head, sort_pack);
+	for (struct packfile_list_entry *e = packed->packs.head; e; e = e->next)
 		if (!e->next)
-			source->packs.tail = e;
+			packed->packs.tail = e;
 
-	source->initialized = true;
-}
-
-static void odb_source_packed_reprepare(struct odb_source *source)
-{
-	struct odb_source_packed *packed = odb_source_packed_downcast(source);
-	packed->initialized = false;
-	odb_source_packed_prepare(packed);
+	packed->initialized = true;
 }
 
 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,
 
 	packed->base.free = odb_source_packed_free;
 	packed->base.close = odb_source_packed_close;
-	packed->base.reprepare = odb_source_packed_reprepare;
+	packed->base.prepare = odb_source_packed_prepare;
 	packed->base.read_object_info = odb_source_packed_read_object_info;
 	packed->base.read_object_stream = odb_source_packed_read_object_stream;
 	packed->base.for_each_object = odb_source_packed_for_each_object;
diff --git a/odb/source-packed.h b/odb/source-packed.h
index 88994098c1..d5230ac68c 100644
--- a/odb/source-packed.h
+++ b/odb/source-packed.h
@@ -82,13 +82,4 @@ static inline struct odb_source_packed *odb_source_packed_downcast(struct odb_so
 	return container_of(source, struct odb_source_packed, base);
 }
 
-/*
- * Prepare the source by loading packfiles and multi-pack indices for
- * all alternates. This becomes a no-op if the source is already prepared.
- *
- * It shouldn't typically be necessary to call this function directly, as
- * functions that access the source know to prepare it.
- */
-void odb_source_packed_prepare(struct odb_source_packed *source);
-
 #endif
diff --git a/odb/source.h b/odb/source.h
index b9a7642b2c..bbf1da3819 100644
--- a/odb/source.h
+++ b/odb/source.h
@@ -83,11 +83,12 @@ struct odb_source {
 	void (*close)(struct odb_source *source);
 
 	/*
-	 * This callback is expected to clear underlying caches of the object
-	 * database source. The function is called when the repository has for
-	 * example just been repacked so that new objects will become visible.
+	 * This callback is expected to prepare the source so that it becomes
+	 * ready for use. It optionally clears underlying caches of the object
+	 * database source.
 	 */
-	void (*reprepare)(struct odb_source *source);
+	void (*prepare)(struct odb_source *source,
+			enum odb_prepare_flags flags);
 
 	/*
 	 * 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)
 }
 
 /*
- * Reprepare the object database source and clear any caches. Depending on the
+ * Prepare the object database source and clear any caches. Depending on the
  * backend used this may have the effect that concurrently-written objects
  * become visible.
  */
-static inline void odb_source_reprepare(struct odb_source *source)
+static inline void odb_source_prepare(struct odb_source *source,
+				      enum odb_prepare_flags flags)
 {
-	source->reprepare(source);
+	source->prepare(source, flags);
 }
 
 /*
diff --git a/packfile.c b/packfile.c
index 59cee7925d..d78fae981a 100644
--- a/packfile.c
+++ b/packfile.c
@@ -855,7 +855,7 @@ void for_each_file_in_pack_dir(const char *objdir,
 
 struct packfile_list_entry *packfile_store_get_packs(struct odb_source_packed *store)
 {
-	odb_source_packed_prepare(store);
+	odb_source_prepare(&store->base, 0);
 
 	if (store->midx) {
 		struct multi_pack_index *m = store->midx;

-- 
2.55.0.rc1.745.g43192e7977.dirty


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] odb: introduce `odb_prepare()`
  2026-06-22  8:47 [PATCH 0/2] odb: generalize `reprepare()` callback Patrick Steinhardt
  2026-06-22  8:47 ` [PATCH 1/2] odb/source: " Patrick Steinhardt
@ 2026-06-22  8:47 ` Patrick Steinhardt
  2026-06-26 12:09   ` Toon Claes
  1 sibling, 1 reply; 5+ messages in thread
From: Patrick Steinhardt @ 2026-06-22  8:47 UTC (permalink / raw)
  To: git

Introduce `odb_prepare()` as a simple wrapper to prepare alternates and
then prepare each individual source. Adapt git-grep(1) to use it.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/grep.c |  9 ++-------
 odb.c          | 18 ++++++++++++------
 odb.h          |  8 ++++++--
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 7361bf071e..a7252d56a1 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1356,13 +1356,8 @@ int cmd_grep(int argc,
 		if (recurse_submodules)
 			repo_read_gitmodules(the_repository, 1);
 
-		if (startup_info->have_repository) {
-			struct odb_source *source;
-
-			odb_prepare_alternates(the_repository->objects);
-			for (source = the_repository->objects->sources; source; source = source->next)
-				odb_source_prepare(source, 0);
-		}
+		if (startup_info->have_repository)
+			odb_prepare(the_repository->objects, 0);
 
 		start_threads(&opt);
 	} else {
diff --git a/odb.c b/odb.c
index 7b45390e12..11414c49a8 100644
--- a/odb.c
+++ b/odb.c
@@ -1070,7 +1070,7 @@ void odb_free(struct object_database *o)
 	free(o);
 }
 
-void odb_reprepare(struct object_database *o)
+void odb_prepare(struct object_database *o, enum odb_prepare_flags flags)
 {
 	struct odb_source *source;
 
@@ -1082,13 +1082,19 @@ void odb_reprepare(struct object_database *o)
 	 * the linked list, so existing odbs will continue to exist for
 	 * the lifetime of the process.
 	 */
-	o->loaded_alternates = 0;
-	odb_prepare_alternates(o);
+	if (flags & ODB_PREPARE_FLUSH_CACHES) {
+		o->loaded_alternates = 0;
+		o->object_count_valid = 0;
+	}
 
+	odb_prepare_alternates(o);
 	for (source = o->sources; source; source = source->next)
-		odb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);
-
-	o->object_count_valid = 0;
+		odb_source_prepare(source, flags);
 
 	obj_read_unlock();
 }
+
+void odb_reprepare(struct object_database *o)
+{
+	odb_prepare(o, ODB_PREPARE_FLUSH_CACHES);
+}
diff --git a/odb.h b/odb.h
index c14c9030e4..b1c0f3767b 100644
--- a/odb.h
+++ b/odb.h
@@ -133,9 +133,13 @@ enum odb_prepare_flags {
 };
 
 /*
- * Clear caches, reload alternates and then reload object sources so that new
- * objects may become accessible.
+ * Prepare the object database for use. Calling this function is generally not
+ * needed, but can be useful in case the caller wants to pre-open individual
+ * sources.
  */
+void odb_prepare(struct object_database *o, enum odb_prepare_flags flags);
+
+/* Equivalent to `odb_prepare(o, ODB_PREPARE_FLUSH_CACHES)`. */
 void odb_reprepare(struct object_database *o);
 
 /*

-- 
2.55.0.rc1.745.g43192e7977.dirty


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] odb: introduce `odb_prepare()`
  2026-06-22  8:47 ` [PATCH 2/2] odb: introduce `odb_prepare()` Patrick Steinhardt
@ 2026-06-26 12:09   ` Toon Claes
  0 siblings, 0 replies; 5+ messages in thread
From: Toon Claes @ 2026-06-26 12:09 UTC (permalink / raw)
  To: Patrick Steinhardt, git

Patrick Steinhardt <ps@pks.im> writes:

> Introduce `odb_prepare()` as a simple wrapper to prepare alternates and
> then prepare each individual source. Adapt git-grep(1) to use it.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  builtin/grep.c |  9 ++-------
>  odb.c          | 18 ++++++++++++------
>  odb.h          |  8 ++++++--
>  3 files changed, 20 insertions(+), 15 deletions(-)
>
> diff --git a/builtin/grep.c b/builtin/grep.c
> index 7361bf071e..a7252d56a1 100644
> --- a/builtin/grep.c
> +++ b/builtin/grep.c
> @@ -1356,13 +1356,8 @@ int cmd_grep(int argc,
>  		if (recurse_submodules)
>  			repo_read_gitmodules(the_repository, 1);
>  
> -		if (startup_info->have_repository) {
> -			struct odb_source *source;
> -
> -			odb_prepare_alternates(the_repository->objects);
> -			for (source = the_repository->objects->sources; source; source = source->next)
> -				odb_source_prepare(source, 0);
> -		}
> +		if (startup_info->have_repository)
> +			odb_prepare(the_repository->objects, 0);
>  
>  		start_threads(&opt);
>  	} else {
> diff --git a/odb.c b/odb.c
> index 7b45390e12..11414c49a8 100644
> --- a/odb.c
> +++ b/odb.c
> @@ -1070,7 +1070,7 @@ void odb_free(struct object_database *o)
>  	free(o);
>  }
>  
> -void odb_reprepare(struct object_database *o)
> +void odb_prepare(struct object_database *o, enum odb_prepare_flags flags)
>  {
>  	struct odb_source *source;
>  
> @@ -1082,13 +1082,19 @@ void odb_reprepare(struct object_database *o)
>  	 * the linked list, so existing odbs will continue to exist for
>  	 * the lifetime of the process.
>  	 */
> -	o->loaded_alternates = 0;
> -	odb_prepare_alternates(o);
> +	if (flags & ODB_PREPARE_FLUSH_CACHES) {
> +		o->loaded_alternates = 0;
> +		o->object_count_valid = 0;
> +	}
>  
> +	odb_prepare_alternates(o);
>  	for (source = o->sources; source; source = source->next)
> -		odb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);
> -
> -	o->object_count_valid = 0;
> +		odb_source_prepare(source, flags);
>  
>  	obj_read_unlock();
>  }
> +
> +void odb_reprepare(struct object_database *o)
> +{
> +	odb_prepare(o, ODB_PREPARE_FLUSH_CACHES);
> +}
> diff --git a/odb.h b/odb.h
> index c14c9030e4..b1c0f3767b 100644
> --- a/odb.h
> +++ b/odb.h
> @@ -133,9 +133,13 @@ enum odb_prepare_flags {
>  };
>  
>  /*
> - * Clear caches, reload alternates and then reload object sources so that new
> - * objects may become accessible.
> + * Prepare the object database for use. Calling this function is generally not
> + * needed, but can be useful in case the caller wants to pre-open individual
> + * sources.
>   */
> +void odb_prepare(struct object_database *o, enum odb_prepare_flags flags);
> +
> +/* Equivalent to `odb_prepare(o, ODB_PREPARE_FLUSH_CACHES)`. */
>  void odb_reprepare(struct object_database *o);

According to my grep results are there 17 callsites for odb_reprepare(),
then I agree it makes sense to create this wrapper.

-- 
Cheers,
Toon

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] odb/source: generalize `reprepare()` callback
  2026-06-22  8:47 ` [PATCH 1/2] odb/source: " Patrick Steinhardt
@ 2026-06-26 12:10   ` Toon Claes
  0 siblings, 0 replies; 5+ messages in thread
From: Toon Claes @ 2026-06-26 12:10 UTC (permalink / raw)
  To: Patrick Steinhardt, git

Patrick Steinhardt <ps@pks.im> writes:

> 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>
> ---
>  builtin/grep.c        |  9 +++------
>  midx.c                |  2 +-
>  odb.c                 |  2 +-
>  odb.h                 |  8 ++++++++
>  odb/source-files.c    |  9 +++++----
>  odb/source-inmemory.c |  5 +++--
>  odb/source-loose.c    |  8 +++++---
>  odb/source-packed.c   | 34 ++++++++++++++++------------------
>  odb/source-packed.h   |  9 ---------
>  odb/source.h          | 16 +++++++++-------
>  packfile.c            |  2 +-
>  11 files changed, 52 insertions(+), 52 deletions(-)
>
> diff --git a/builtin/grep.c b/builtin/grep.c
> index 8080d1bf5e..7361bf071e 100644
> --- a/builtin/grep.c
> +++ b/builtin/grep.c
> @@ -25,12 +25,11 @@
>  #include "setup.h"
>  #include "submodule.h"
>  #include "submodule-config.h"
> -#include "object-file.h"
>  #include "object-name.h"
>  #include "odb.h"
> +#include "odb/source.h"
>  #include "oid-array.h"
>  #include "oidset.h"
> -#include "packfile.h"
>  #include "pager.h"
>  #include "path.h"
>  #include "promisor-remote.h"
> @@ -1361,10 +1360,8 @@ int cmd_grep(int argc,
>  			struct odb_source *source;
>  
>  			odb_prepare_alternates(the_repository->objects);
> -			for (source = the_repository->objects->sources; source; source = source->next) {
> -				struct odb_source_files *files = odb_source_files_downcast(source);

So you're downcasting inside the implementation by the backends itself.
That makes sense, but would it be worth to say something about that in
the commit message?

> -				odb_source_packed_prepare(files->packed);
> -			}
> +			for (source = the_repository->objects->sources; source; source = source->next)
> +				odb_source_prepare(source, 0);
>  		}
>  
>  		start_threads(&opt);
> diff --git a/midx.c b/midx.c
> index cc6b94f9dd..76c3f92cc3 100644
> --- a/midx.c
> +++ b/midx.c
> @@ -101,7 +101,7 @@ static int midx_read_object_offsets(const unsigned char *chunk_start,
>  
>  struct multi_pack_index *get_multi_pack_index(struct odb_source_packed *source)
>  {
> -	odb_source_packed_prepare(source);
> +	odb_source_prepare(&source->base, 0);
>  	return source->midx;
>  }
>  
> diff --git a/odb.c b/odb.c
> index 965ef68e4e..7b45390e12 100644
> --- a/odb.c
> +++ b/odb.c
> @@ -1086,7 +1086,7 @@ void odb_reprepare(struct object_database *o)
>  	odb_prepare_alternates(o);
>  
>  	for (source = o->sources; source; source = source->next)
> -		odb_source_reprepare(source);
> +		odb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);
>  
>  	o->object_count_valid = 0;
>  
> diff --git a/odb.h b/odb.h
> index 0030467a52..c14c9030e4 100644
> --- a/odb.h
> +++ b/odb.h
> @@ -124,6 +124,14 @@ void odb_free(struct object_database *o);
>   */
>  void odb_close(struct object_database *o);
>  
> +enum odb_prepare_flags {
> +	/*
> +	 * Flush caches, reload alternates and then re-prepare each object
> +	 * source so that new objects may become accessible.
> +	 */
> +	ODB_PREPARE_FLUSH_CACHES = (1 << 0),
> +};
> +
>  /*
>   * Clear caches, reload alternates and then reload object sources so that new
>   * objects may become accessible.
> diff --git a/odb/source-files.c b/odb/source-files.c
> index 3bc6419dd7..ad9e0b52f9 100644
> --- a/odb/source-files.c
> +++ b/odb/source-files.c
> @@ -41,11 +41,12 @@ static void odb_source_files_close(struct odb_source *source)
>  	odb_source_close(&files->packed->base);
>  }
>  
> -static void odb_source_files_reprepare(struct odb_source *source)
> +static void odb_source_files_prepare(struct odb_source *source,
> +				     enum odb_prepare_flags flags)
>  {
>  	struct odb_source_files *files = odb_source_files_downcast(source);
> -	odb_source_reprepare(&files->loose->base);
> -	odb_source_reprepare(&files->packed->base);
> +	odb_source_prepare(&files->loose->base, flags);
> +	odb_source_prepare(&files->packed->base, flags);
>  }
>  
>  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,
>  
>  	files->base.free = odb_source_files_free;
>  	files->base.close = odb_source_files_close;
> -	files->base.reprepare = odb_source_files_reprepare;
> +	files->base.prepare = odb_source_files_prepare;
>  	files->base.read_object_info = odb_source_files_read_object_info;
>  	files->base.read_object_stream = odb_source_files_read_object_stream;
>  	files->base.for_each_object = odb_source_files_for_each_object;
> diff --git a/odb/source-inmemory.c b/odb/source-inmemory.c
> index e004566d76..cc5e9e62cb 100644
> --- a/odb/source-inmemory.c
> +++ b/odb/source-inmemory.c
> @@ -325,7 +325,8 @@ static void odb_source_inmemory_close(struct odb_source *source UNUSED)
>  {
>  }
>  
> -static void odb_source_inmemory_reprepare(struct odb_source *source UNUSED)
> +static void odb_source_inmemory_prepare(struct odb_source *source UNUSED,
> +					enum odb_prepare_flags flags UNUSED)
>  {
>  }
>  
> @@ -365,7 +366,7 @@ struct odb_source_inmemory *odb_source_inmemory_new(struct object_database *odb)
>  
>  	source->base.free = odb_source_inmemory_free;
>  	source->base.close = odb_source_inmemory_close;
> -	source->base.reprepare = odb_source_inmemory_reprepare;
> +	source->base.prepare = odb_source_inmemory_prepare;
>  	source->base.read_object_info = odb_source_inmemory_read_object_info;
>  	source->base.read_object_stream = odb_source_inmemory_read_object_stream;
>  	source->base.for_each_object = odb_source_inmemory_for_each_object;
> diff --git a/odb/source-loose.c b/odb/source-loose.c
> index 7d7ea2fb84..af46316e35 100644
> --- a/odb/source-loose.c
> +++ b/odb/source-loose.c
> @@ -672,10 +672,12 @@ static void odb_source_loose_clear_cache(struct odb_source_loose *loose)
>  	       sizeof(loose->subdir_seen));
>  }
>  
> -static void odb_source_loose_reprepare(struct odb_source *source)
> +static void odb_source_loose_prepare(struct odb_source *source,
> +				     enum odb_prepare_flags flags)
>  {
>  	struct odb_source_loose *loose = odb_source_loose_downcast(source);
> -	odb_source_loose_clear_cache(loose);
> +	if (flags & ODB_PREPARE_FLUSH_CACHES)
> +		odb_source_loose_clear_cache(loose);
>  }
>  
>  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,
>  
>  	loose->base.free = odb_source_loose_free;
>  	loose->base.close = odb_source_loose_close;
> -	loose->base.reprepare = odb_source_loose_reprepare;
> +	loose->base.prepare = odb_source_loose_prepare;
>  	loose->base.read_object_info = odb_source_loose_read_object_info;
>  	loose->base.read_object_stream = odb_source_loose_read_object_stream;
>  	loose->base.for_each_object = odb_source_loose_for_each_object;
> diff --git a/odb/source-packed.c b/odb/source-packed.c
> index 42c28fba0e..fa5a072488 100644
> --- a/odb/source-packed.c
> +++ b/odb/source-packed.c
> @@ -15,7 +15,7 @@ static int find_pack_entry(struct odb_source_packed *store,
>  {
>  	struct packfile_list_entry *l;
>  
> -	odb_source_packed_prepare(store);
> +	odb_source_prepare(&store->base, 0);

Why are you not using ODB_PREPARE_FLUSH_CACHES here? It used to do
before?

>  	if (store->midx && fill_midx_entry(store->midx, oid, e))
>  		return 1;
>  
> @@ -47,7 +47,7 @@ static int odb_source_packed_read_object_info(struct odb_source *source,
>  	 * been added since the last time we have prepared the packfile store.
>  	 */
>  	if (flags & OBJECT_INFO_SECOND_READ)
> -		odb_source_reprepare(source);
> +		odb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);

I think the new code is correct, but why wasn't `packed` used here in
the past? The old odb_source_reprepare() expected a downcasted, didn't
it?

>  
>  	if (!find_pack_entry(packed, oid, &e))
>  		return 1;
> @@ -668,27 +668,25 @@ static int sort_pack(const struct packfile_list_entry *a,
>  	return -1;
>  }
>  
> -void odb_source_packed_prepare(struct odb_source_packed *source)
> +static void odb_source_packed_prepare(struct odb_source *source,
> +				      enum odb_prepare_flags flags)
>  {
> -	if (source->initialized)
> +	struct odb_source_packed *packed = odb_source_packed_downcast(source);
> +
> +	if (flags & ODB_PREPARE_FLUSH_CACHES)
> +		packed->initialized = false;
> +	if (packed->initialized)
>  		return;
>  
> -	prepare_multi_pack_index_one(source);
> -	prepare_packed_git_one(source);
> +	prepare_multi_pack_index_one(packed);
> +	prepare_packed_git_one(packed);
>  
> -	sort_packs(&source->packs.head, sort_pack);
> -	for (struct packfile_list_entry *e = source->packs.head; e; e = e->next)
> +	sort_packs(&packed->packs.head, sort_pack);
> +	for (struct packfile_list_entry *e = packed->packs.head; e; e = e->next)
>  		if (!e->next)
> -			source->packs.tail = e;
> +			packed->packs.tail = e;
>  
> -	source->initialized = true;
> -}
> -
> -static void odb_source_packed_reprepare(struct odb_source *source)
> -{
> -	struct odb_source_packed *packed = odb_source_packed_downcast(source);
> -	packed->initialized = false;
> -	odb_source_packed_prepare(packed);
> +	packed->initialized = true;
>  }
>  
>  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,
>  
>  	packed->base.free = odb_source_packed_free;
>  	packed->base.close = odb_source_packed_close;
> -	packed->base.reprepare = odb_source_packed_reprepare;
> +	packed->base.prepare = odb_source_packed_prepare;
>  	packed->base.read_object_info = odb_source_packed_read_object_info;
>  	packed->base.read_object_stream = odb_source_packed_read_object_stream;
>  	packed->base.for_each_object = odb_source_packed_for_each_object;
> diff --git a/odb/source-packed.h b/odb/source-packed.h
> index 88994098c1..d5230ac68c 100644
> --- a/odb/source-packed.h
> +++ b/odb/source-packed.h
> @@ -82,13 +82,4 @@ static inline struct odb_source_packed *odb_source_packed_downcast(struct odb_so
>  	return container_of(source, struct odb_source_packed, base);
>  }
>  
> -/*
> - * Prepare the source by loading packfiles and multi-pack indices for
> - * all alternates. This becomes a no-op if the source is already prepared.
> - *
> - * It shouldn't typically be necessary to call this function directly, as
> - * functions that access the source know to prepare it.
> - */
> -void odb_source_packed_prepare(struct odb_source_packed *source);
> -
>  #endif
> diff --git a/odb/source.h b/odb/source.h
> index b9a7642b2c..bbf1da3819 100644
> --- a/odb/source.h
> +++ b/odb/source.h
> @@ -83,11 +83,12 @@ struct odb_source {
>  	void (*close)(struct odb_source *source);
>  
>  	/*
> -	 * This callback is expected to clear underlying caches of the object
> -	 * database source. The function is called when the repository has for
> -	 * example just been repacked so that new objects will become visible.
> +	 * This callback is expected to prepare the source so that it becomes
> +	 * ready for use. It optionally clears underlying caches of the object
> +	 * database source.
>  	 */
> -	void (*reprepare)(struct odb_source *source);
> +	void (*prepare)(struct odb_source *source,
> +			enum odb_prepare_flags flags);
>  
>  	/*
>  	 * 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)
>  }
>  
>  /*
> - * Reprepare the object database source and clear any caches. Depending on the
> + * Prepare the object database source and clear any caches. Depending on the
>   * backend used this may have the effect that concurrently-written objects
>   * become visible.
>   */
> -static inline void odb_source_reprepare(struct odb_source *source)
> +static inline void odb_source_prepare(struct odb_source *source,
> +				      enum odb_prepare_flags flags)
>  {
> -	source->reprepare(source);
> +	source->prepare(source, flags);
>  }
>  
>  /*
> diff --git a/packfile.c b/packfile.c
> index 59cee7925d..d78fae981a 100644
> --- a/packfile.c
> +++ b/packfile.c
> @@ -855,7 +855,7 @@ void for_each_file_in_pack_dir(const char *objdir,
>  
>  struct packfile_list_entry *packfile_store_get_packs(struct odb_source_packed *store)
>  {
> -	odb_source_packed_prepare(store);
> +	odb_source_prepare(&store->base, 0);
>  
>  	if (store->midx) {
>  		struct multi_pack_index *m = store->midx;
>
> -- 
> 2.55.0.rc1.745.g43192e7977.dirty
>
>

-- 
Cheers,
Toon

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-06-26 12:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-22  8:47 [PATCH 0/2] odb: generalize `reprepare()` callback Patrick Steinhardt
2026-06-22  8:47 ` [PATCH 1/2] odb/source: " Patrick Steinhardt
2026-06-26 12:10   ` Toon Claes
2026-06-22  8:47 ` [PATCH 2/2] odb: introduce `odb_prepare()` Patrick Steinhardt
2026-06-26 12:09   ` Toon Claes

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox