From: Derrick Stolee <dstolee@xxxxxxxxxxxxx> Signed-off-by: Derrick Stolee <dstolee@xxxxxxxxxxxxx> --- commit-graph.c | 66 ++++++++++++++++++++++++++++++++++++++++++++------ commit-graph.h | 4 +++ 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/commit-graph.c b/commit-graph.c index 7723156964..f790f44a9c 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -371,6 +371,25 @@ static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t g->chunk_oid_lookup, g->hash_len, pos); } +static void load_oid_from_graph(struct commit_graph *g, int pos, struct object_id *oid) +{ + if (!g) + BUG("NULL commit-graph"); + + if (pos < g->num_commits_in_base) { + load_oid_from_graph(g->base_graph, pos, oid); + return; + } + + if (pos >= g->num_commits + g->num_commits_in_base) + BUG("position %d is beyond the scope of this commit-graph (%d local + %d base commits)", + pos, g->num_commits, g->num_commits_in_base); + + pos -= g->num_commits_in_base; + + hashcpy(oid->hash, g->chunk_oid_lookup + g->hash_len * pos); +} + static struct commit_list **insert_parent_or_die(struct repository *r, struct commit_graph *g, uint64_t pos, @@ -379,10 +398,10 @@ static struct commit_list **insert_parent_or_die(struct repository *r, struct commit *c; struct object_id oid; - if (pos >= g->num_commits) + if (pos >= g->num_commits + g->num_commits_in_base) die("invalid parent position %"PRIu64, pos); - hashcpy(oid.hash, g->chunk_oid_lookup + g->hash_len * pos); + load_oid_from_graph(g, pos, &oid); c = lookup_commit(r, &oid); if (!c) die(_("could not find commit %s"), oid_to_hex(&oid)); @@ -393,7 +412,7 @@ static struct commit_list **insert_parent_or_die(struct repository *r, static void fill_commit_graph_info(struct commit *item, struct commit_graph *g, uint32_t pos) { const unsigned char *commit_data = g->chunk_commit_data + GRAPH_DATA_WIDTH * pos; - item->graph_pos = pos; + item->graph_pos = pos + g->num_commits_in_base; item->generation = get_be32(commit_data + g->hash_len + 8) >> 2; } @@ -405,10 +424,25 @@ static int fill_commit_in_graph(struct repository *r, uint32_t *parent_data_ptr; uint64_t date_low, date_high; struct commit_list **pptr; - const unsigned char *commit_data = g->chunk_commit_data + (g->hash_len + 16) * pos; + const unsigned char *commit_data; - item->object.parsed = 1; + if (pos < g->num_commits_in_base) + return fill_commit_in_graph(r, item, g->base_graph, pos); + + if (pos >= g->num_commits + g->num_commits_in_base) + BUG("position %d is beyond the scope of this commit-graph (%d local + %d base commits)", + pos, g->num_commits, g->num_commits_in_base); + + /* + * Store the "full" position, but then use the + * "local" position for the rest of the calculation. + */ item->graph_pos = pos; + pos -= g->num_commits_in_base; + + commit_data = g->chunk_commit_data + (g->hash_len + 16) * pos; + + item->object.parsed = 1; item->maybe_tree = NULL; @@ -452,7 +486,18 @@ static int find_commit_in_graph(struct commit *item, struct commit_graph *g, uin *pos = item->graph_pos; return 1; } else { - return bsearch_graph(g, &(item->object.oid), pos); + struct commit_graph *cur_g = g; + uint32_t pos_in_g; + + while (cur_g && !bsearch_graph(cur_g, &(item->object.oid), &pos_in_g)) + cur_g = cur_g->base_graph; + + if (cur_g) { + *pos = pos_in_g + cur_g->num_commits_in_base; + return 1; + } + + return 0; } } @@ -492,8 +537,13 @@ static struct tree *load_tree_for_commit(struct repository *r, struct commit *c) { struct object_id oid; - const unsigned char *commit_data = g->chunk_commit_data + - GRAPH_DATA_WIDTH * (c->graph_pos); + const unsigned char *commit_data; + + if (c->graph_pos < g->num_commits_in_base) + return load_tree_for_commit(r, g->base_graph, c); + + commit_data = g->chunk_commit_data + + GRAPH_DATA_WIDTH * (c->graph_pos - g->num_commits_in_base); hashcpy(oid.hash, commit_data); c->maybe_tree = lookup_tree(r, &oid); diff --git a/commit-graph.h b/commit-graph.h index 70f4caf0c7..170920720d 100644 --- a/commit-graph.h +++ b/commit-graph.h @@ -48,10 +48,14 @@ struct commit_graph { uint32_t num_commits; struct object_id oid; + uint32_t num_commits_in_base; + struct commit_graph *base_graph; + const uint32_t *chunk_oid_fanout; const unsigned char *chunk_oid_lookup; const unsigned char *chunk_commit_data; const unsigned char *chunk_extra_edges; + const unsigned char *chunk_base_graph; }; struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st); -- gitgitgadget