Thread (73 messages) 73 messages, 3 authors, 2026-03-05
STALE106d

[PATCH 11/17] odb/source: make `for_each_object()` function pluggable

From: Patrick Steinhardt <hidden>
Date: 2026-02-23 16:18:39
Subsystem: the rest · Maintainer: Linus Torvalds

Introduce a new callback function in `struct odb_source` to make the
function pluggable.

Signed-off-by: Patrick Steinhardt <redacted>
---
 odb.c              | 12 +----------
 odb.h              | 12 -----------
 odb/source-files.c | 23 +++++++++++++++++++++
 odb/source.h       | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 83 insertions(+), 23 deletions(-)
diff --git a/odb.c b/odb.c
index c0b8cd062b..494a3273cf 100644
--- a/odb.c
+++ b/odb.c
@@ -984,20 +984,10 @@ int odb_for_each_object(struct object_database *odb,
 
 	odb_prepare_alternates(odb);
 	for (struct odb_source *source = odb->sources; source; source = source->next) {
-		struct odb_source_files *files = odb_source_files_downcast(source);
-
 		if (flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY && !source->local)
 			continue;
 
-		if (!(flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY)) {
-			ret = odb_source_loose_for_each_object(source, request,
-							       cb, cb_data, flags);
-			if (ret)
-				return ret;
-		}
-
-		ret = packfile_store_for_each_object(files->packed, request,
-						     cb, cb_data, flags);
+		ret = odb_source_for_each_object(source, request, cb, cb_data, flags);
 		if (ret)
 			return ret;
 	}
diff --git a/odb.h b/odb.h
index 70ffb033f9..692d9029ef 100644
--- a/odb.h
+++ b/odb.h
@@ -432,18 +432,6 @@ enum odb_for_each_object_flags {
 	ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS = (1<<4),
 };
 
-/*
- * A callback function that can be used to iterate through objects. If given,
- * the optional `oi` parameter will be populated the same as if you would call
- * `odb_read_object_info()`.
- *
- * Returning a non-zero error code will cause iteration to abort. The error
- * code will be propagated.
- */
-typedef int (*odb_for_each_object_cb)(const struct object_id *oid,
-				      struct object_info *oi,
-				      void *cb_data);
-
 /*
  * Iterate through all objects contained in the object database. Note that
  * objects may be iterated over multiple times in case they are either stored
diff --git a/odb/source-files.c b/odb/source-files.c
index b50a1f5492..d8ef1d8237 100644
--- a/odb/source-files.c
+++ b/odb/source-files.c
@@ -66,6 +66,28 @@ static int odb_source_files_read_object_stream(struct odb_read_stream **out,
 	return -1;
 }
 
+static int odb_source_files_for_each_object(struct odb_source *source,
+					    const struct object_info *request,
+					    odb_for_each_object_cb cb,
+					    void *cb_data,
+					    unsigned flags)
+{
+	struct odb_source_files *files = odb_source_files_downcast(source);
+	int ret;
+
+	if (!(flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY)) {
+		ret = odb_source_loose_for_each_object(source, request, cb, cb_data, flags);
+		if (ret)
+			return ret;
+	}
+
+	ret = packfile_store_for_each_object(files->packed, request, cb, cb_data, flags);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 struct odb_source_files *odb_source_files_new(struct object_database *odb,
 					      const char *path,
 					      bool local)
@@ -82,6 +104,7 @@ struct odb_source_files *odb_source_files_new(struct object_database *odb,
 	files->base.reprepare = odb_source_files_reprepare;
 	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;
 
 	/*
 	 * Ideally, we would only ever store absolute paths in the source. This
diff --git a/odb/source.h b/odb/source.h
index edb425fdef..35aa78e140 100644
--- a/odb/source.h
+++ b/odb/source.h
@@ -53,6 +53,18 @@ struct object_id;
 struct object_info;
 struct odb_read_stream;
 
+/*
+ * A callback function that can be used to iterate through objects. If given,
+ * the optional `oi` parameter will be populated the same as if you would call
+ * `odb_read_object_info()`.
+ *
+ * Returning a non-zero error code will cause iteration to abort. The error
+ * code will be propagated.
+ */
+typedef int (*odb_for_each_object_cb)(const struct object_id *oid,
+				      struct object_info *oi,
+				      void *cb_data);
+
 /*
  * The source is the part of the object database that stores the actual
  * objects. It thus encapsulates the logic to read and write the specific
@@ -151,6 +163,27 @@ struct odb_source {
 	int (*read_object_stream)(struct odb_read_stream **out,
 				  struct odb_source *source,
 				  const struct object_id *oid);
+
+	/*
+	 * This callback is expected to iterate over all objects stored in this
+	 * source and invoke the callback function for each of them. It is
+	 * valid to yield the same object multiple time. A non-zero exit code
+	 * from the object callback shall abort iteration.
+	 *
+	 * The optional `oi` structure shall be populated similar to how an individual
+	 * call to `odb_source_read_object_info()` would have behaved. If the caller
+	 * passes a `NULL` pointer then the object itself shall not be read.
+	 *
+	 * The callback is expected to return a negative error code in case the
+	 * iteration has failed to read all objects, 0 otherwise. When the
+	 * callback function returns a non-zero error code then that error code
+	 * should be returned.
+	 */
+	int (*for_each_object)(struct odb_source *source,
+			       const struct object_info *request,
+			       odb_for_each_object_cb cb,
+			       void *cb_data,
+			       unsigned flags);
 };
 
 /*
@@ -233,4 +266,30 @@ static inline int odb_source_read_object_stream(struct odb_read_stream **out,
 	return source->read_object_stream(out, source, oid);
 }
 
+/*
+ * Iterate through all objects contained in the given source and invoke the
+ * callback function for each of them. Returning a non-zero code from the
+ * callback function aborts iteration. There is no guarantee that objects
+ * are only iterated over once.
+ *
+ * The optional `oi` structure shall be populated similar to how an individual
+ * call to `odb_source_read_object_info()` would have behaved. If the caller
+ * passes a `NULL` pointer then the object itself shall not be read.
+ *
+ * The flags is a bitfield of `ODB_FOR_EACH_OBJECT_*` flags. Not all flags may
+ * apply to a specific backend, so whether or not they are honored is defined
+ * by the implementation.
+ *
+ * Returns 0 when all objects have been iterated over, a negative error code in
+ * case iteration has failed, or a non-zero value returned from the callback.
+ */
+static inline int odb_source_for_each_object(struct odb_source *source,
+					     const struct object_info *request,
+					     odb_for_each_object_cb cb,
+					     void *cb_data,
+					     unsigned flags)
+{
+	return source->for_each_object(source, request, cb, cb_data, flags);
+}
+
 #endif
-- 
2.53.0.536.g309c995771.dirty
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help