aboutsummaryrefslogtreecommitdiff
path: root/revision.c
diff options
context:
space:
mode:
authorAlexander N. Gavrilov <angavrilov@gmail.com>2008-07-12 22:00:57 +0400
committerJunio C Hamano <gitster@pobox.com>2008-07-13 13:46:56 -0700
commitfce87ae53883d22a9912abb2d11a926de747006e (patch)
tree4b86b3ed068814d0b2cc1d4c85473b20e8ee35ec /revision.c
parente09c4e753c337d914f4eb7a05cb5e8bbfc362489 (diff)
downloadgit-fce87ae53883d22a9912abb2d11a926de747006e.tar.gz
git-fce87ae53883d22a9912abb2d11a926de747006e.tar.xz
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>
Diffstat (limited to 'revision.c')
-rw-r--r--revision.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/revision.c b/revision.c
index fc6675525..d464f14d5 100644
--- a/revision.c
+++ b/revision.c
@@ -412,10 +412,26 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
commit->object.flags |= TREESAME;
}
-static int add_parents_to_list(struct rev_info *revs, struct commit *commit, struct commit_list **list)
+static void insert_by_date_cached(struct commit *p, struct commit_list **head,
+ struct commit_list *cached_base, struct commit_list **cache)
+{
+ struct commit_list *new_entry;
+
+ if (cached_base && p->date < cached_base->item->date)
+ new_entry = insert_by_date(p, &cached_base->next);
+ else
+ new_entry = insert_by_date(p, head);
+
+ if (cache && (!*cache || p->date < (*cache)->item->date))
+ *cache = new_entry;
+}
+
+static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
+ struct commit_list **list, struct commit_list **cache_ptr)
{
struct commit_list *parent = commit->parents;
unsigned left_flag;
+ struct commit_list *cached_base = cache_ptr ? *cache_ptr : NULL;
if (commit->object.flags & ADDED)
return 0;
@@ -445,7 +461,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, str
if (p->object.flags & SEEN)
continue;
p->object.flags |= SEEN;
- insert_by_date(p, list);
+ insert_by_date_cached(p, list, cached_base, cache_ptr);
}
return 0;
}
@@ -470,7 +486,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, str
p->object.flags |= left_flag;
if (!(p->object.flags & SEEN)) {
p->object.flags |= SEEN;
- insert_by_date(p, list);
+ insert_by_date_cached(p, list, cached_base, cache_ptr);
}
if(revs->first_parent_only)
break;
@@ -611,7 +627,7 @@ static int limit_list(struct rev_info *revs)
if (revs->max_age != -1 && (commit->date < revs->max_age))
obj->flags |= UNINTERESTING;
- if (add_parents_to_list(revs, commit, &list) < 0)
+ if (add_parents_to_list(revs, commit, &list, NULL) < 0)
return -1;
if (obj->flags & UNINTERESTING) {
mark_parents_uninteresting(commit);
@@ -1458,10 +1474,12 @@ enum rewrite_result {
static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp)
{
+ struct commit_list *cache = NULL;
+
for (;;) {
struct commit *p = *pp;
if (!revs->limited)
- if (add_parents_to_list(revs, p, &revs->commits) < 0)
+ if (add_parents_to_list(revs, p, &revs->commits, &cache) < 0)
return rewrite_one_error;
if (p->parents && p->parents->next)
return rewrite_one_ok;
@@ -1580,7 +1598,7 @@ static struct commit *get_revision_1(struct rev_info *revs)
if (revs->max_age != -1 &&
(commit->date < revs->max_age))
continue;
- if (add_parents_to_list(revs, commit, &revs->commits) < 0)
+ if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0)
return NULL;
}