Skip to content

Commit 94f0ced

Browse files
committed
get_merge_bases_many(): walk from many tips in parallel
The get_merge_bases_many() function reduces the result returned by the merge_bases_many() function, which is a set of possible merge bases, by excluding commits that can be reached from other commits. We used to do N*(N-1) traversals for this, but we can check if one commit reaches which other (N-1) commits by a single traversal, and repeat it for all the candidates to find the answer. Introduce remove_redundant() helper function to do this painting; we should be able to use it to reimplement reduce_heads() as well. Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6440fdb commit 94f0ced

File tree

1 file changed

+58
-21
lines changed

1 file changed

+58
-21
lines changed

commit.c

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,60 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
692692
return ret;
693693
}
694694

695+
static int remove_redundant(struct commit **array, int cnt)
696+
{
697+
/*
698+
* Some commit in the array may be an ancestor of
699+
* another commit. Move such commit to the end of
700+
* the array, and return the number of commits that
701+
* are independent from each other.
702+
*/
703+
struct commit **work;
704+
unsigned char *redundant;
705+
int *filled_index;
706+
int i, j, filled;
707+
708+
work = xcalloc(cnt, sizeof(*work));
709+
redundant = xcalloc(cnt, 1);
710+
filled_index = xmalloc(sizeof(*filled_index) * (cnt - 1));
711+
712+
for (i = 0; i < cnt; i++) {
713+
struct commit_list *common;
714+
715+
if (redundant[i])
716+
continue;
717+
for (j = filled = 0; j < cnt; j++) {
718+
if (i == j || redundant[j])
719+
continue;
720+
filled_index[filled] = j;
721+
work[filled++] = array[j];
722+
}
723+
common = paint_down_to_common(array[i], filled, work);
724+
if (array[i]->object.flags & PARENT2)
725+
redundant[i] = 1;
726+
for (j = 0; j < filled; j++)
727+
if (work[j]->object.flags & PARENT1)
728+
redundant[filled_index[j]] = 1;
729+
clear_commit_marks(array[i], all_flags);
730+
for (j = 0; j < filled; j++)
731+
clear_commit_marks(work[j], all_flags);
732+
free_commit_list(common);
733+
}
734+
735+
/* Now collect the result */
736+
memcpy(work, array, sizeof(*array) * cnt);
737+
for (i = filled = 0; i < cnt; i++)
738+
if (!redundant[i])
739+
array[filled++] = work[i];
740+
for (j = filled, i = 0; i < cnt; i++)
741+
if (redundant[i])
742+
array[j++] = work[i];
743+
free(work);
744+
free(redundant);
745+
free(filled_index);
746+
return filled;
747+
}
748+
695749
struct commit_list *get_merge_bases_many(struct commit *one,
696750
int n,
697751
struct commit **twos,
@@ -700,7 +754,7 @@ struct commit_list *get_merge_bases_many(struct commit *one,
700754
struct commit_list *list;
701755
struct commit **rslt;
702756
struct commit_list *result;
703-
int cnt, i, j;
757+
int cnt, i;
704758

705759
result = merge_bases_many(one, n, twos);
706760
for (i = 0; i < n; i++) {
@@ -731,28 +785,11 @@ struct commit_list *get_merge_bases_many(struct commit *one,
731785
clear_commit_marks(one, all_flags);
732786
for (i = 0; i < n; i++)
733787
clear_commit_marks(twos[i], all_flags);
734-
for (i = 0; i < cnt - 1; i++) {
735-
for (j = i+1; j < cnt; j++) {
736-
if (!rslt[i] || !rslt[j])
737-
continue;
738-
result = merge_bases_many(rslt[i], 1, &rslt[j]);
739-
clear_commit_marks(rslt[i], all_flags);
740-
clear_commit_marks(rslt[j], all_flags);
741-
for (list = result; list; list = list->next) {
742-
if (rslt[i] == list->item)
743-
rslt[i] = NULL;
744-
if (rslt[j] == list->item)
745-
rslt[j] = NULL;
746-
}
747-
}
748-
}
749788

750-
/* Surviving ones in rslt[] are the independent results */
789+
cnt = remove_redundant(rslt, cnt);
751790
result = NULL;
752-
for (i = 0; i < cnt; i++) {
753-
if (rslt[i])
754-
commit_list_insert_by_date(rslt[i], &result);
755-
}
791+
for (i = 0; i < cnt; i++)
792+
commit_list_insert_by_date(rslt[i], &result);
756793
free(rslt);
757794
return result;
758795
}

0 commit comments

Comments
 (0)