summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--commit-graph.c112
1 files changed, 106 insertions, 6 deletions
diff --git a/commit-graph.c b/commit-graph.c
index 96b07a674e..f7dfc6aecd 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -45,6 +45,19 @@ char *get_commit_graph_filename(const char *obj_dir)
return xstrfmt("%s/info/commit-graph", obj_dir);
}
+static char *get_split_graph_filename(const char *obj_dir,
+ const char *oid_hex)
+{
+ return xstrfmt("%s/info/commit-graphs/graph-%s.graph",
+ obj_dir,
+ oid_hex);
+}
+
+static char *get_chain_filename(const char *obj_dir)
+{
+ return xstrfmt("%s/info/commit-graphs/commit-graph-chain", obj_dir);
+}
+
static uint8_t oid_version(void)
{
return 1;
@@ -286,18 +299,105 @@ static struct commit_graph *load_commit_graph_one(const char *graph_file)
return load_commit_graph_one_fd_st(fd, &st);
}
+static struct commit_graph *load_commit_graph_v1(struct repository *r, const char *obj_dir)
+{
+ char *graph_name = get_commit_graph_filename(obj_dir);
+ struct commit_graph *g = load_commit_graph_one(graph_name);
+ free(graph_name);
+
+ return g;
+}
+
+static int add_graph_to_chain(struct commit_graph *g,
+ struct commit_graph *chain,
+ struct object_id *oids,
+ int n)
+{
+ struct commit_graph *cur_g = chain;
+
+ while (n) {
+ n--;
+ cur_g = cur_g->base_graph;
+ }
+
+ g->base_graph = chain;
+
+ if (chain)
+ g->num_commits_in_base = chain->num_commits + chain->num_commits_in_base;
+
+ return 1;
+}
+
+static struct commit_graph *load_commit_graph_chain(struct repository *r, const char *obj_dir)
+{
+ struct commit_graph *graph_chain = NULL;
+ struct strbuf line = STRBUF_INIT;
+ struct stat st;
+ struct object_id *oids;
+ int i = 0, valid = 1, count;
+ char *chain_name = get_chain_filename(obj_dir);
+ FILE *fp;
+ int stat_res;
+
+ fp = fopen(chain_name, "r");
+ stat_res = stat(chain_name, &st);
+ free(chain_name);
+
+ if (!fp ||
+ stat_res ||
+ st.st_size <= the_hash_algo->hexsz)
+ return NULL;
+
+ count = st.st_size / (the_hash_algo->hexsz + 1);
+ oids = xcalloc(count, sizeof(struct object_id));
+
+ for (i = 0; i < count && valid; i++) {
+ char *graph_name;
+ struct commit_graph *g;
+
+ if (strbuf_getline_lf(&line, fp) == EOF)
+ break;
+
+ if (get_oid_hex(line.buf, &oids[i])) {
+ warning(_("invalid commit-graph chain: line '%s' not a hash"),
+ line.buf);
+ valid = 0;
+ break;
+ }
+
+ graph_name = get_split_graph_filename(obj_dir, line.buf);
+ g = load_commit_graph_one(graph_name);
+ free(graph_name);
+
+ if (g && add_graph_to_chain(g, graph_chain, oids, i))
+ graph_chain = g;
+ else
+ valid = 0;
+ }
+
+ free(oids);
+ fclose(fp);
+
+ return graph_chain;
+}
+
+static struct commit_graph *read_commit_graph_one(struct repository *r, const char *obj_dir)
+{
+ struct commit_graph *g = load_commit_graph_v1(r, obj_dir);
+
+ if (!g)
+ g = load_commit_graph_chain(r, obj_dir);
+
+ return g;
+}
+
static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
{
- char *graph_name;
if (r->objects->commit_graph)
return;
- graph_name = get_commit_graph_filename(obj_dir);
- r->objects->commit_graph =
- load_commit_graph_one(graph_name);
-
- FREE_AND_NULL(graph_name);
+ r->objects->commit_graph = read_commit_graph_one(r, obj_dir);
}
/*