revision: avoid hitting packfiles when commits are in commit-graph
When queueing references in git-rev-list(1), we try to optimize parsing of commits via the commit-graph. To do so, we first look up the object's type, and if it is a commit we call `repo_parse_commit()` instead of `parse_object()`. This is quite inefficient though given that we're always uncompressing the object header in order to determine the type. Instead, we can opportunistically search the commit-graph for the object ID: in case it's found, we know it's a commit and can directly fill in the commit object without having to uncompress the object header. Expose a new function `lookup_commit_in_graph()`, which tries to find a commit in the commit-graph by ID, and convert `get_reference()` to use this function. This provides a big performance win in cases where we load references in a repository with lots of references pointing to commits. The following has been executed in a real-world repository with about 2.2 million refs: Benchmark #1: HEAD~: rev-list --unsorted-input --objects --quiet --not --all --not $newrev Time (mean ± σ): 4.458 s ± 0.044 s [User: 4.115 s, System: 0.342 s] Range (min … max): 4.409 s … 4.534 s 10 runs Benchmark #2: HEAD: rev-list --unsorted-input --objects --quiet --not --all --not $newrev Time (mean ± σ): 3.089 s ± 0.015 s [User: 2.768 s, System: 0.321 s] Range (min … max): 3.061 s … 3.105 s 10 runs Summary 'HEAD: rev-list --unsorted-input --objects --quiet --not --all --not $newrev' ran 1.44 ± 0.02 times faster than 'HEAD~: rev-list --unsorted-input --objects --quiet --not --all --not $newrev' Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
809ea28f80
commit
f559d6d45e
18
revision.c
18
revision.c
@ -360,20 +360,18 @@ static struct object *get_reference(struct rev_info *revs, const char *name,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct object *object;
|
||||
struct commit *commit;
|
||||
|
||||
/*
|
||||
* If the repository has commit graphs, repo_parse_commit() avoids
|
||||
* reading the object buffer, so use it whenever possible.
|
||||
* If the repository has commit graphs, we try to opportunistically
|
||||
* look up the object ID in those graphs. Like this, we can avoid
|
||||
* parsing commit data from disk.
|
||||
*/
|
||||
if (oid_object_info(revs->repo, oid, NULL) == OBJ_COMMIT) {
|
||||
struct commit *c = lookup_commit(revs->repo, oid);
|
||||
if (!repo_parse_commit(revs->repo, c))
|
||||
object = (struct object *) c;
|
||||
else
|
||||
object = NULL;
|
||||
} else {
|
||||
commit = lookup_commit_in_graph(revs->repo, oid);
|
||||
if (commit)
|
||||
object = &commit->object;
|
||||
else
|
||||
object = parse_object(revs->repo, oid);
|
||||
}
|
||||
|
||||
if (!object) {
|
||||
if (revs->ignore_missing)
|
||||
|
Reference in New Issue
Block a user