Skip to content

Commit 73f43f2

Browse files
peffgitster
authored andcommitted
paint_down_to_common: use prio_queue
When we are traversing to find merge bases, we keep our usual commit_list of commits to process, sorted by their commit timestamp. As we add each parent to the list, we have to spend "O(width of history)" to do the insertion, where the width of history is the number of simultaneous lines of development. If we instead use a heap-based priority queue, we can do these insertions in "O(log width)" time. This provides minor speedups to merge-base calculations (timings in linux.git, warm cache, best-of-five): [before] $ git merge-base HEAD v2.6.12 real 0m3.251s user 0m3.148s sys 0m0.104s [after] $ git merge-base HEAD v2.6.12 real 0m3.234s user 0m3.108s sys 0m0.128s That's only an 0.5% speedup, but it does help protect us against pathological cases. While we are munging the "interesting" function, we also take the opportunity to give it a more descriptive name, and convert the return value to an int (we returned the first interesting commit, but nobody ever looked at it). Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent e8f91e3 commit 73f43f2

File tree

1 file changed

+19
-23
lines changed

1 file changed

+19
-23
lines changed

commit.c

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -786,45 +786,41 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so
786786

787787
static const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT);
788788

789-
static struct commit *interesting(struct commit_list *list)
789+
static int queue_has_nonstale(struct prio_queue *queue)
790790
{
791-
while (list) {
792-
struct commit *commit = list->item;
793-
list = list->next;
794-
if (commit->object.flags & STALE)
795-
continue;
796-
return commit;
791+
int i;
792+
for (i = 0; i < queue->nr; i++) {
793+
struct commit *commit = queue->array[i].data;
794+
if (!(commit->object.flags & STALE))
795+
return 1;
797796
}
798-
return NULL;
797+
return 0;
799798
}
800799

801800
/* all input commits in one and twos[] must have been parsed! */
802801
static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos)
803802
{
804-
struct commit_list *list = NULL;
803+
struct prio_queue queue = { compare_commits_by_commit_date };
805804
struct commit_list *result = NULL;
806805
int i;
807806

808807
one->object.flags |= PARENT1;
809-
commit_list_insert_by_date(one, &list);
810-
if (!n)
811-
return list;
808+
if (!n) {
809+
commit_list_append(one, &result);
810+
return result;
811+
}
812+
prio_queue_put(&queue, one);
813+
812814
for (i = 0; i < n; i++) {
813815
twos[i]->object.flags |= PARENT2;
814-
commit_list_insert_by_date(twos[i], &list);
816+
prio_queue_put(&queue, twos[i]);
815817
}
816818

817-
while (interesting(list)) {
818-
struct commit *commit;
819+
while (queue_has_nonstale(&queue)) {
820+
struct commit *commit = prio_queue_get(&queue);
819821
struct commit_list *parents;
820-
struct commit_list *next;
821822
int flags;
822823

823-
commit = list->item;
824-
next = list->next;
825-
free(list);
826-
list = next;
827-
828824
flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
829825
if (flags == (PARENT1 | PARENT2)) {
830826
if (!(commit->object.flags & RESULT)) {
@@ -843,11 +839,11 @@ static struct commit_list *paint_down_to_common(struct commit *one, int n, struc
843839
if (parse_commit(p))
844840
return NULL;
845841
p->object.flags |= flags;
846-
commit_list_insert_by_date(p, &list);
842+
prio_queue_put(&queue, p);
847843
}
848844
}
849845

850-
free_commit_list(list);
846+
clear_prio_queue(&queue);
851847
return result;
852848
}
853849

0 commit comments

Comments
 (0)