odb: introduce `struct odb_for_each_object_options`

The `odb_for_each_object()` function only accepts a bitset of flags. In a subsequent commit we'll want to change object iteration to also support iterating over only those objects that have a specific prefix. While we could of course add the prefix to the function signature, or alternatively introduce a new function, both of these options don't really seem to be that sensible. Instead, introduce a new `struct odb_for_each_object_options` that can be passed to a new `odb_for_each_object_ext()` function. Splice through the options structure into the respective object database sources. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Mar 20, 2026 at 08:07 UTC cfd575f0a9730712107e4ee6799a37665bcd8204
11 files changed +71 -34
builtin/cat-file.c
+5 -2
@@ -848,6 +848,9 @@ static void batch_each_object(struct batch_options *opt,
848 .callback = callback,
849 .payload = _payload,
850 };
851 + struct odb_for_each_object_options opts = {
852 + .flags = flags,
853 + };
854 struct bitmap_index *bitmap = NULL;
855 struct odb_source *source;
856
@@ -860,7 +863,7 @@ static void batch_each_object(struct batch_options *opt,
863 odb_prepare_alternates(the_repository->objects);
864 for (source = the_repository->objects->sources; source; source = source->next) {
865 int ret = odb_source_loose_for_each_object(source, NULL, batch_one_object_oi,
863 - &payload, flags);
866 + &payload, &opts);
867 if (ret)
868 break;
869 }
@@ -884,7 +887,7 @@ static void batch_each_object(struct batch_options *opt,
887 for (source = the_repository->objects->sources; source; source = source->next) {
888 struct odb_source_files *files = odb_source_files_downcast(source);
889 int ret = packfile_store_for_each_object(files->packed, &oi,
887 - batch_one_object_oi, &payload, flags);
890 + batch_one_object_oi, &payload, &opts);
891 if (ret)
892 break;
893 }
builtin/pack-objects.c
+7 -5
@@ -4344,6 +4344,12 @@ static void add_objects_in_unpacked_packs(void)
4344 {
4345 struct odb_source *source;
4346 time_t mtime;
4347 + struct odb_for_each_object_options opts = {
4348 + .flags = ODB_FOR_EACH_OBJECT_PACK_ORDER |
4349 + ODB_FOR_EACH_OBJECT_LOCAL_ONLY |
4350 + ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS |
4351 + ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS,
4352 + };
4353 struct object_info oi = {
4354 .mtimep = &mtime,
4355 };
@@ -4356,11 +4362,7 @@ static void add_objects_in_unpacked_packs(void)
4362 continue;
4363
4364 if (packfile_store_for_each_object(files->packed, &oi,
4359 - add_object_in_unpacked_pack, NULL,
4360 - ODB_FOR_EACH_OBJECT_PACK_ORDER |
4361 - ODB_FOR_EACH_OBJECT_LOCAL_ONLY |
4362 - ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS |
4363 - ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS))
4365 + add_object_in_unpacked_pack, NULL, &opts))
4366 die(_("cannot open pack index"));
4367 }
4368 }
commit-graph.c
+4 -1
@@ -1969,6 +1969,9 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
1969 {
1970 struct odb_source *source;
1971 enum object_type type;
1972 + struct odb_for_each_object_options opts = {
1973 + .flags = ODB_FOR_EACH_OBJECT_PACK_ORDER,
1974 + };
1975 struct object_info oi = {
1976 .typep = &type,
1977 };
@@ -1983,7 +1986,7 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
1986 for (source = ctx->r->objects->sources; source; source = source->next) {
1987 struct odb_source_files *files = odb_source_files_downcast(source);
1988 packfile_store_for_each_object(files->packed, &oi, add_packed_commits_oi,
1986 - ctx, ODB_FOR_EACH_OBJECT_PACK_ORDER);
1989 + ctx, &opts);
1990 }
1991
1992 if (ctx->progress_done < ctx->approx_nr_objects)
object-file.c
+5 -4
@@ -1849,7 +1849,7 @@ int odb_source_loose_for_each_object(struct odb_source *source,
1849 const struct object_info *request,
1850 odb_for_each_object_cb cb,
1851 void *cb_data,
1852 - unsigned flags)
1852 + const struct odb_for_each_object_options *opts)
1853 {
1854 struct for_each_object_wrapper_data data = {
1855 .source = source,
@@ -1859,9 +1859,9 @@ int odb_source_loose_for_each_object(struct odb_source *source,
1859 };
1860
1861 /* There are no loose promisor objects, so we can return immediately. */
1862 - if ((flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY))
1862 + if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY))
1863 return 0;
1864 - if ((flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !source->local)
1864 + if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !source->local)
1865 return 0;
1866
1867 return for_each_loose_file_in_source(source, for_each_object_wrapper_cb,
@@ -1914,9 +1914,10 @@ int odb_source_loose_count_objects(struct odb_source *source,
1914 *out = count * 256;
1915 ret = 0;
1916 } else {
1917 + struct odb_for_each_object_options opts = { 0 };
1918 *out = 0;
1919 ret = odb_source_loose_for_each_object(source, NULL, count_loose_object,
1919 - out, NULL);
1920 + out, &opts);
1921 }
1922
1923 out:
object-file.h
+1 -1
@@ -137,7 +137,7 @@ int odb_source_loose_for_each_object(struct odb_source *source,
137 const struct object_info *request,
138 odb_for_each_object_cb cb,
139 void *cb_data,
140 - unsigned flags);
140 + const struct odb_for_each_object_options *opts);
141
142 /*
143 * Count the number of loose objects in this source.
odb.c
+19 -7
@@ -896,20 +896,20 @@ int odb_freshen_object(struct object_database *odb,
896 return 0;
897 }
898
899 -int odb_for_each_object(struct object_database *odb,
900 - const struct object_info *request,
901 - odb_for_each_object_cb cb,
902 - void *cb_data,
903 - unsigned flags)
899 +int odb_for_each_object_ext(struct object_database *odb,
900 + const struct object_info *request,
901 + odb_for_each_object_cb cb,
902 + void *cb_data,
903 + const struct odb_for_each_object_options *opts)
904 {
905 int ret;
906
907 odb_prepare_alternates(odb);
908 for (struct odb_source *source = odb->sources; source; source = source->next) {
909 - if (flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY && !source->local)
909 + if (opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY && !source->local)
910 continue;
911
912 - ret = odb_source_for_each_object(source, request, cb, cb_data, flags);
912 + ret = odb_source_for_each_object(source, request, cb, cb_data, opts);
913 if (ret)
914 return ret;
915 }
@@ -917,6 +917,18 @@ int odb_for_each_object(struct object_database *odb,
917 return 0;
918 }
919
920 +int odb_for_each_object(struct object_database *odb,
921 + const struct object_info *request,
922 + odb_for_each_object_cb cb,
923 + void *cb_data,
924 + unsigned flags)
925 +{
926 + struct odb_for_each_object_options opts = {
927 + .flags = flags,
928 + };
929 + return odb_for_each_object_ext(odb, request, cb, cb_data, &opts);
930 +}
931 +
932 int odb_count_objects(struct object_database *odb,
933 enum odb_count_objects_flags flags,
934 unsigned long *out)
odb.h
+16
@@ -481,6 +481,15 @@ typedef int (*odb_for_each_object_cb)(const struct object_id *oid,
481 struct object_info *oi,
482 void *cb_data);
483
484 +/*
485 + * Options that can be passed to `odb_for_each_object()` and its
486 + * backend-specific implementations.
487 + */
488 +struct odb_for_each_object_options {
489 + /* A bitfield of `odb_for_each_object_flags`. */
490 + enum odb_for_each_object_flags flags;
491 +};
492 +
493 /*
494 * Iterate through all objects contained in the object database. Note that
495 * objects may be iterated over multiple times in case they are either stored
@@ -495,6 +504,13 @@ typedef int (*odb_for_each_object_cb)(const struct object_id *oid,
504 * Returns 0 on success, a negative error code in case a failure occurred, or
505 * an arbitrary non-zero error code returned by the callback itself.
506 */
507 +int odb_for_each_object_ext(struct object_database *odb,
508 + const struct object_info *request,
509 + odb_for_each_object_cb cb,
510 + void *cb_data,
511 + const struct odb_for_each_object_options *opts);
512 +
513 +/* Same as `odb_for_each_object_ext()` with `opts.flags` set to the given flags. */
514 int odb_for_each_object(struct object_database *odb,
515 const struct object_info *request,
516 odb_for_each_object_cb cb,
odb/source-files.c
+4 -4
@@ -75,18 +75,18 @@ static int odb_source_files_for_each_object(struct odb_source *source,
75 const struct object_info *request,
76 odb_for_each_object_cb cb,
77 void *cb_data,
78 - unsigned flags)
78 + const struct odb_for_each_object_options *opts)
79 {
80 struct odb_source_files *files = odb_source_files_downcast(source);
81 int ret;
82
83 - if (!(flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY)) {
84 - ret = odb_source_loose_for_each_object(source, request, cb, cb_data, flags);
83 + if (!(opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY)) {
84 + ret = odb_source_loose_for_each_object(source, request, cb, cb_data, opts);
85 if (ret)
86 return ret;
87 }
88
89 - ret = packfile_store_for_each_object(files->packed, request, cb, cb_data, flags);
89 + ret = packfile_store_for_each_object(files->packed, request, cb, cb_data, opts);
90 if (ret)
91 return ret;
92
odb/source.h
+3 -3
@@ -140,7 +140,7 @@ struct odb_source {
140 const struct object_info *request,
141 odb_for_each_object_cb cb,
142 void *cb_data,
143 - unsigned flags);
143 + const struct odb_for_each_object_options *opts);
144
145 /*
146 * This callback is expected to count objects in the given object
@@ -343,9 +343,9 @@ static inline int odb_source_for_each_object(struct odb_source *source,
343 const struct object_info *request,
344 odb_for_each_object_cb cb,
345 void *cb_data,
346 - unsigned flags)
346 + const struct odb_for_each_object_options *opts)
347 {
348 - return source->for_each_object(source, request, cb, cb_data, flags);
348 + return source->for_each_object(source, request, cb, cb_data, opts);
349 }
350
351 /*
packfile.c
+6 -6
@@ -2375,7 +2375,7 @@ int packfile_store_for_each_object(struct packfile_store *store,
2375 const struct object_info *request,
2376 odb_for_each_object_cb cb,
2377 void *cb_data,
2378 - unsigned flags)
2378 + const struct odb_for_each_object_options *opts)
2379 {
2380 struct packfile_store_for_each_object_wrapper_data data = {
2381 .store = store,
@@ -2391,15 +2391,15 @@ int packfile_store_for_each_object(struct packfile_store *store,
2391 for (e = packfile_store_get_packs(store); e; e = e->next) {
2392 struct packed_git *p = e->pack;
2393
2394 - if ((flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
2394 + if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
2395 continue;
2396 - if ((flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) &&
2396 + if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) &&
2397 !p->pack_promisor)
2398 continue;
2399 - if ((flags & ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS) &&
2399 + if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS) &&
2400 p->pack_keep_in_core)
2401 continue;
2402 - if ((flags & ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS) &&
2402 + if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS) &&
2403 p->pack_keep)
2404 continue;
2405 if (open_pack_index(p)) {
@@ -2408,7 +2408,7 @@ int packfile_store_for_each_object(struct packfile_store *store,
2408 }
2409
2410 ret = for_each_object_in_pack(p, packfile_store_for_each_object_wrapper,
2411 - &data, flags);
2411 + &data, opts->flags);
2412 if (ret)
2413 goto out;
2414 }
packfile.h
+1 -1
@@ -367,7 +367,7 @@ int packfile_store_for_each_object(struct packfile_store *store,
367 const struct object_info *request,
368 odb_for_each_object_cb cb,
369 void *cb_data,
370 - unsigned flags);
370 + const struct odb_for_each_object_options *opts);
371
372 /* A hook to report invalid files in pack directory */
373 #define PACKDIR_FILE_PACK 1