summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2015-04-14 03:26:45 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2015-04-14 03:26:45 +0200
commita05416951e15a2fea4036ddf502f44504bb53faa (patch)
tree0baec585b44ad42cfa019fc2ba9ae3b2e0b35eeb
parent623fbd93f1a7538df0c9a433df68f87bbd58b803 (diff)
downloadlibgit2-cmn/odd-slowdown.tar.gz
revwalk: detect when we're out of interesting commitscmn/odd-slowdown
When walking backwards and marking parents uninteresting, make sure we detect when the list of commits we have left has run out of uninteresting commits so we can stop marking commits as uninteresting. Failing to do so can mean that we walk the whole history marking everything uninteresting, which eats up time, CPU and IO for with useless work. While pre-marking does look for this, we still need to check during the main traversal as there are setups for which pre-marking does not leave enough information in the commits. This can happen if we push a commit and hide its parent.
-rw-r--r--src/revwalk.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/src/revwalk.c b/src/revwalk.c
index a6d823ec8..5f5ae9ae4 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -41,11 +41,31 @@ git_commit_list_node *git_revwalk__commit_lookup(
return commit;
}
+typedef git_array_t(git_commit_list_node*) commit_list_node_array;
+
+static bool interesting_arr(commit_list_node_array arr)
+{
+ git_commit_list_node **n;
+ size_t i = 0, size;
+
+ size = git_array_size(arr);
+ for (i = 0; i < size; i++) {
+ n = git_array_get(arr, i);
+ if (!*n)
+ break;
+
+ if (!(*n)->uninteresting)
+ return true;
+ }
+
+ return false;
+}
+
static int mark_uninteresting(git_revwalk *walk, git_commit_list_node *commit)
{
int error;
unsigned short i;
- git_array_t(git_commit_list_node *) pending = GIT_ARRAY_INIT;
+ commit_list_node_array pending = GIT_ARRAY_INIT;
git_commit_list_node **tmp;
assert(commit);
@@ -66,7 +86,7 @@ static int mark_uninteresting(git_revwalk *walk, git_commit_list_node *commit)
tmp = git_array_pop(pending);
commit = tmp ? *tmp : NULL;
- } while (commit != NULL);
+ } while (commit != NULL && !interesting_arr(pending));
git_array_clear(pending);