mirror of
https://github.com/git/git
synced 2024-08-27 11:39:22 +00:00
Eliminate recursion in setting/clearing marks in commit list
Recursion in a DAG is generally a bad idea because it could be very deep. Be defensive and avoid recursion in mark_parents_uninteresting() and clear_commit_marks(). mark_parents_uninteresting() learns a trick from clear_commit_marks() to avoid malloc() in (dominant) single-parent case. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
ec330158ec
commit
941ba8db57
13
commit.c
13
commit.c
|
@ -421,7 +421,8 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_commit_marks(struct commit *commit, unsigned int mark)
|
static void clear_commit_marks_1(struct commit_list **plist,
|
||||||
|
struct commit *commit, unsigned int mark)
|
||||||
{
|
{
|
||||||
while (commit) {
|
while (commit) {
|
||||||
struct commit_list *parents;
|
struct commit_list *parents;
|
||||||
|
@ -436,12 +437,20 @@ void clear_commit_marks(struct commit *commit, unsigned int mark)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while ((parents = parents->next))
|
while ((parents = parents->next))
|
||||||
clear_commit_marks(parents->item, mark);
|
commit_list_insert(parents->item, plist);
|
||||||
|
|
||||||
commit = commit->parents->item;
|
commit = commit->parents->item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear_commit_marks(struct commit *commit, unsigned int mark)
|
||||||
|
{
|
||||||
|
struct commit_list *list = NULL;
|
||||||
|
commit_list_insert(commit, &list);
|
||||||
|
while (list)
|
||||||
|
clear_commit_marks_1(&list, pop_commit(&list), mark);
|
||||||
|
}
|
||||||
|
|
||||||
void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark)
|
void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark)
|
||||||
{
|
{
|
||||||
struct object *object;
|
struct object *object;
|
||||||
|
|
45
revision.c
45
revision.c
|
@ -139,11 +139,32 @@ void mark_tree_uninteresting(struct tree *tree)
|
||||||
|
|
||||||
void mark_parents_uninteresting(struct commit *commit)
|
void mark_parents_uninteresting(struct commit *commit)
|
||||||
{
|
{
|
||||||
struct commit_list *parents = commit->parents;
|
struct commit_list *parents = NULL, *l;
|
||||||
|
|
||||||
|
for (l = commit->parents; l; l = l->next)
|
||||||
|
commit_list_insert(l->item, &parents);
|
||||||
|
|
||||||
while (parents) {
|
while (parents) {
|
||||||
struct commit *commit = parents->item;
|
struct commit *commit = parents->item;
|
||||||
if (!(commit->object.flags & UNINTERESTING)) {
|
l = parents;
|
||||||
|
parents = parents->next;
|
||||||
|
free(l);
|
||||||
|
|
||||||
|
while (commit) {
|
||||||
|
/*
|
||||||
|
* A missing commit is ok iff its parent is marked
|
||||||
|
* uninteresting.
|
||||||
|
*
|
||||||
|
* We just mark such a thing parsed, so that when
|
||||||
|
* it is popped next time around, we won't be trying
|
||||||
|
* to parse it and get an error.
|
||||||
|
*/
|
||||||
|
if (!has_sha1_file(commit->object.sha1))
|
||||||
|
commit->object.parsed = 1;
|
||||||
|
|
||||||
|
if (commit->object.flags & UNINTERESTING)
|
||||||
|
break;
|
||||||
|
|
||||||
commit->object.flags |= UNINTERESTING;
|
commit->object.flags |= UNINTERESTING;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -154,21 +175,13 @@ void mark_parents_uninteresting(struct commit *commit)
|
||||||
* wasn't uninteresting), in which case we need
|
* wasn't uninteresting), in which case we need
|
||||||
* to mark its parents recursively too..
|
* to mark its parents recursively too..
|
||||||
*/
|
*/
|
||||||
if (commit->parents)
|
if (!commit->parents)
|
||||||
mark_parents_uninteresting(commit);
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
for (l = commit->parents->next; l; l = l->next)
|
||||||
* A missing commit is ok iff its parent is marked
|
commit_list_insert(l->item, &parents);
|
||||||
* uninteresting.
|
commit = commit->parents->item;
|
||||||
*
|
}
|
||||||
* We just mark such a thing parsed, so that when
|
|
||||||
* it is popped next time around, we won't be trying
|
|
||||||
* to parse it and get an error.
|
|
||||||
*/
|
|
||||||
if (!has_sha1_file(commit->object.sha1))
|
|
||||||
commit->object.parsed = 1;
|
|
||||||
parents = parents->next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue