]> git.ipfire.org Git - thirdparty/git.git/commitdiff
odb/source: make `for_each_object()` function pluggable
authorPatrick Steinhardt <ps@pks.im>
Thu, 5 Mar 2026 14:19:51 +0000 (15:19 +0100)
committerJunio C Hamano <gitster@pobox.com>
Thu, 5 Mar 2026 19:45:16 +0000 (11:45 -0800)
Introduce a new callback function in `struct odb_source` to make the
function pluggable.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
odb.c
odb.h
odb/source-files.c
odb/source.h

diff --git a/odb.c b/odb.c
index c0b8cd062bf3b38e27b71174a19171e93efb4ca6..494a3273cf77873eebb0348072f398cc3d6105fc 100644 (file)
--- 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 70ffb033f936158caa41fd095945df9261e8e963..692d9029efd36c2b918540f618ddb966ef110cf4 100644 (file)
--- 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
index b50a1f54926f1d82702a36462992232d5fb49e18..d8ef1d82378c83e19a991d84d9642792b832dfc9 100644 (file)
@@ -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
index 4397cada27861a4fadae1a7692022a2042f55883..be569953898e87033fb38c5bc913057a76a630a5 100644 (file)
@@ -52,6 +52,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
@@ -150,6 +162,30 @@ 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 `request` structure should serve as a template for
+        * looking up object info for every individual iterated object. It
+        * should not be modified directly and should instead be copied into a
+        * separate `struct object_info` that gets passed to the callback. 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);
 };
 
 /*
@@ -232,4 +268,33 @@ 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 `request` structure serves as a template for retrieving the
+ * object info for each indvidual iterated object and will be populated as if
+ * `odb_source_read_object_info()` was called on the object. It will not be
+ * modified, the callback will instead be invoked with a separate `struct
+ * object_info` for every object. Object info will not be read when passing a
+ * `NULL` pointer.
+ *
+ * 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