From fdefdc2e6979e9e8cb28b34c458f42b44f217bf0 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 5 Mar 2026 15:19:51 +0100 Subject: [PATCH] odb/source: make `for_each_object()` function pluggable Introduce a new callback function in `struct odb_source` to make the function pluggable. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- odb.c | 12 +-------- odb.h | 12 --------- odb/source-files.c | 23 ++++++++++++++++ odb/source.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 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 4397cada27..be56995389 100644 --- a/odb/source.h +++ b/odb/source.h @@ -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