object-file: introduce function to iterate through objects

We have multiple divergent interfaces to iterate through objects of a
specific backend:

  - `for_each_loose_object()` yields all loose objects.

  - `for_each_packed_object()` (somewhat obviously) yields all packed
    objects.

These functions have different function signatures, which makes it hard
to create a common abstraction layer that covers both of these.

Introduce a new function `odb_source_loose_for_each_object()` to plug
this gap. This function doesn't take any data specific to loose objects,
but instead it accepts a `struct object_info` that will be populated the
exact same as if `odb_source_loose_read_object()` was called.

The benefit of this new interface is that we can continue to pass
backend-specific data, as `struct object_info` contains a union for
these exact use cases. This will allow us to unify how we iterate
through objects across both loose and packed objects in a subsequent
commit.

The `for_each_loose_object()` function continues to exist for now, but
it will be removed at the end of this patch series.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt 2026-01-20 16:26:00 +01:00 committed by Junio C Hamano
parent 2fa45b49fe
commit cd73ca57e4
3 changed files with 64 additions and 0 deletions

View File

@ -1801,6 +1801,47 @@ int for_each_loose_object(struct object_database *odb,
return 0;
}
struct for_each_object_wrapper_data {
struct odb_source *source;
struct object_info *oi;
odb_for_each_object_cb cb;
void *cb_data;
};
static int for_each_object_wrapper_cb(const struct object_id *oid,
const char *path,
void *cb_data)
{
struct for_each_object_wrapper_data *data = cb_data;
if (data->oi &&
read_object_info_from_path(data->source, path, oid, data->oi, 0) < 0)
return -1;
return data->cb(oid, data->oi, data->cb_data);
}
int odb_source_loose_for_each_object(struct odb_source *source,
struct object_info *oi,
odb_for_each_object_cb cb,
void *cb_data,
unsigned flags)
{
struct for_each_object_wrapper_data data = {
.source = source,
.oi = oi,
.cb = cb,
.cb_data = cb_data,
};
/* There are no loose promisor objects, so we can return immediately. */
if ((flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY))
return 0;
if ((flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !source->local)
return 0;
return for_each_loose_file_in_source(source, for_each_object_wrapper_cb,
NULL, NULL, &data);
}
static int append_loose_object(const struct object_id *oid,
const char *path UNUSED,
void *data)

View File

@ -137,6 +137,17 @@ int for_each_loose_object(struct object_database *odb,
each_loose_object_fn, void *,
enum odb_for_each_object_flags flags);
/*
* Iterate through all loose objects in the given object database source and
* invoke the callback function for each of them. If given, the object info
* will be populated with the object's data as if you had called
* `odb_source_loose_read_object_info()` on the object.
*/
int odb_source_loose_for_each_object(struct odb_source *source,
struct object_info *oi,
odb_for_each_object_cb cb,
void *cb_data,
unsigned flags);
/**
* format_object_header() is a thin wrapper around s xsnprintf() that

12
odb.h
View File

@ -463,6 +463,18 @@ 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);
enum {
/*
* By default, `odb_write_object()` does not actually write anything