]> git.ipfire.org Git - thirdparty/git.git/commitdiff
fetch-pack: speed up loading of refs via commit graph
authorPatrick Steinhardt <ps@pks.im>
Wed, 4 Aug 2021 13:56:11 +0000 (15:56 +0200)
committerJunio C Hamano <gitster@pobox.com>
Wed, 4 Aug 2021 17:45:32 +0000 (10:45 -0700)
When doing reference negotiation, git-fetch-pack(1) is loading all refs
from disk in order to determine which commits it has in common with the
remote repository. This can be quite expensive in repositories with many
references though: in a real-world repository with around 2.2 million
refs, fetching a single commit by its ID takes around 44 seconds.

Dominating the loading time is decompression and parsing of the objects
which are referenced by commits. Given the fact that we only care about
commits (or tags which can be peeled to one) in this context, there is
thus an easy performance win by switching the parsing logic to make use
of the commit graph in case we have one available. Like this, we avoid
hitting the object database to parse these commits but instead only load
them from the commit-graph. This results in a significant performance
boost when executing git-fetch in said repository with 2.2 million refs:

    Benchmark #1: HEAD~: git fetch $remote $commit
      Time (mean ± σ):     44.168 s ±  0.341 s    [User: 42.985 s, System: 1.106 s]
      Range (min … max):   43.565 s … 44.577 s    10 runs

    Benchmark #2: HEAD: git fetch $remote $commit
      Time (mean ± σ):     19.498 s ±  0.724 s    [User: 18.751 s, System: 0.690 s]
      Range (min … max):   18.629 s … 20.454 s    10 runs

    Summary
      'HEAD: git fetch $remote $commit' ran
        2.27 ± 0.09 times faster than 'HEAD~: git fetch $remote $commit'

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
fetch-pack.c

index c135635e34a9000a948186c0e316865d14dc89c0..89fdeb3497a05975abea8d1a6e874ffff46bc48d 100644 (file)
@@ -137,8 +137,14 @@ static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
                        break;
                }
        }
-       if (type == OBJ_COMMIT)
-               return (struct commit *) parse_object(the_repository, oid);
+
+       if (type == OBJ_COMMIT) {
+               struct commit *commit = lookup_commit(the_repository, oid);
+               if (!commit || repo_parse_commit(the_repository, commit))
+                       return NULL;
+               return commit;
+       }
+
        return NULL;
 }