@matheusbsbs / matheus-bagliano / commits / fce87ae538
Fork 0

Fix quadratic performance in rewrite_one.

Parent commits are usually older than their children. Thus, on each iteration of the loop in rewrite_one, add_parents_to_list traverses all commits previously processed by the loop. It performs very poorly in case of very long rewrite chains. Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Alexander N. Gavrilov committed Jul 12, 2008 at 22:00 UTC fce87ae53883d22a9912abb2d11a926de747006e
1 file changed +24 -6
revision.c
+24 -6
@@ -412,10 +412,26 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
412 commit->object.flags |= TREESAME;
413 }
414
415 -static int add_parents_to_list(struct rev_info *revs, struct commit *commit, struct commit_list **list)
415 +static void insert_by_date_cached(struct commit *p, struct commit_list **head,
416 + struct commit_list *cached_base, struct commit_list **cache)
417 +{
418 + struct commit_list *new_entry;
419 +
420 + if (cached_base && p->date < cached_base->item->date)
421 + new_entry = insert_by_date(p, &cached_base->next);
422 + else
423 + new_entry = insert_by_date(p, head);
424 +
425 + if (cache && (!*cache || p->date < (*cache)->item->date))
426 + *cache = new_entry;
427 +}
428 +
429 +static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
430 + struct commit_list **list, struct commit_list **cache_ptr)
431 {
432 struct commit_list *parent = commit->parents;
433 unsigned left_flag;
434 + struct commit_list *cached_base = cache_ptr ? *cache_ptr : NULL;
435
436 if (commit->object.flags & ADDED)
437 return 0;
@@ -445,7 +461,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, str
461 if (p->object.flags & SEEN)
462 continue;
463 p->object.flags |= SEEN;
448 - insert_by_date(p, list);
464 + insert_by_date_cached(p, list, cached_base, cache_ptr);
465 }
466 return 0;
467 }
@@ -470,7 +486,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, str
486 p->object.flags |= left_flag;
487 if (!(p->object.flags & SEEN)) {
488 p->object.flags |= SEEN;
473 - insert_by_date(p, list);
489 + insert_by_date_cached(p, list, cached_base, cache_ptr);
490 }
491 if(revs->first_parent_only)
492 break;
@@ -611,7 +627,7 @@ static int limit_list(struct rev_info *revs)
627
628 if (revs->max_age != -1 && (commit->date < revs->max_age))
629 obj->flags |= UNINTERESTING;
614 - if (add_parents_to_list(revs, commit, &list) < 0)
630 + if (add_parents_to_list(revs, commit, &list, NULL) < 0)
631 return -1;
632 if (obj->flags & UNINTERESTING) {
633 mark_parents_uninteresting(commit);
@@ -1458,10 +1474,12 @@ enum rewrite_result {
1474
1475 static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp)
1476 {
1477 + struct commit_list *cache = NULL;
1478 +
1479 for (;;) {
1480 struct commit *p = *pp;
1481 if (!revs->limited)
1464 - if (add_parents_to_list(revs, p, &revs->commits) < 0)
1482 + if (add_parents_to_list(revs, p, &revs->commits, &cache) < 0)
1483 return rewrite_one_error;
1484 if (p->parents && p->parents->next)
1485 return rewrite_one_ok;
@@ -1580,7 +1598,7 @@ static struct commit *get_revision_1(struct rev_info *revs)
1598 if (revs->max_age != -1 &&
1599 (commit->date < revs->max_age))
1600 continue;
1583 - if (add_parents_to_list(revs, commit, &revs->commits) < 0)
1601 + if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0)
1602 return NULL;
1603 }
1604