object-file: move logic to compute packed abbreviation length

Same as the preceding commit, move the logic that computes the minimum required prefix length to make a given object ID unique for the packfile store into a new function `packfile_store_find_abbrev_len()` that is part of "packfile.c". This prepares for making the logic fully generic via pluggable object databases. 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 6c2ede6e4abed754bb5891c2904212c05efcfb11
3 files changed +128 -123
object-name.c
+12 -123
@@ -582,115 +582,6 @@ static unsigned msb(unsigned long val)
582 return r;
583 }
584
585 -struct min_abbrev_data {
586 - unsigned int init_len;
587 - unsigned int cur_len;
588 - struct repository *repo;
589 - const struct object_id *oid;
590 -};
591 -
592 -static int extend_abbrev_len(const struct object_id *oid,
593 - struct min_abbrev_data *mad)
594 -{
595 - unsigned len = oid_common_prefix_hexlen(oid, mad->oid);
596 - if (len != hash_algos[oid->algo].hexsz && len >= mad->cur_len)
597 - mad->cur_len = len + 1;
598 - return 0;
599 -}
600 -
601 -static void find_abbrev_len_for_midx(struct multi_pack_index *m,
602 - struct min_abbrev_data *mad)
603 -{
604 - for (; m; m = m->base_midx) {
605 - int match = 0;
606 - uint32_t num, first = 0;
607 - struct object_id oid;
608 - const struct object_id *mad_oid;
609 -
610 - if (!m->num_objects)
611 - continue;
612 -
613 - num = m->num_objects + m->num_objects_in_base;
614 - mad_oid = mad->oid;
615 - match = bsearch_one_midx(mad_oid, m, &first);
616 -
617 - /*
618 - * first is now the position in the packfile where we
619 - * would insert mad->hash if it does not exist (or the
620 - * position of mad->hash if it does exist). Hence, we
621 - * consider a maximum of two objects nearby for the
622 - * abbreviation length.
623 - */
624 - mad->init_len = 0;
625 - if (!match) {
626 - if (nth_midxed_object_oid(&oid, m, first))
627 - extend_abbrev_len(&oid, mad);
628 - } else if (first < num - 1) {
629 - if (nth_midxed_object_oid(&oid, m, first + 1))
630 - extend_abbrev_len(&oid, mad);
631 - }
632 - if (first > 0) {
633 - if (nth_midxed_object_oid(&oid, m, first - 1))
634 - extend_abbrev_len(&oid, mad);
635 - }
636 - mad->init_len = mad->cur_len;
637 - }
638 -}
639 -
640 -static void find_abbrev_len_for_pack(struct packed_git *p,
641 - struct min_abbrev_data *mad)
642 -{
643 - int match = 0;
644 - uint32_t num, first = 0;
645 - struct object_id oid;
646 - const struct object_id *mad_oid;
647 -
648 - if (p->multi_pack_index)
649 - return;
650 -
651 - if (open_pack_index(p) || !p->num_objects)
652 - return;
653 -
654 - num = p->num_objects;
655 - mad_oid = mad->oid;
656 - match = bsearch_pack(mad_oid, p, &first);
657 -
658 - /*
659 - * first is now the position in the packfile where we would insert
660 - * mad->hash if it does not exist (or the position of mad->hash if
661 - * it does exist). Hence, we consider a maximum of two objects
662 - * nearby for the abbreviation length.
663 - */
664 - mad->init_len = 0;
665 - if (!match) {
666 - if (!nth_packed_object_id(&oid, p, first))
667 - extend_abbrev_len(&oid, mad);
668 - } else if (first < num - 1) {
669 - if (!nth_packed_object_id(&oid, p, first + 1))
670 - extend_abbrev_len(&oid, mad);
671 - }
672 - if (first > 0) {
673 - if (!nth_packed_object_id(&oid, p, first - 1))
674 - extend_abbrev_len(&oid, mad);
675 - }
676 - mad->init_len = mad->cur_len;
677 -}
678 -
679 -static void find_abbrev_len_packed(struct min_abbrev_data *mad)
680 -{
681 - struct packed_git *p;
682 -
683 - odb_prepare_alternates(mad->repo->objects);
684 - for (struct odb_source *source = mad->repo->objects->sources; source; source = source->next) {
685 - struct multi_pack_index *m = get_multi_pack_index(source);
686 - if (m)
687 - find_abbrev_len_for_midx(m, mad);
688 - }
689 -
690 - repo_for_each_pack(mad->repo, p)
691 - find_abbrev_len_for_pack(p, mad);
692 -}
693 -
585 void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
586 const struct object_id *oid, int abbrev_len)
587 {
@@ -707,14 +598,14 @@ void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
598 }
599
600 int repo_find_unique_abbrev_r(struct repository *r, char *hex,
710 - const struct object_id *oid, int len)
601 + const struct object_id *oid, int min_len)
602 {
603 const struct git_hash_algo *algo =
604 oid->algo ? &hash_algos[oid->algo] : r->hash_algo;
714 - struct min_abbrev_data mad;
605 const unsigned hexsz = algo->hexsz;
606 + unsigned len;
607
717 - if (len < 0) {
608 + if (min_len < 0) {
609 unsigned long count;
610
611 if (odb_count_objects(r->objects, ODB_COUNT_OBJECTS_APPROXIMATE, &count) < 0)
@@ -738,25 +629,23 @@ int repo_find_unique_abbrev_r(struct repository *r, char *hex,
629 */
630 if (len < FALLBACK_DEFAULT_ABBREV)
631 len = FALLBACK_DEFAULT_ABBREV;
632 + } else {
633 + len = min_len;
634 }
635
636 oid_to_hex_r(hex, oid);
637 if (len >= hexsz || !len)
638 return hexsz;
639
747 - mad.repo = r;
748 - mad.init_len = len;
749 - mad.cur_len = len;
750 - mad.oid = oid;
751 -
752 - find_abbrev_len_packed(&mad);
753 -
640 odb_prepare_alternates(r->objects);
755 - for (struct odb_source *s = r->objects->sources; s; s = s->next)
756 - odb_source_loose_find_abbrev_len(s, mad.oid, mad.cur_len, &mad.cur_len);
641 + for (struct odb_source *s = r->objects->sources; s; s = s->next) {
642 + struct odb_source_files *files = odb_source_files_downcast(s);
643 + packfile_store_find_abbrev_len(files->packed, oid, len, &len);
644 + odb_source_loose_find_abbrev_len(s, oid, len, &len);
645 + }
646
758 - hex[mad.cur_len] = 0;
759 - return mad.cur_len;
647 + hex[len] = 0;
648 + return len;
649 }
650
651 const char *repo_find_unique_abbrev(struct repository *r,
packfile.c
+111
@@ -2597,6 +2597,117 @@ out:
2597 return ret;
2598 }
2599
2600 +static int extend_abbrev_len(const struct object_id *a,
2601 + const struct object_id *b,
2602 + unsigned *out)
2603 +{
2604 + unsigned len = oid_common_prefix_hexlen(a, b);
2605 + if (len != hash_algos[a->algo].hexsz && len >= *out)
2606 + *out = len + 1;
2607 + return 0;
2608 +}
2609 +
2610 +static void find_abbrev_len_for_midx(struct multi_pack_index *m,
2611 + const struct object_id *oid,
2612 + unsigned min_len,
2613 + unsigned *out)
2614 +{
2615 + unsigned len = min_len;
2616 +
2617 + for (; m; m = m->base_midx) {
2618 + int match = 0;
2619 + uint32_t num, first = 0;
2620 + struct object_id found_oid;
2621 +
2622 + if (!m->num_objects)
2623 + continue;
2624 +
2625 + num = m->num_objects + m->num_objects_in_base;
2626 + match = bsearch_one_midx(oid, m, &first);
2627 +
2628 + /*
2629 + * first is now the position in the packfile where we
2630 + * would insert the object ID if it does not exist (or the
2631 + * position of the object ID if it does exist). Hence, we
2632 + * consider a maximum of two objects nearby for the
2633 + * abbreviation length.
2634 + */
2635 +
2636 + if (!match) {
2637 + if (nth_midxed_object_oid(&found_oid, m, first))
2638 + extend_abbrev_len(&found_oid, oid, &len);
2639 + } else if (first < num - 1) {
2640 + if (nth_midxed_object_oid(&found_oid, m, first + 1))
2641 + extend_abbrev_len(&found_oid, oid, &len);
2642 + }
2643 + if (first > 0) {
2644 + if (nth_midxed_object_oid(&found_oid, m, first - 1))
2645 + extend_abbrev_len(&found_oid, oid, &len);
2646 + }
2647 + }
2648 +
2649 + *out = len;
2650 +}
2651 +
2652 +static void find_abbrev_len_for_pack(struct packed_git *p,
2653 + const struct object_id *oid,
2654 + unsigned min_len,
2655 + unsigned *out)
2656 +{
2657 + int match;
2658 + uint32_t num, first = 0;
2659 + struct object_id found_oid;
2660 + unsigned len = min_len;
2661 +
2662 + num = p->num_objects;
2663 + match = bsearch_pack(oid, p, &first);
2664 +
2665 + /*
2666 + * first is now the position in the packfile where we would insert
2667 + * the object ID if it does not exist (or the position of mad->hash if
2668 + * it does exist). Hence, we consider a maximum of two objects
2669 + * nearby for the abbreviation length.
2670 + */
2671 + if (!match) {
2672 + if (!nth_packed_object_id(&found_oid, p, first))
2673 + extend_abbrev_len(&found_oid, oid, &len);
2674 + } else if (first < num - 1) {
2675 + if (!nth_packed_object_id(&found_oid, p, first + 1))
2676 + extend_abbrev_len(&found_oid, oid, &len);
2677 + }
2678 + if (first > 0) {
2679 + if (!nth_packed_object_id(&found_oid, p, first - 1))
2680 + extend_abbrev_len(&found_oid, oid, &len);
2681 + }
2682 +
2683 + *out = len;
2684 +}
2685 +
2686 +int packfile_store_find_abbrev_len(struct packfile_store *store,
2687 + const struct object_id *oid,
2688 + unsigned min_len,
2689 + unsigned *out)
2690 +{
2691 + struct packfile_list_entry *e;
2692 + struct multi_pack_index *m;
2693 +
2694 + m = get_multi_pack_index(store->source);
2695 + if (m)
2696 + find_abbrev_len_for_midx(m, oid, min_len, &min_len);
2697 +
2698 + for (e = packfile_store_get_packs(store); e; e = e->next) {
2699 + if (e->pack->multi_pack_index)
2700 + continue;
2701 + if (open_pack_index(e->pack) || !e->pack->num_objects)
2702 + continue;
2703 +
2704 + find_abbrev_len_for_pack(e->pack, oid, min_len, &min_len);
2705 + }
2706 +
2707 + *out = min_len;
2708 + return 0;
2709 +}
2710 +
2711 struct add_promisor_object_data {
2712 struct repository *repo;
2713 struct oidset *set;
packfile.h
+5
@@ -369,6 +369,11 @@ int packfile_store_for_each_object(struct packfile_store *store,
369 void *cb_data,
370 const struct odb_for_each_object_options *opts);
371
372 +int packfile_store_find_abbrev_len(struct packfile_store *store,
373 + const struct object_id *oid,
374 + unsigned min_len,
375 + unsigned *out);
376 +
377 /* A hook to report invalid files in pack directory */
378 #define PACKDIR_FILE_PACK 1
379 #define PACKDIR_FILE_IDX 2