Skip to content

Commit 85daa01

Browse files
derrickstoleegitster
authored andcommitted
remote: make add_missing_tags() linear
The add_missing_tags() method currently has quadratic behavior. This is due to a linear number (based on number of tags T) of calls to in_merge_bases_many, which has linear performance (based on number of commits C in the repository). Replace this O(T * C) algorithm with an O(T + C) algorithm by using get_reachable_subset(). We ignore the return list and focus instead on the reachable_flag assigned to the commits we care about, because we need to interact with the tag ref and not just the commit object. Signed-off-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 4c7bb45 commit 85daa01

File tree

1 file changed

+33
-1
lines changed

1 file changed

+33
-1
lines changed

remote.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1205,9 +1205,36 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds
12051205
* sent to the other side.
12061206
*/
12071207
if (sent_tips.nr) {
1208+
const int reachable_flag = 1;
1209+
struct commit_list *found_commits;
1210+
struct commit **src_commits;
1211+
int nr_src_commits = 0, alloc_src_commits = 16;
1212+
ALLOC_ARRAY(src_commits, alloc_src_commits);
1213+
12081214
for_each_string_list_item(item, &src_tag) {
12091215
struct ref *ref = item->util;
1216+
struct commit *commit;
1217+
1218+
if (is_null_oid(&ref->new_oid))
1219+
continue;
1220+
commit = lookup_commit_reference_gently(the_repository,
1221+
&ref->new_oid,
1222+
1);
1223+
if (!commit)
1224+
/* not pushing a commit, which is not an error */
1225+
continue;
1226+
1227+
ALLOC_GROW(src_commits, nr_src_commits + 1, alloc_src_commits);
1228+
src_commits[nr_src_commits++] = commit;
1229+
}
1230+
1231+
found_commits = get_reachable_subset(sent_tips.tip, sent_tips.nr,
1232+
src_commits, nr_src_commits,
1233+
reachable_flag);
1234+
1235+
for_each_string_list_item(item, &src_tag) {
12101236
struct ref *dst_ref;
1237+
struct ref *ref = item->util;
12111238
struct commit *commit;
12121239

12131240
if (is_null_oid(&ref->new_oid))
@@ -1223,15 +1250,20 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds
12231250
* Is this tag, which they do not have, reachable from
12241251
* any of the commits we are sending?
12251252
*/
1226-
if (!in_merge_bases_many(commit, sent_tips.nr, sent_tips.tip))
1253+
if (!(commit->object.flags & reachable_flag))
12271254
continue;
12281255

12291256
/* Add it in */
12301257
dst_ref = make_linked_ref(ref->name, dst_tail);
12311258
oidcpy(&dst_ref->new_oid, &ref->new_oid);
12321259
dst_ref->peer_ref = copy_ref(ref);
12331260
}
1261+
1262+
clear_commit_marks_many(nr_src_commits, src_commits, reachable_flag);
1263+
free(src_commits);
1264+
free_commit_list(found_commits);
12341265
}
1266+
12351267
string_list_clear(&src_tag, 0);
12361268
free(sent_tips.tip);
12371269
}

0 commit comments

Comments
 (0)