Skip to content

Commit 7b8a21d

Browse files
derrickstoleegitster
authored andcommitted
commit-graph: lazy-load trees for commits
The commit-graph file provides quick access to commit data, including the OID of the root tree for each commit in the graph. When performing a deep commit-graph walk, we may not need to load most of the trees for these commits. Delay loading the tree object for a commit loaded from the graph until requested via get_commit_tree(). Do not lazy-load trees for commits not in the graph, since that requires duplicate parsing and the relative peformance improvement when trees are not needed is small. On the Linux repository, performance tests were run for the following command: git log --graph --oneline -1000 Before: 0.92s After: 0.66s Rel %: -28.3% Adding '-- kernel/' to the command requires loading the root tree for every commit that is walked. There was no measureable performance change as a result of this patch. Signed-off-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2e27bd7 commit 7b8a21d

File tree

4 files changed

+38
-4
lines changed

4 files changed

+38
-4
lines changed

commit-graph.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,6 @@ static struct commit_list **insert_parent_or_die(struct commit_graph *g,
247247

248248
static int fill_commit_in_graph(struct commit *item, struct commit_graph *g, uint32_t pos)
249249
{
250-
struct object_id oid;
251250
uint32_t edge_value;
252251
uint32_t *parent_data_ptr;
253252
uint64_t date_low, date_high;
@@ -257,8 +256,7 @@ static int fill_commit_in_graph(struct commit *item, struct commit_graph *g, uin
257256
item->object.parsed = 1;
258257
item->graph_pos = pos;
259258

260-
hashcpy(oid.hash, commit_data);
261-
item->maybe_tree = lookup_tree(&oid);
259+
item->maybe_tree = NULL;
262260

263261
date_high = get_be32(commit_data + g->hash_len + 8) & 0x3;
264262
date_low = get_be32(commit_data + g->hash_len + 12);
@@ -317,6 +315,28 @@ int parse_commit_in_graph(struct commit *item)
317315
return 0;
318316
}
319317

318+
static struct tree *load_tree_for_commit(struct commit_graph *g, struct commit *c)
319+
{
320+
struct object_id oid;
321+
const unsigned char *commit_data = g->chunk_commit_data +
322+
GRAPH_DATA_WIDTH * (c->graph_pos);
323+
324+
hashcpy(oid.hash, commit_data);
325+
c->maybe_tree = lookup_tree(&oid);
326+
327+
return c->maybe_tree;
328+
}
329+
330+
struct tree *get_commit_tree_in_graph(const struct commit *c)
331+
{
332+
if (c->maybe_tree)
333+
return c->maybe_tree;
334+
if (c->graph_pos == COMMIT_NOT_FROM_GRAPH)
335+
BUG("get_commit_tree_in_graph called from non-commit-graph commit");
336+
337+
return load_tree_for_commit(commit_graph, (struct commit *)c);
338+
}
339+
320340
static void write_graph_chunk_fanout(struct hashfile *f,
321341
struct commit **commits,
322342
int nr_commits)

commit-graph.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ char *get_commit_graph_filename(const char *obj_dir);
1717
*/
1818
int parse_commit_in_graph(struct commit *item);
1919

20+
struct tree *get_commit_tree_in_graph(const struct commit *c);
21+
2022
struct commit_graph {
2123
int graph_fd;
2224

commit.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,13 @@ void free_commit_buffer(struct commit *commit)
298298

299299
struct tree *get_commit_tree(const struct commit *commit)
300300
{
301-
return commit->maybe_tree;
301+
if (commit->maybe_tree || !commit->object.parsed)
302+
return commit->maybe_tree;
303+
304+
if (commit->graph_pos == COMMIT_NOT_FROM_GRAPH)
305+
BUG("commit has NULL tree, but was not loaded from commit-graph");
306+
307+
return get_commit_tree_in_graph(commit);
302308
}
303309

304310
struct object_id *get_commit_tree_oid(const struct commit *commit)

commit.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ struct commit {
2222
unsigned int index;
2323
timestamp_t date;
2424
struct commit_list *parents;
25+
26+
/*
27+
* If the commit is loaded from the commit-graph file, then this
28+
* member may be NULL. Only access it through get_commit_tree()
29+
* or get_commit_tree_oid().
30+
*/
2531
struct tree *maybe_tree;
2632
uint32_t graph_pos;
2733
};

0 commit comments

Comments
 (0)