midx: introduce `bsearch_one_midx()`

The `bsearch_midx()` function will be extended in a following commit to search for the location of a given object ID across all MIDXs in a chain (or the single non-chain MIDX if no chain is available). While most callers will naturally want to use the updated `bsearch_midx()` function, there are a handful of special cases that will want finer control and will only want to search through a single MIDX. For instance, the object abbreviation code, which cares about object IDs near to where we'd expect to find a match in a MIDX. In that case, we want to look at the nearby matches in each layer of the MIDX chain, not just a single one). Split the more fine-grained control out into a separate function called `bsearch_one_midx()` which searches only a single MIDX. At present both `bsearch_midx()` and `bsearch_one_midx()` have identical behavior, but the following commit will rewrite the former to be aware of incremental MIDXs for the remaining non-special case callers. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Taylor Blau committed Aug 6, 2024 at 11:37 UTC 3f5f1cff92dfe64bbbfa9f2fb4ed810125810b1b
3 files changed +71 -50
midx.c
+14 -3
@@ -330,10 +330,21 @@ int nth_bitmapped_pack(struct repository *r, struct multi_pack_index *m,
330 return 0;
331 }
332
333 -int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m, uint32_t *result)
333 +int bsearch_one_midx(const struct object_id *oid, struct multi_pack_index *m,
334 + uint32_t *result)
335 {
335 - return bsearch_hash(oid->hash, m->chunk_oid_fanout, m->chunk_oid_lookup,
336 - the_hash_algo->rawsz, result);
336 + int ret = bsearch_hash(oid->hash, m->chunk_oid_fanout,
337 + m->chunk_oid_lookup, the_hash_algo->rawsz,
338 + result);
339 + if (result)
340 + *result += m->num_objects_in_base;
341 + return ret;
342 +}
343 +
344 +int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m,
345 + uint32_t *result)
346 +{
347 + return bsearch_one_midx(oid, m, result);
348 }
349
350 struct object_id *nth_midxed_object_oid(struct object_id *oid,
midx.h
+4 -1
@@ -90,7 +90,10 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
90 int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t pack_int_id);
91 int nth_bitmapped_pack(struct repository *r, struct multi_pack_index *m,
92 struct bitmapped_pack *bp, uint32_t pack_int_id);
93 -int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m, uint32_t *result);
93 +int bsearch_one_midx(const struct object_id *oid, struct multi_pack_index *m,
94 + uint32_t *result);
95 +int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m,
96 + uint32_t *result);
97 off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos);
98 uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos);
99 struct object_id *nth_midxed_object_oid(struct object_id *oid,
object-name.c
+53 -46
@@ -134,28 +134,32 @@ static int match_hash(unsigned len, const unsigned char *a, const unsigned char
134 static void unique_in_midx(struct multi_pack_index *m,
135 struct disambiguate_state *ds)
136 {
137 - uint32_t num, i, first = 0;
138 - const struct object_id *current = NULL;
139 - int len = ds->len > ds->repo->hash_algo->hexsz ?
140 - ds->repo->hash_algo->hexsz : ds->len;
141 - num = m->num_objects;
137 + for (; m; m = m->base_midx) {
138 + uint32_t num, i, first = 0;
139 + const struct object_id *current = NULL;
140 + int len = ds->len > ds->repo->hash_algo->hexsz ?
141 + ds->repo->hash_algo->hexsz : ds->len;
142
143 - if (!num)
144 - return;
143 + if (!m->num_objects)
144 + continue;
145
146 - bsearch_midx(&ds->bin_pfx, m, &first);
146 + num = m->num_objects + m->num_objects_in_base;
147
148 - /*
149 - * At this point, "first" is the location of the lowest object
150 - * with an object name that could match "bin_pfx". See if we have
151 - * 0, 1 or more objects that actually match(es).
152 - */
153 - for (i = first; i < num && !ds->ambiguous; i++) {
154 - struct object_id oid;
155 - current = nth_midxed_object_oid(&oid, m, i);
156 - if (!match_hash(len, ds->bin_pfx.hash, current->hash))
157 - break;
158 - update_candidates(ds, current);
148 + bsearch_one_midx(&ds->bin_pfx, m, &first);
149 +
150 + /*
151 + * At this point, "first" is the location of the lowest
152 + * object with an object name that could match
153 + * "bin_pfx". See if we have 0, 1 or more objects that
154 + * actually match(es).
155 + */
156 + for (i = first; i < num && !ds->ambiguous; i++) {
157 + struct object_id oid;
158 + current = nth_midxed_object_oid(&oid, m, i);
159 + if (!match_hash(len, ds->bin_pfx.hash, current->hash))
160 + break;
161 + update_candidates(ds, current);
162 + }
163 }
164 }
165
@@ -708,37 +712,40 @@ static int repo_extend_abbrev_len(struct repository *r UNUSED,
712 static void find_abbrev_len_for_midx(struct multi_pack_index *m,
713 struct min_abbrev_data *mad)
714 {
711 - int match = 0;
712 - uint32_t num, first = 0;
713 - struct object_id oid;
714 - const struct object_id *mad_oid;
715 + for (; m; m = m->base_midx) {
716 + int match = 0;
717 + uint32_t num, first = 0;
718 + struct object_id oid;
719 + const struct object_id *mad_oid;
720
716 - if (!m->num_objects)
717 - return;
721 + if (!m->num_objects)
722 + continue;
723
719 - num = m->num_objects;
720 - mad_oid = mad->oid;
721 - match = bsearch_midx(mad_oid, m, &first);
724 + num = m->num_objects + m->num_objects_in_base;
725 + mad_oid = mad->oid;
726 + match = bsearch_one_midx(mad_oid, m, &first);
727
723 - /*
724 - * first is now the position in the packfile where we would insert
725 - * mad->hash if it does not exist (or the position of mad->hash if
726 - * it does exist). Hence, we consider a maximum of two objects
727 - * nearby for the abbreviation length.
728 - */
729 - mad->init_len = 0;
730 - if (!match) {
731 - if (nth_midxed_object_oid(&oid, m, first))
732 - extend_abbrev_len(&oid, mad);
733 - } else if (first < num - 1) {
734 - if (nth_midxed_object_oid(&oid, m, first + 1))
735 - extend_abbrev_len(&oid, mad);
736 - }
737 - if (first > 0) {
738 - if (nth_midxed_object_oid(&oid, m, first - 1))
739 - extend_abbrev_len(&oid, mad);
728 + /*
729 + * first is now the position in the packfile where we
730 + * would insert mad->hash if it does not exist (or the
731 + * position of mad->hash if it does exist). Hence, we
732 + * consider a maximum of two objects nearby for the
733 + * abbreviation length.
734 + */
735 + mad->init_len = 0;
736 + if (!match) {
737 + if (nth_midxed_object_oid(&oid, m, first))
738 + extend_abbrev_len(&oid, mad);
739 + } else if (first < num - 1) {
740 + if (nth_midxed_object_oid(&oid, m, first + 1))
741 + extend_abbrev_len(&oid, mad);
742 + }
743 + if (first > 0) {
744 + if (nth_midxed_object_oid(&oid, m, first - 1))
745 + extend_abbrev_len(&oid, mad);
746 + }
747 + mad->init_len = mad->cur_len;
748 }
741 - mad->init_len = mad->cur_len;
749 }
750
751 static void find_abbrev_len_for_pack(struct packed_git *p,