Skip to content

Commit

Permalink
Merge branch 'ds/lazy-load-trees'
Browse files Browse the repository at this point in the history
The code has been taught to use the duplicated information stored
in the commit-graph file to learn the tree object name for a commit
to avoid opening and parsing the commit object when it makes sense
to do so.

* ds/lazy-load-trees:
  coccinelle: avoid wrong transformation suggestions from commit.cocci
  commit-graph: lazy-load trees for commits
  treewide: replace maybe_tree with accessor methods
  commit: create get_commit_tree() method
  treewide: rename tree to maybe_tree
  • Loading branch information
gitster committed May 23, 2018
2 parents 05682ee + 279ffad commit c89b6e1
Show file tree
Hide file tree
Showing 26 changed files with 152 additions and 66 deletions.
18 changes: 9 additions & 9 deletions blame.c
Original file line number Diff line number Diff line change
Expand Up @@ -551,10 +551,10 @@ static struct blame_origin *find_origin(struct commit *parent,
diff_setup_done(&diff_opts);

if (is_null_oid(&origin->commit->object.oid))
do_diff_cache(&parent->tree->object.oid, &diff_opts);
do_diff_cache(get_commit_tree_oid(parent), &diff_opts);
else
diff_tree_oid(&parent->tree->object.oid,
&origin->commit->tree->object.oid,
diff_tree_oid(get_commit_tree_oid(parent),
get_commit_tree_oid(origin->commit),
"", &diff_opts);
diffcore_std(&diff_opts);

Expand Down Expand Up @@ -620,10 +620,10 @@ static struct blame_origin *find_rename(struct commit *parent,
diff_setup_done(&diff_opts);

if (is_null_oid(&origin->commit->object.oid))
do_diff_cache(&parent->tree->object.oid, &diff_opts);
do_diff_cache(get_commit_tree_oid(parent), &diff_opts);
else
diff_tree_oid(&parent->tree->object.oid,
&origin->commit->tree->object.oid,
diff_tree_oid(get_commit_tree_oid(parent),
get_commit_tree_oid(origin->commit),
"", &diff_opts);
diffcore_std(&diff_opts);

Expand Down Expand Up @@ -1255,10 +1255,10 @@ static void find_copy_in_parent(struct blame_scoreboard *sb,
diff_opts.flags.find_copies_harder = 1;

if (is_null_oid(&target->commit->object.oid))
do_diff_cache(&parent->tree->object.oid, &diff_opts);
do_diff_cache(get_commit_tree_oid(parent), &diff_opts);
else
diff_tree_oid(&parent->tree->object.oid,
&target->commit->tree->object.oid,
diff_tree_oid(get_commit_tree_oid(parent),
get_commit_tree_oid(target->commit),
"", &diff_opts);

if (!diff_opts.flags.find_copies_harder)
Expand Down
18 changes: 12 additions & 6 deletions builtin/checkout.c
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,8 @@ static int merge_working_tree(const struct checkout_opts *opts,

resolve_undo_clear();
if (opts->force) {
ret = reset_tree(new_branch_info->commit->tree, opts, 1, writeout_error);
ret = reset_tree(get_commit_tree(new_branch_info->commit),
opts, 1, writeout_error);
if (ret)
return ret;
} else {
Expand Down Expand Up @@ -570,18 +571,23 @@ static int merge_working_tree(const struct checkout_opts *opts,
o.verbosity = 0;
work = write_tree_from_memory(&o);

ret = reset_tree(new_branch_info->commit->tree, opts, 1,
ret = reset_tree(get_commit_tree(new_branch_info->commit),
opts, 1,
writeout_error);
if (ret)
return ret;
o.ancestor = old_branch_info->name;
o.branch1 = new_branch_info->name;
o.branch2 = "local";
ret = merge_trees(&o, new_branch_info->commit->tree, work,
old_branch_info->commit->tree, &result);
ret = merge_trees(&o,
get_commit_tree(new_branch_info->commit),
work,
get_commit_tree(old_branch_info->commit),
&result);
if (ret < 0)
exit(128);
ret = reset_tree(new_branch_info->commit->tree, opts, 0,
ret = reset_tree(get_commit_tree(new_branch_info->commit),
opts, 0,
writeout_error);
strbuf_release(&o.obuf);
if (ret)
Expand Down Expand Up @@ -1002,7 +1008,7 @@ static int parse_branchname_arg(int argc, const char **argv,
*source_tree = parse_tree_indirect(rev);
} else {
parse_commit_or_die(new_branch_info->commit);
*source_tree = new_branch_info->commit->tree;
*source_tree = get_commit_tree(new_branch_info->commit);
}

if (!*source_tree) /* case (1): want a tree */
Expand Down
2 changes: 1 addition & 1 deletion builtin/diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
if (!obj)
die(_("invalid object '%s' given."), name);
if (obj->type == OBJ_COMMIT)
obj = &((struct commit *)obj)->tree->object;
obj = &get_commit_tree(((struct commit *)obj))->object;

if (obj->type == OBJ_TREE) {
obj->flags |= flags;
Expand Down
6 changes: 3 additions & 3 deletions builtin/fast-export.c
Original file line number Diff line number Diff line change
Expand Up @@ -578,11 +578,11 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
get_object_mark(&commit->parents->item->object) != 0 &&
!full_tree) {
parse_commit_or_die(commit->parents->item);
diff_tree_oid(&commit->parents->item->tree->object.oid,
&commit->tree->object.oid, "", &rev->diffopt);
diff_tree_oid(get_commit_tree_oid(commit->parents->item),
get_commit_tree_oid(commit), "", &rev->diffopt);
}
else
diff_root_tree_oid(&commit->tree->object.oid,
diff_root_tree_oid(get_commit_tree_oid(commit),
"", &rev->diffopt);

/* Export the referenced blobs, and remember the marks. */
Expand Down
4 changes: 2 additions & 2 deletions builtin/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -1067,8 +1067,8 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,

diff_setup_done(&opts);

diff_tree_oid(&origin->tree->object.oid,
&head->tree->object.oid,
diff_tree_oid(get_commit_tree_oid(origin),
get_commit_tree_oid(head),
"", &opts);
diffcore_std(&opts);
diff_flush(&opts);
Expand Down
2 changes: 1 addition & 1 deletion builtin/reflog.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ static int commit_is_complete(struct commit *commit)
for (i = 0; i < found.nr; i++) {
struct commit *c =
(struct commit *)found.objects[i].item;
if (!tree_is_complete(&c->tree->object.oid)) {
if (!tree_is_complete(get_commit_tree_oid(c))) {
is_incomplete = 1;
c->object.flags |= INCOMPLETE;
}
Expand Down
28 changes: 24 additions & 4 deletions commit-graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,6 @@ static struct commit_list **insert_parent_or_die(struct commit_graph *g,

static int fill_commit_in_graph(struct commit *item, struct commit_graph *g, uint32_t pos)
{
struct object_id oid;
uint32_t edge_value;
uint32_t *parent_data_ptr;
uint64_t date_low, date_high;
Expand All @@ -260,8 +259,7 @@ static int fill_commit_in_graph(struct commit *item, struct commit_graph *g, uin
item->object.parsed = 1;
item->graph_pos = pos;

hashcpy(oid.hash, commit_data);
item->tree = lookup_tree(&oid);
item->maybe_tree = NULL;

date_high = get_be32(commit_data + g->hash_len + 8) & 0x3;
date_low = get_be32(commit_data + g->hash_len + 12);
Expand Down Expand Up @@ -320,6 +318,28 @@ int parse_commit_in_graph(struct commit *item)
return 0;
}

static struct tree *load_tree_for_commit(struct commit_graph *g, struct commit *c)
{
struct object_id oid;
const unsigned char *commit_data = g->chunk_commit_data +
GRAPH_DATA_WIDTH * (c->graph_pos);

hashcpy(oid.hash, commit_data);
c->maybe_tree = lookup_tree(&oid);

return c->maybe_tree;
}

struct tree *get_commit_tree_in_graph(const struct commit *c)
{
if (c->maybe_tree)
return c->maybe_tree;
if (c->graph_pos == COMMIT_NOT_FROM_GRAPH)
BUG("get_commit_tree_in_graph called from non-commit-graph commit");

return load_tree_for_commit(commit_graph, (struct commit *)c);
}

static void write_graph_chunk_fanout(struct hashfile *f,
struct commit **commits,
int nr_commits)
Expand Down Expand Up @@ -372,7 +392,7 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
uint32_t packedDate[2];

parse_commit(*list);
hashwrite(f, (*list)->tree->object.oid.hash, hash_len);
hashwrite(f, get_commit_tree_oid(*list)->hash, hash_len);

parent = (*list)->parents;

Expand Down
2 changes: 2 additions & 0 deletions commit-graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ char *get_commit_graph_filename(const char *obj_dir);
*/
int parse_commit_in_graph(struct commit *item);

struct tree *get_commit_tree_in_graph(const struct commit *c);

struct commit_graph {
int graph_fd;

Expand Down
18 changes: 17 additions & 1 deletion commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,22 @@ void free_commit_buffer(struct commit *commit)
}
}

struct tree *get_commit_tree(const struct commit *commit)
{
if (commit->maybe_tree || !commit->object.parsed)
return commit->maybe_tree;

if (commit->graph_pos == COMMIT_NOT_FROM_GRAPH)
BUG("commit has NULL tree, but was not loaded from commit-graph");

return get_commit_tree_in_graph(commit);
}

struct object_id *get_commit_tree_oid(const struct commit *commit)
{
return &get_commit_tree(commit)->object.oid;
}

const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
{
struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
Expand Down Expand Up @@ -335,7 +351,7 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s
if (get_sha1_hex(bufptr + 5, parent.hash) < 0)
return error("bad tree pointer in commit %s",
oid_to_hex(&item->object.oid));
item->tree = lookup_tree(&parent);
item->maybe_tree = lookup_tree(&parent);
bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
pptr = &item->parents;

Expand Down
11 changes: 10 additions & 1 deletion commit.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ struct commit {
unsigned int index;
timestamp_t date;
struct commit_list *parents;
struct tree *tree;

/*
* If the commit is loaded from the commit-graph file, then this
* member may be NULL. Only access it through get_commit_tree()
* or get_commit_tree_oid().
*/
struct tree *maybe_tree;
uint32_t graph_pos;
};

Expand Down Expand Up @@ -102,6 +108,9 @@ void unuse_commit_buffer(const struct commit *, const void *buffer);
*/
void free_commit_buffer(struct commit *);

struct tree *get_commit_tree(const struct commit *);
struct object_id *get_commit_tree_oid(const struct commit *);

/*
* Disassociate any cached object buffer from the commit, but do not free it.
* The buffer (or NULL, if none) is returned.
Expand Down
28 changes: 28 additions & 0 deletions contrib/coccinelle/commit.cocci
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@@
expression c;
@@
- &c->maybe_tree->object.oid
+ get_commit_tree_oid(c)

@@
expression c;
@@
- c->maybe_tree->object.oid.hash
+ get_commit_tree_oid(c)->hash

// These excluded functions must access c->maybe_tree direcly.
@@
identifier f !~ "^(get_commit_tree|get_commit_tree_in_graph|load_tree_for_commit)$";
expression c;
@@
f(...) {...
- c->maybe_tree
+ get_commit_tree(c)
...}

@@
expression c;
expression s;
@@
- get_commit_tree(c) = s
+ c->maybe_tree = s
8 changes: 5 additions & 3 deletions fsck.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,9 +396,11 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio

name = get_object_name(options, &commit->object);
if (name)
put_object_name(options, &commit->tree->object, "%s:", name);
put_object_name(options, &get_commit_tree(commit)->object,
"%s:", name);

result = options->walk((struct object *)commit->tree, OBJ_TREE, data, options);
result = options->walk((struct object *)get_commit_tree(commit),
OBJ_TREE, data, options);
if (result < 0)
return result;
res = result;
Expand Down Expand Up @@ -772,7 +774,7 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
err = fsck_ident(&buffer, &commit->object, options);
if (err)
return err;
if (!commit->tree) {
if (!get_commit_tree(commit)) {
err = report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", sha1_to_hex(tree_sha1));
if (err)
return err;
Expand Down
2 changes: 1 addition & 1 deletion http-push.c
Original file line number Diff line number Diff line change
Expand Up @@ -1331,7 +1331,7 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock)
int count = 0;

while ((commit = get_revision(revs)) != NULL) {
p = process_tree(commit->tree, p);
p = process_tree(get_commit_tree(commit), p);
commit->object.flags |= LOCAL;
if (!(commit->object.flags & UNINTERESTING))
count += add_send_request(&commit->object, lock);
Expand Down
4 changes: 2 additions & 2 deletions line-log.c
Original file line number Diff line number Diff line change
Expand Up @@ -816,8 +816,8 @@ static void queue_diffs(struct line_log_data *range,
assert(commit);

DIFF_QUEUE_CLEAR(&diff_queued_diff);
diff_tree_oid(parent ? &parent->tree->object.oid : NULL,
&commit->tree->object.oid, "", opt);
diff_tree_oid(parent ? get_commit_tree_oid(parent) : NULL,
get_commit_tree_oid(commit), "", opt);
if (opt->detect_rename) {
filter_diffs_for_paths(range, 1);
if (diff_might_be_rename())
Expand Down
10 changes: 5 additions & 5 deletions list-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ static void mark_edge_parents_uninteresting(struct commit *commit,
struct commit *parent = parents->item;
if (!(parent->object.flags & UNINTERESTING))
continue;
mark_tree_uninteresting(parent->tree);
mark_tree_uninteresting(get_commit_tree(parent));
if (revs->edge_hint && !(parent->object.flags & SHOWN)) {
parent->object.flags |= SHOWN;
show_edge(parent);
Expand All @@ -212,7 +212,7 @@ void mark_edges_uninteresting(struct rev_info *revs, show_edge_fn show_edge)
struct commit *commit = list->item;

if (commit->object.flags & UNINTERESTING) {
mark_tree_uninteresting(commit->tree);
mark_tree_uninteresting(get_commit_tree(commit));
if (revs->edge_hint_aggressive && !(commit->object.flags & SHOWN)) {
commit->object.flags |= SHOWN;
show_edge(commit);
Expand All @@ -227,7 +227,7 @@ void mark_edges_uninteresting(struct rev_info *revs, show_edge_fn show_edge)
struct commit *commit = (struct commit *)obj;
if (obj->type != OBJ_COMMIT || !(obj->flags & UNINTERESTING))
continue;
mark_tree_uninteresting(commit->tree);
mark_tree_uninteresting(get_commit_tree(commit));
if (!(obj->flags & SHOWN)) {
obj->flags |= SHOWN;
show_edge(commit);
Expand Down Expand Up @@ -300,8 +300,8 @@ static void do_traverse(struct rev_info *revs,
* an uninteresting boundary commit may not have its tree
* parsed yet, but we are not going to show them anyway
*/
if (commit->tree)
add_pending_tree(revs, commit->tree);
if (get_commit_tree(commit))
add_pending_tree(revs, get_commit_tree(commit));
show_commit(commit, show_data);

if (revs->tree_blobs_in_commit_order)
Expand Down
6 changes: 3 additions & 3 deletions log-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
return 0;

parse_commit_or_die(commit);
oid = &commit->tree->object.oid;
oid = get_commit_tree_oid(commit);

/* Root commit? */
parents = get_saved_parents(opt, commit);
Expand All @@ -831,7 +831,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
* we merged _in_.
*/
parse_commit_or_die(parents->item);
diff_tree_oid(&parents->item->tree->object.oid,
diff_tree_oid(get_commit_tree_oid(parents->item),
oid, "", &opt->diffopt);
log_tree_diff_flush(opt);
return !opt->loginfo;
Expand All @@ -846,7 +846,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
struct commit *parent = parents->item;

parse_commit_or_die(parent);
diff_tree_oid(&parent->tree->object.oid,
diff_tree_oid(get_commit_tree_oid(parent),
oid, "", &opt->diffopt);
log_tree_diff_flush(opt);

Expand Down
Loading

0 comments on commit c89b6e1

Please sign in to comment.