fetch-pack: avoid quadratic list insertion in mark_complete
We insert the commit pointed to by each ref one-by-one into
the "complete" commit_list using insert_by_date. Because
each insertion is O(n), we end up with O(n^2) behavior.
This typically doesn't matter, because the number of refs is
reasonably small. And even if there are a lot of refs, they
often point to a smaller set of objects (in which case the
optimization in commit ea5f220
keeps our "n" small).
However, in pathological repositories (hundreds of thousands
of refs, each pointing to a unique commit), this quadratic
behavior can make a difference. Since we do not care about
the list order until we have finished building it, we can
simply keep it unsorted during the insertion phase, then
sort it afterwards.
On a repository like the one described above, this dropped
the time to do a no-op fetch from 2.0s to 1.7s. On normal
repositories, it probably does not matter at all, but it
does not hurt to protect ourselves from pathological cases.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
534f0e0996
commit
16445242ed
@ -505,7 +505,7 @@ static int mark_complete(const char *refname, const unsigned char *sha1, int fla
|
||||
struct commit *commit = (struct commit *)o;
|
||||
if (!(commit->object.flags & COMPLETE)) {
|
||||
commit->object.flags |= COMPLETE;
|
||||
commit_list_insert_by_date(commit, &complete);
|
||||
commit_list_insert(commit, &complete);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -622,6 +622,7 @@ static int everything_local(struct fetch_pack_args *args,
|
||||
if (!args->depth) {
|
||||
for_each_ref(mark_complete, NULL);
|
||||
for_each_alternate_ref(mark_alternate_complete, NULL);
|
||||
commit_list_sort_by_date(&complete);
|
||||
if (cutoff)
|
||||
mark_recent_complete_commits(args, cutoff);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user