odb/source-packed: wire up for_each_object() callback

Move `packfile_store_for_each_object()` and its associated helpers from
"packfile.c" into "odb/source-packed.c" and wire it up as the
`for_each_object()` callback of the "packed" source.

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-06-09 10:51:04 +02:00
committed by Junio C Hamano
parent 8813b9486d
commit f298de400e
7 changed files with 269 additions and 280 deletions

View File

@@ -916,8 +916,8 @@ static void batch_each_object(struct batch_options *opt,
for (source = the_repository->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
int ret = packfile_store_for_each_object(files->packed, &oi,
batch_one_object_oi, &payload, &opts);
int ret = odb_source_for_each_object(&files->packed->base, &oi,
batch_one_object_oi, &payload, &opts);
if (ret)
break;
}

View File

@@ -4503,8 +4503,8 @@ static void add_objects_in_unpacked_packs(void)
if (!source->local)
continue;
if (packfile_store_for_each_object(files->packed, &oi,
add_object_in_unpacked_pack, NULL, &opts))
if (odb_source_for_each_object(&files->packed->base, &oi,
add_object_in_unpacked_pack, NULL, &opts))
die(_("cannot open pack index"));
}
}

View File

@@ -2016,8 +2016,8 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
odb_prepare_alternates(ctx->r->objects);
for (source = ctx->r->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
packfile_store_for_each_object(files->packed, &oi, add_packed_commits_oi,
ctx, &opts);
odb_source_for_each_object(&files->packed->base, &oi, add_packed_commits_oi,
ctx, &opts);
}
if (ctx->progress_done < ctx->approx_nr_objects)

View File

@@ -88,7 +88,7 @@ static int odb_source_files_for_each_object(struct odb_source *source,
return ret;
}
ret = packfile_store_for_each_object(files->packed, request, cb, cb_data, opts);
ret = odb_source_for_each_object(&files->packed->base, request, cb, cb_data, opts);
if (ret)
return ret;

View File

