object-name: move logic to iterate through packed prefixed objects

Similar to the preceding commit, move the logic to iterate through objects that have a given prefix into "packfile.c". 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 e30bff8f8402f0f147a08fe00b75e24f293fa870
2 files changed +181 -87
object-name.c
+7 -87
@@ -100,8 +100,6 @@ static void update_candidates(struct disambiguate_state *ds, const struct object
100 /* otherwise, current can be discarded and candidate is still good */
101 }
102
103 -static int match_hash(unsigned, const unsigned char *, const unsigned char *);
104 -
103 static int match_prefix(const struct object_id *oid, struct object_info *oi UNUSED, void *arg)
104 {
105 struct disambiguate_state *ds = arg;
@@ -122,103 +120,25 @@ static void find_short_object_filename(struct disambiguate_state *ds)
120 odb_source_loose_for_each_object(source, NULL, match_prefix, ds, &opts);
121 }
122
125 -static int match_hash(unsigned len, const unsigned char *a, const unsigned char *b)
126 -{
127 - do {
128 - if (*a != *b)
129 - return 0;
130 - a++;
131 - b++;
132 - len -= 2;
133 - } while (len > 1);
134 - if (len)
135 - if ((*a ^ *b) & 0xf0)
136 - return 0;
137 - return 1;
138 -}
139 -
140 -static void unique_in_midx(struct multi_pack_index *m,
141 - struct disambiguate_state *ds)
142 -{
143 - for (; m; m = m->base_midx) {
144 - uint32_t num, i, first = 0;
145 - const struct object_id *current = NULL;
146 - int len = ds->len > ds->repo->hash_algo->hexsz ?
147 - ds->repo->hash_algo->hexsz : ds->len;
148 -
149 - if (!m->num_objects)
150 - continue;
151 -
152 - num = m->num_objects + m->num_objects_in_base;
153 -
154 - bsearch_one_midx(&ds->bin_pfx, m, &first);
155 -
156 - /*
157 - * At this point, "first" is the location of the lowest
158 - * object with an object name that could match
159 - * "bin_pfx". See if we have 0, 1 or more objects that
160 - * actually match(es).
161 - */
162 - for (i = first; i < num && !ds->ambiguous; i++) {
163 - struct object_id oid;
164 - current = nth_midxed_object_oid(&oid, m, i);
165 - if (!match_hash(len, ds->bin_pfx.hash, current->hash))
166 - break;
167 - update_candidates(ds, current);
168 - }
169 - }
170 -}
171 -
172 -static void unique_in_pack(struct packed_git *p,
173 - struct disambiguate_state *ds)
174 -{
175 - uint32_t num, i, first = 0;
176 - int len = ds->len > ds->repo->hash_algo->hexsz ?
177 - ds->repo->hash_algo->hexsz : ds->len;
178 -
179 - if (p->multi_pack_index)
180 - return;
181 -
182 - if (open_pack_index(p) || !p->num_objects)
183 - return;
184 -
185 - num = p->num_objects;
186 - bsearch_pack(&ds->bin_pfx, p, &first);
187 -
188 - /*
189 - * At this point, "first" is the location of the lowest object
190 - * with an object name that could match "bin_pfx". See if we have
191 - * 0, 1 or more objects that actually match(es).
192 - */
193 - for (i = first; i < num && !ds->ambiguous; i++) {
194 - struct object_id oid;
195 - nth_packed_object_id(&oid, p, i);
196 - if (!match_hash(len, ds->bin_pfx.hash, oid.hash))
197 - break;
198 - update_candidates(ds, &oid);
199 - }
200 -}
201 -
123 static void find_short_packed_object(struct disambiguate_state *ds)
124 {
125 + struct odb_for_each_object_options opts = {
126 + .prefix = &ds->bin_pfx,
127 + .prefix_hex_len = ds->len,
128 + };
129 struct odb_source *source;
205 - struct packed_git *p;
130
131 /* Skip, unless oids from the storage hash algorithm are wanted */
132 if (ds->bin_pfx.algo && (&hash_algos[ds->bin_pfx.algo] != ds->repo->hash_algo))
133 return;
134
135 odb_prepare_alternates(ds->repo->objects);
212 - for (source = ds->repo->objects->sources; source && !ds->ambiguous; source = source->next) {
213 - struct multi_pack_index *m = get_multi_pack_index(source);
214 - if (m)
215 - unique_in_midx(m, ds);
216 - }
136 + for (source = ds->repo->objects->sources; source; source = source->next) {
137 + struct odb_source_files *files = odb_source_files_downcast(source);
138
218 - repo_for_each_pack(ds->repo, p) {
139 + packfile_store_for_each_object(files->packed, NULL, match_prefix, ds, &opts);
140 if (ds->ambiguous)
141 break;
221 - unique_in_pack(p, ds);
142 }
143 }
144
packfile.c
+174
@@ -2371,6 +2371,177 @@ static int packfile_store_for_each_object_wrapper(const struct object_id *oid,
2371 }
2372 }
2373
2374 +static int match_hash(unsigned len, const unsigned char *a, const unsigned char *b)
2375 +{
2376 + do {
2377 + if (*a != *b)
2378 + return 0;
2379 + a++;
2380 + b++;
2381 + len -= 2;
2382 + } while (len > 1);
2383 + if (len)
2384 + if ((*a ^ *b) & 0xf0)
2385 + return 0;
2386 + return 1;
2387 +}
2388 +
2389 +static int for_each_prefixed_object_in_midx(
2390 + struct packfile_store *store,
2391 + struct multi_pack_index *m,
2392 + const struct odb_for_each_object_options *opts,
2393 + struct packfile_store_for_each_object_wrapper_data *data)
2394 +{
2395 + int ret;
2396 +
2397 + for (; m; m = m->base_midx) {
2398 + uint32_t num, i, first = 0;
2399 + int len = opts->prefix_hex_len > m->source->odb->repo->hash_algo->hexsz ?
2400 + m->source->odb->repo->hash_algo->hexsz : opts->prefix_hex_len;
2401 +
2402 + if (!m->num_objects)
2403 + continue;
2404 +
2405 + num = m->num_objects + m->num_objects_in_base;
2406 +
2407 + bsearch_one_midx(opts->prefix, m, &first);
2408 +
2409 + /*
2410 + * At this point, "first" is the location of the lowest
2411 + * object with an object name that could match "opts->prefix".
2412 + * See if we have 0, 1 or more objects that actually match(es).
2413 + */
2414 + for (i = first; i < num; i++) {
2415 + const struct object_id *current = NULL;
2416 + struct object_id oid;
2417 +
2418 + current = nth_midxed_object_oid(&oid, m, i);
2419 +
2420 + if (!match_hash(len, opts->prefix->hash, current->hash))
2421 + break;
2422 +
2423 + if (data->request) {
2424 + struct object_info oi = *data->request;
2425 +
2426 + ret = packfile_store_read_object_info(store, current,
2427 + &oi, 0);
2428 + if (ret)
2429 + goto out;
2430 +
2431 + ret = data->cb(&oid, &oi, data->cb_data);
2432 + if (ret)
2433 + goto out;
2434 + } else {
2435 + ret = data->cb(&oid, NULL, data->cb_data);
2436 + if (ret)
2437 + goto out;
2438 + }
2439 + }
2440 + }
2441 +
2442 + ret = 0;
2443 +
2444 +out:
2445 + return ret;
2446 +}
2447 +
2448 +static int for_each_prefixed_object_in_pack(
2449 + struct packfile_store *store,
2450 + struct packed_git *p,
2451 + const struct odb_for_each_object_options *opts,
2452 + struct packfile_store_for_each_object_wrapper_data *data)
2453 +{
2454 + uint32_t num, i, first = 0;
2455 + int len = opts->prefix_hex_len > p->repo->hash_algo->hexsz ?
2456 + p->repo->hash_algo->hexsz : opts->prefix_hex_len;
2457 + int ret;
2458 +
2459 + num = p->num_objects;
2460 + bsearch_pack(opts->prefix, p, &first);
2461 +
2462 + /*
2463 + * At this point, "first" is the location of the lowest object
2464 + * with an object name that could match "bin_pfx". See if we have
2465 + * 0, 1 or more objects that actually match(es).
2466 + */
2467 + for (i = first; i < num; i++) {
2468 + struct object_id oid;
2469 +
2470 + nth_packed_object_id(&oid, p, i);
2471 + if (!match_hash(len, opts->prefix->hash, oid.hash))
2472 + break;
2473 +
2474 + if (data->request) {
2475 + struct object_info oi = *data->request;
2476 +
2477 + ret = packfile_store_read_object_info(store, &oid, &oi, 0);
2478 + if (ret)
2479 + goto out;
2480 +
2481 + ret = data->cb(&oid, &oi, data->cb_data);
2482 + if (ret)
2483 + goto out;
2484 + } else {
2485 + ret = data->cb(&oid, NULL, data->cb_data);
2486 + if (ret)
2487 + goto out;
2488 + }
2489 + }
2490 +
2491 + ret = 0;
2492 +
2493 +out:
2494 + return ret;
2495 +}
2496 +
2497 +static int packfile_store_for_each_prefixed_object(
2498 + struct packfile_store *store,
2499 + const struct odb_for_each_object_options *opts,
2500 + struct packfile_store_for_each_object_wrapper_data *data)
2501 +{
2502 + struct packfile_list_entry *e;
2503 + struct multi_pack_index *m;
2504 + bool pack_errors = false;
2505 + int ret;
2506 +
2507 + if (opts->flags)
2508 + BUG("flags unsupported");
2509 +
2510 + store->skip_mru_updates = true;
2511 +
2512 + m = get_multi_pack_index(store->source);
2513 + if (m) {
2514 + ret = for_each_prefixed_object_in_midx(store, m, opts, data);
2515 + if (ret)
2516 + goto out;
2517 + }
2518 +
2519 + for (e = packfile_store_get_packs(store); e; e = e->next) {
2520 + if (e->pack->multi_pack_index)
2521 + continue;
2522 +
2523 + if (open_pack_index(e->pack)) {
2524 + pack_errors = true;
2525 + continue;
2526 + }
2527 +
2528 + if (!e->pack->num_objects)
2529 + continue;
2530 +
2531 + ret = for_each_prefixed_object_in_pack(store, e->pack, opts, data);
2532 + if (ret)
2533 + goto out;
2534 + }
2535 +
2536 + ret = 0;
2537 +
2538 +out:
2539 + store->skip_mru_updates = false;
2540 + if (!ret && pack_errors)
2541 + ret = -1;
2542 + return ret;
2543 +}
2544 +
2545 int packfile_store_for_each_object(struct packfile_store *store,
2546 const struct object_info *request,
2547 odb_for_each_object_cb cb,
@@ -2386,6 +2557,9 @@ int packfile_store_for_each_object(struct packfile_store *store,
2557 struct packfile_list_entry *e;
2558 int pack_errors = 0, ret;
2559
2560 + if (opts->prefix)
2561 + return packfile_store_for_each_prefixed_object(store, opts, &data);
2562 +
2563 store->skip_mru_updates = true;
2564
2565 for (e = packfile_store_get_packs(store); e; e = e->next) {