diff options
| author | Junio C Hamano <gitster@pobox.com> | 2025-04-23 13:58:50 -0700 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2025-04-23 13:58:50 -0700 |
| commit | bb74c0abbc31da35be52999569ea481ebd149d1d (patch) | |
| tree | e10db152ee6486a1b9af0f7990a140730ebe0ce2 | |
| parent | 68cd0cfa7ef753cc5549aa7882790565d51b9133 (diff) | |
| parent | a52d459e72b890c192485002ec518bb9e01c19a6 (diff) | |
| download | git-bb74c0abbc31da35be52999569ea481ebd149d1d.tar.gz | |
Merge branch 'kn/bundle-dedup-optim'
Optimize the code to dedup references recorded in a bundle file.
* kn/bundle-dedup-optim:
bundle: fix non-linear performance scaling with refs
t6020: test for duplicate refnames in bundle creation
| -rw-r--r-- | bundle.c | 8 | ||||
| -rw-r--r-- | object.c | 35 | ||||
| -rw-r--r-- | object.h | 6 | ||||
| -rwxr-xr-x | t/t6020-bundle-misc.sh | 53 |
4 files changed, 61 insertions, 41 deletions
@@ -384,6 +384,7 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs) { int i; int ref_count = 0; + struct strset objects = STRSET_INIT; for (i = 0; i < revs->pending.nr; i++) { struct object_array_entry *e = revs->pending.objects + i; @@ -401,6 +402,9 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs) flag = 0; display_ref = (flag & REF_ISSYMREF) ? e->name : ref; + if (strset_contains(&objects, display_ref)) + goto skip_write_ref; + if (e->item->type == OBJ_TAG && !is_tag_in_date_range(e->item, revs)) { e->item->flags |= UNINTERESTING; @@ -423,6 +427,7 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs) } ref_count++; + strset_add(&objects, display_ref); write_or_die(bundle_fd, oid_to_hex(&e->item->oid), the_hash_algo->hexsz); write_or_die(bundle_fd, " ", 1); write_or_die(bundle_fd, display_ref, strlen(display_ref)); @@ -431,6 +436,8 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs) free(ref); } + strset_clear(&objects); + /* end header */ write_or_die(bundle_fd, "\n", 1); return ref_count; @@ -566,7 +573,6 @@ int create_bundle(struct repository *r, const char *path, */ revs.blob_objects = revs.tree_objects = 0; traverse_commit_list(&revs, write_bundle_prerequisites, NULL, &bpi); - object_array_remove_duplicates(&revs_copy.pending); /* write bundle refs */ ref_count = write_bundle_refs(bundle_fd, &revs_copy); @@ -492,44 +492,11 @@ void object_array_clear(struct object_array *array) array->nr = array->alloc = 0; } -/* - * Return true if array already contains an entry. - */ -static int contains_object(struct object_array *array, - const struct object *item, const char *name) -{ - unsigned nr = array->nr, i; - struct object_array_entry *object = array->objects; - - for (i = 0; i < nr; i++, object++) - if (item == object->item && !strcmp(object->name, name)) - return 1; - return 0; -} - -void object_array_remove_duplicates(struct object_array *array) -{ - unsigned nr = array->nr, src; - struct object_array_entry *objects = array->objects; - - array->nr = 0; - for (src = 0; src < nr; src++) { - if (!contains_object(array, objects[src].item, - objects[src].name)) { - if (src != array->nr) - objects[array->nr] = objects[src]; - array->nr++; - } else { - object_array_release_entry(&objects[src]); - } - } -} - void clear_object_flags(struct repository *repo, unsigned flags) { int i; - for (i=0; i < repo->parsed_objects->obj_hash_size; i++) { + for (i = 0; i < repo->parsed_objects->obj_hash_size; i++) { struct object *obj = repo->parsed_objects->obj_hash[i]; if (obj) obj->flags &= ~flags; @@ -327,12 +327,6 @@ void object_array_filter(struct object_array *array, object_array_each_func_t want, void *cb_data); /* - * Remove from array all but the first entry with a given name. - * Warning: this function uses an O(N^2) algorithm. - */ -void object_array_remove_duplicates(struct object_array *array); - -/* * Remove any objects from the array, freeing all used memory; afterwards * the array is ready to store more objects with add_object_array(). */ diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh index b3807e8f35..500c81b8a1 100755 --- a/t/t6020-bundle-misc.sh +++ b/t/t6020-bundle-misc.sh @@ -673,6 +673,59 @@ test_expect_success 'bundle progress with --no-quiet' ' grep "%" err ' +test_expect_success 'create bundle with duplicate refnames' ' + git bundle create out.bdl "main" "main" && + + git bundle list-heads out.bdl | + make_user_friendly_and_stable_output >actual && + cat >expect <<-\EOF && + <COMMIT-P> refs/heads/main + EOF + test_cmp expect actual +' + +test_expect_success 'create bundle with duplicate refnames and --all' ' + git bundle create out.bdl --all "main" "main" && + + git bundle list-heads out.bdl | + make_user_friendly_and_stable_output >actual && + cat >expect <<-\EOF && + <COMMIT-P> refs/heads/main + <COMMIT-N> refs/heads/release + <COMMIT-D> refs/heads/topic/1 + <COMMIT-H> refs/heads/topic/2 + <COMMIT-D> refs/pull/1/head + <COMMIT-G> refs/pull/2/head + <TAG-1> refs/tags/v1 + <TAG-2> refs/tags/v2 + <TAG-3> refs/tags/v3 + <COMMIT-P> HEAD + EOF + test_cmp expect actual +' + +test_expect_success 'create bundle with duplicate exlusion refnames' ' + git bundle create out.bdl "main" "main^!" && + + git bundle list-heads out.bdl | + make_user_friendly_and_stable_output >actual && + cat >expect <<-\EOF && + <COMMIT-P> refs/heads/main + EOF + test_cmp expect actual +' + +test_expect_success 'create bundle with duplicate refname short-form' ' + git bundle create out.bdl "main" "main" "refs/heads/main" "refs/heads/main" && + + git bundle list-heads out.bdl | + make_user_friendly_and_stable_output >actual && + cat >expect <<-\EOF && + <COMMIT-P> refs/heads/main + EOF + test_cmp expect actual +' + test_expect_success 'read bundle over stdin' ' git bundle create some.bundle HEAD && |