@@ -81,6 +81,263 @@ static int odb_source_packed_read_object_stream(struct odb_read_stream **out,
return packfile_read_object_stream(out, oid, e.p, e.offset);
}
struct odb_source_packed_for_each_object_wrapper_data {
struct odb_source_packed *store;
const struct object_info *request;
odb_for_each_object_cb cb;
void *cb_data;
};
static int odb_source_packed_for_each_object_wrapper(const struct object_id *oid,
struct packed_git *pack,
uint32_t index_pos,
void *cb_data)
{
struct odb_source_packed_for_each_object_wrapper_data *data = cb_data;
if (data->request) {
off_t offset = nth_packed_object_offset(pack, index_pos);
struct object_info oi = *data->request;
if (packed_object_info_with_index_pos(pack, offset,
&index_pos, &oi) < 0) {
mark_bad_packed_object(pack, oid);
return -1;
}
return data->cb(oid, &oi, data->cb_data);
} else {
return data->cb(oid, NULL, data->cb_data);
}
}
static int match_hash(unsigned len, const unsigned char *a, const unsigned char *b)
{
do {
if (*a != *b)
return 0;
a++;
b++;
len -= 2;
} while (len > 1);
if (len)
if ((*a ^ *b) & 0xf0)
return 0;
return 1;
}
static int for_each_prefixed_object_in_midx(
struct odb_source_packed *store,
struct multi_pack_index *m,
const struct odb_for_each_object_options *opts,
struct odb_source_packed_for_each_object_wrapper_data *data)
{
int ret;
for (; m; m = m->base_midx) {
uint32_t num, i, first = 0;
int len = opts->prefix_hex_len > m->source->odb->repo->hash_algo->hexsz ?
m->source->odb->repo->hash_algo->hexsz : opts->prefix_hex_len;
if (!m->num_objects)
continue;
num = m->num_objects + m->num_objects_in_base;
bsearch_one_midx(opts->prefix, m, &first);
/*
* At this point, "first" is the location of the lowest
* object with an object name that could match "opts->prefix".
* See if we have 0, 1 or more objects that actually match(es).
*/
for (i = first; i < num; i++) {
const struct object_id *current = NULL;
struct object_id oid;
current = nth_midxed_object_oid(&oid, m, i);
if (!match_hash(len, opts->prefix->hash, current->hash))
break;
if (data->request) {
struct object_info oi = *data->request;
ret = odb_source_read_object_info(&store->base, current,
&oi, 0);
if (ret)
goto out;
ret = data->cb(&oid, &oi, data->cb_data);
if (ret)
goto out;
} else {
ret = data->cb(&oid, NULL, data->cb_data);
if (ret)
goto out;
}
}
}
ret = 0;
out:
return ret;
}
static int for_each_prefixed_object_in_pack(
struct odb_source_packed *store,
struct packed_git *p,
const struct odb_for_each_object_options *opts,
struct odb_source_packed_for_each_object_wrapper_data *data)
{
uint32_t num, i, first = 0;
int len = opts->prefix_hex_len > p->repo->hash_algo->hexsz ?
p->repo->hash_algo->hexsz : opts->prefix_hex_len;
int ret;
num = p->num_objects;
bsearch_pack(opts->prefix, p, &first);
/*
* At this point, "first" is the location of the lowest object
* with an object name that could match "bin_pfx". See if we have
* 0, 1 or more objects that actually match(es).
*/
for (i = first; i < num; i++) {
struct object_id oid;
nth_packed_object_id(&oid, p, i);
if (!match_hash(len, opts->prefix->hash, oid.hash))
break;
if (data->request) {
struct object_info oi = *data->request;
ret = odb_source_read_object_info(&store->base, &oid, &oi, 0);
if (ret)
goto out;
ret = data->cb(&oid, &oi, data->cb_data);
if (ret)
goto out;
} else {
ret = data->cb(&oid, NULL, data->cb_data);
if (ret)
goto out;
}
}
ret = 0;
out:
return ret;
}
static int odb_source_packed_for_each_prefixed_object(
struct odb_source_packed *store,
const struct odb_for_each_object_options *opts,
struct odb_source_packed_for_each_object_wrapper_data *data)
{
struct packfile_list_entry *e;
struct multi_pack_index *m;
bool pack_errors = false;
int ret;
if (opts->flags)
BUG("flags unsupported");
store->skip_mru_updates = true;
m = get_multi_pack_index(&store->files->base);
if (m) {
ret = for_each_prefixed_object_in_midx(store, m, opts, data);
if (ret)
goto out;
}
for (e = packfile_store_get_packs(store); e; e = e->next) {
if (e->pack->multi_pack_index)
continue;
if (open_pack_index(e->pack)) {
pack_errors = true;
continue;
}
if (!e->pack->num_objects)
continue;
ret = for_each_prefixed_object_in_pack(store, e->pack, opts, data);
if (ret)
goto out;
}
ret = 0;
out:
store->skip_mru_updates = false;
if (!ret && pack_errors)
ret = -1;
return ret;
}
static int odb_source_packed_for_each_object(struct odb_source *source,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
const struct odb_for_each_object_options *opts)
{
struct odb_source_packed *packed = odb_source_packed_downcast(source);
struct odb_source_packed_for_each_object_wrapper_data data = {
.store = packed,
.request = request,
.cb = cb,
.cb_data = cb_data,
};
struct packfile_list_entry *e;
int pack_errors = 0, ret;
if (opts->prefix)
return odb_source_packed_for_each_prefixed_object(packed, opts, &data);
packed->skip_mru_updates = true;
for (e = packfile_store_get_packs(packed); e; e = e->next) {
struct packed_git *p = e->pack;
if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
continue;
if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) &&
!p->pack_promisor)
continue;
if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS) &&
p->pack_keep_in_core)
continue;
if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS) &&
p->pack_keep)
continue;
if (open_pack_index(p)) {
pack_errors = 1;
continue;
}
ret = for_each_object_in_pack(p, odb_source_packed_for_each_object_wrapper,
&data, opts->flags);
if (ret)
goto out;
}
ret = 0;
out:
packed->skip_mru_updates = false;
if (!ret && pack_errors)
ret = -1;
return ret;
}
void (*report_garbage)(unsigned seen_bits, const char *path);
static void report_helper(const struct string_list *list,
@@ -291,6 +548,7 @@ struct odb_source_packed *odb_source_packed_new(struct odb_source_files *parent)
packed->base.reprepare = odb_source_packed_reprepare;
packed->base.read_object_info = odb_source_packed_read_object_info;
packed->base.read_object_stream = odb_source_packed_read_object_stream;
packed->base.for_each_object = odb_source_packed_for_each_object;
if (!is_absolute_path(parent->base.path))
chdir_notify_register(NULL, odb_source_packed_reparent, packed);

View File

@@ -1362,8 +1362,8 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
hashmap_add(&delta_base_cache, &ent->ent);
}
static int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_offset,
uint32_t *maybe_index_pos, struct object_info *oi)
int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_offset,
uint32_t *maybe_index_pos, struct object_info *oi)
{
struct pack_window *w_curs = NULL;
size_t size;
@@ -2068,262 +2068,6 @@ int for_each_object_in_pack(struct packed_git *p,
return r;
}
struct odb_source_packed_for_each_object_wrapper_data {
struct odb_source_packed *store;
const struct object_info *request;
odb_for_each_object_cb cb;
void *cb_data;
};
static int packfile_store_for_each_object_wrapper(const struct object_id *oid,
struct packed_git *pack,
uint32_t index_pos,
void *cb_data)
{
struct odb_source_packed_for_each_object_wrapper_data *data = cb_data;
if (data->request) {
off_t offset = nth_packed_object_offset(pack, index_pos);
struct object_info oi = *data->request;
if (packed_object_info_with_index_pos(pack, offset,
&index_pos, &oi) < 0) {
mark_bad_packed_object(pack, oid);
return -1;
}
return data->cb(oid, &oi, data->cb_data);
} else {
return data->cb(oid, NULL, data->cb_data);
}
}
static int match_hash(unsigned len, const unsigned char *a, const unsigned char *b)
{
do {
if (*a != *b)
return 0;
a++;
b++;
len -= 2;
} while (len > 1);
if (len)
if ((*a ^ *b) & 0xf0)
return 0;
return 1;
}
static int for_each_prefixed_object_in_midx(
struct odb_source_packed *store,
struct multi_pack_index *m,
const struct odb_for_each_object_options *opts,
struct odb_source_packed_for_each_object_wrapper_data *data)
{
int ret;
for (; m; m = m->base_midx) {
uint32_t num, i, first = 0;
int len = opts->prefix_hex_len > m->source->odb->repo->hash_algo->hexsz ?
m->source->odb->repo->hash_algo->hexsz : opts->prefix_hex_len;
if (!m->num_objects)
continue;
num = m->num_objects + m->num_objects_in_base;
bsearch_one_midx(opts->prefix, m, &first);
/*
* At this point, "first" is the location of the lowest
* object with an object name that could match "opts->prefix".
* See if we have 0, 1 or more objects that actually match(es).
*/
for (i = first; i < num; i++) {
const struct object_id *current = NULL;
struct object_id oid;
current = nth_midxed_object_oid(&oid, m, i);
if (!match_hash(len, opts->prefix->hash, current->hash))
break;
if (data->request) {
struct object_info oi = *data->request;
ret = odb_source_read_object_info(&store->base, current,
&oi, 0);
if (ret)
goto out;
ret = data->cb(&oid, &oi, data->cb_data);
if (ret)
goto out;
} else {
ret = data->cb(&oid, NULL, data->cb_data);
if (ret)
goto out;
}
}
}
ret = 0;
out:
return ret;
}
static int for_each_prefixed_object_in_pack(
struct odb_source_packed *store,
struct packed_git *p,
const struct odb_for_each_object_options *opts,
struct odb_source_packed_for_each_object_wrapper_data *data)
{
uint32_t num, i, first = 0;
int len = opts->prefix_hex_len > p->repo->hash_algo->hexsz ?
p->repo->hash_algo->hexsz : opts->prefix_hex_len;
int ret;
num = p->num_objects;
bsearch_pack(opts->prefix, p, &first);
/*
* At this point, "first" is the location of the lowest object
* with an object name that could match "bin_pfx". See if we have
* 0, 1 or more objects that actually match(es).
*/
for (i = first; i < num; i++) {
struct object_id oid;
nth_packed_object_id(&oid, p, i);
if (!match_hash(len, opts->prefix->hash, oid.hash))
break;
if (data->request) {
struct object_info oi = *data->request;
ret = odb_source_read_object_info(&store->base, &oid, &oi, 0);
if (ret)
goto out;
ret = data->cb(&oid, &oi, data->cb_data);
if (ret)
goto out;
} else {
ret = data->cb(&oid, NULL, data->cb_data);
if (ret)
goto out;
}
}
ret = 0;
out:
return ret;
}
static int packfile_store_for_each_prefixed_object(
struct odb_source_packed *store,
const struct odb_for_each_object_options *opts,
struct odb_source_packed_for_each_object_wrapper_data *data)
{
struct packfile_list_entry *e;
struct multi_pack_index *m;
bool pack_errors = false;
int ret;
if (opts->flags)
BUG("flags unsupported");
store->skip_mru_updates = true;
m = get_multi_pack_index(&store->files->base);
if (m) {
ret = for_each_prefixed_object_in_midx(store, m, opts, data);
if (ret)
goto out;
}
for (e = packfile_store_get_packs(store); e; e = e->next) {
if (e->pack->multi_pack_index)
continue;
if (open_pack_index(e->pack)) {
pack_errors = true;
continue;
}
if (!e->pack->num_objects)
continue;
ret = for_each_prefixed_object_in_pack(store, e->pack, opts, data);
if (ret)
goto out;
}
ret = 0;
out:
store->skip_mru_updates = false;
if (!ret && pack_errors)
ret = -1;
return ret;
}
int packfile_store_for_each_object(struct odb_source_packed *store,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
const struct odb_for_each_object_options *opts)
{
struct odb_source_packed_for_each_object_wrapper_data data = {
.store = store,
.request = request,
.cb = cb,
.cb_data = cb_data,
};
struct packfile_list_entry *e;
int pack_errors = 0, ret;
if (opts->prefix)
return packfile_store_for_each_prefixed_object(store, opts, &data);
store->skip_mru_updates = true;
for (e = packfile_store_get_packs(store); e; e = e->next) {
struct packed_git *p = e->pack;
if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
continue;
if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) &&
!p->pack_promisor)
continue;
if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS) &&
p->pack_keep_in_core)
continue;
if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS) &&
p->pack_keep)
continue;
if (open_pack_index(p)) {
pack_errors = 1;
continue;
}
ret = for_each_object_in_pack(p, packfile_store_for_each_object_wrapper,
&data, opts->flags);
if (ret)
goto out;
}
ret = 0;
out:
store->skip_mru_updates = false;
if (!ret && pack_errors)
ret = -1;
return ret;
}
static int extend_abbrev_len(const struct object_id *a,
const struct object_id *b,
unsigned *out)

View File

@@ -227,21 +227,6 @@ int for_each_object_in_pack(struct packed_git *p,
each_packed_object_fn, void *data,
enum odb_for_each_object_flags flags);
/*
* Iterate through all packed objects in the given packfile store and invoke
* the callback function for each of them. If an object info request is given,
* then the object info will be read for every individual object and passed to
* the callback as if `packfile_store_read_object_info()` was called for the
* object.
*
* The flags parameter is a combination of `odb_for_each_object_flags`.
*/
int packfile_store_for_each_object(struct odb_source_packed *store,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
const struct odb_for_each_object_options *opts);
int packfile_store_find_abbrev_len(struct odb_source_packed *store,
const struct object_id *oid,
unsigned min_len,
@@ -354,6 +339,8 @@ extern int do_check_packed_object_crc;
*/
int packed_object_info(struct packed_git *pack,
off_t offset, struct object_info *);
int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_offset,
uint32_t *maybe_index_pos, struct object_info *oi);
void mark_bad_packed_object(struct packed_git *, const struct object_id *);
const struct packed_git *has_packed_and_bad(struct repository *, const struct object_id *);