Commit graphs are inherently tied to one specific object source. Furthermore, with the upcoming pluggable object sources, it is not even guaranteed that an object source may even have a commit graph as these are specific to the actual on-disk data format. Prepare for this future by moving the commit-graph pointer from `struct object_database` to `struct odb_source`. Eventually, this will allow us to make commit graphs an implementation detail of an object source's backend. Signed-off-by: Patrick Steinhardt <ps@xxxxxx> --- commit-graph.c | 65 +++++++++++++++++++++++++++++++++++++++++----------------- commit-graph.h | 2 +- odb.c | 9 ++++---- odb.h | 6 +++--- packfile.c | 3 +-- 5 files changed, 56 insertions(+), 29 deletions(-) diff --git a/commit-graph.c b/commit-graph.c index 0e25b14076..9929c1ed87 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -721,11 +721,15 @@ static struct commit_graph *load_commit_graph_chain(struct odb_source *source) struct commit_graph *read_commit_graph_one(struct odb_source *source) { - struct commit_graph *g = load_commit_graph_v1(source); + struct commit_graph *g; + + if (source->commit_graph_attempted) + return NULL; + source->commit_graph_attempted = true; + g = load_commit_graph_v1(source); if (!g) g = load_commit_graph_chain(source); - return g; } @@ -737,6 +741,7 @@ struct commit_graph *read_commit_graph_one(struct odb_source *source) */ static struct commit_graph *prepare_commit_graph(struct repository *r) { + bool all_attempted = true; struct odb_source *source; /* @@ -749,9 +754,19 @@ static struct commit_graph *prepare_commit_graph(struct repository *r) if (!r->gitdir || r->commit_graph_disabled) return NULL; - if (r->objects->commit_graph_attempted) - return r->objects->commit_graph; - r->objects->commit_graph_attempted = 1; + odb_prepare_alternates(r->objects); + for (source = r->objects->sources; source; source = source->next) { + all_attempted &= source->commit_graph_attempted; + if (source->commit_graph) + return source->commit_graph; + } + + /* + * There is no point in re-trying to load commit graphs if we already + * tried loading all of them beforehand. + */ + if (all_attempted) + return NULL; prepare_repo_settings(r); @@ -768,14 +783,16 @@ static struct commit_graph *prepare_commit_graph(struct repository *r) if (!commit_graph_compatible(r)) return NULL; - odb_prepare_alternates(r->objects); for (source = r->objects->sources; source; source = source->next) { - r->objects->commit_graph = read_commit_graph_one(source); - if (r->objects->commit_graph) - break; + if (source->commit_graph_attempted) + continue; + + source->commit_graph = read_commit_graph_one(source); + if (source->commit_graph) + return source->commit_graph; } - return r->objects->commit_graph; + return NULL; } int generation_numbers_enabled(struct repository *r) @@ -806,7 +823,7 @@ int corrected_commit_dates_enabled(struct repository *r) struct bloom_filter_settings *get_bloom_filter_settings(struct repository *r) { - struct commit_graph *g = r->objects->commit_graph; + struct commit_graph *g = prepare_commit_graph(r); while (g) { if (g->bloom_filter_settings) return g->bloom_filter_settings; @@ -815,15 +832,16 @@ struct bloom_filter_settings *get_bloom_filter_settings(struct repository *r) return NULL; } -void close_commit_graph(struct object_database *o) +void close_commit_graph(struct odb_source *source) { - if (!o->commit_graph) + if (!source->commit_graph) return; clear_commit_graph_data_slab(&commit_graph_data_slab); deinit_bloom_filters(); - free_commit_graph(o->commit_graph); - o->commit_graph = NULL; + free_commit_graph(source->commit_graph); + source->commit_graph = NULL; + source->commit_graph_attempted = 0; } static int bsearch_graph(struct commit_graph *g, const struct object_id *oid, uint32_t *pos) @@ -1119,7 +1137,15 @@ static struct tree *get_commit_tree_in_graph_one(struct commit_graph *g, struct tree *get_commit_tree_in_graph(struct repository *r, const struct commit *c) { - return get_commit_tree_in_graph_one(r->objects->commit_graph, c); + struct odb_source *source; + + for (source = r->objects->sources; source; source = source->next) { + if (!source->commit_graph) + continue; + return get_commit_tree_in_graph_one(source->commit_graph, c); + } + + return NULL; } struct packed_commit_list { @@ -2165,7 +2191,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx) ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 2] = new_base_hash; } - close_commit_graph(ctx->r->objects); + for (struct odb_source *s = ctx->r->objects->sources; s; s = s->next) + close_commit_graph(s); finalize_hashfile(f, file_hash, FSYNC_COMPONENT_COMMIT_GRAPH, CSUM_HASH_IN_STREAM | CSUM_FSYNC); free_chunkfile(cf); @@ -2667,8 +2694,8 @@ int write_commit_graph(struct odb_source *source, oid_array_clear(&ctx.oids); clear_topo_level_slab(&topo_levels); - if (ctx.r->objects->commit_graph) { - struct commit_graph *g = ctx.r->objects->commit_graph; + if (source->commit_graph) { + struct commit_graph *g = source->commit_graph; while (g) { g->topo_levels = NULL; diff --git a/commit-graph.h b/commit-graph.h index f6a5433641..33cb6a7577 100644 --- a/commit-graph.h +++ b/commit-graph.h @@ -185,7 +185,7 @@ int write_commit_graph(struct odb_source *source, int verify_commit_graph(struct commit_graph *g, int flags); -void close_commit_graph(struct object_database *); +void close_commit_graph(struct odb_source *); void free_commit_graph(struct commit_graph *); /* diff --git a/odb.c b/odb.c index 2a92a018c4..fdcc6849a8 100644 --- a/odb.c +++ b/odb.c @@ -363,6 +363,11 @@ static void free_object_directory(struct odb_source *source) free(source->path); odb_clear_loose_cache(source); loose_object_map_clear(&source->loose_map); + + free_commit_graph(source->commit_graph); + source->commit_graph = NULL; + source->commit_graph_attempted = 0; + free(source); } @@ -1023,10 +1028,6 @@ void odb_clear(struct object_database *o) oidmap_clear(&o->replace_map, 1); pthread_mutex_destroy(&o->replace_mutex); - free_commit_graph(o->commit_graph); - o->commit_graph = NULL; - o->commit_graph_attempted = 0; - free_object_directories(o); o->sources_tail = NULL; o->loaded_alternates = 0; diff --git a/odb.h b/odb.h index 3dfc66d75a..a4835db685 100644 --- a/odb.h +++ b/odb.h @@ -63,6 +63,9 @@ struct odb_source { */ struct multi_pack_index *midx; + struct commit_graph *commit_graph; + bool commit_graph_attempted; /* if loading has been attempted */ + /* * This is a temporary object store created by the tmp_objdir * facility. Disable ref updates since the objects in the store @@ -120,9 +123,6 @@ struct object_database { unsigned replace_map_initialized : 1; pthread_mutex_t replace_mutex; /* protect object replace functions */ - struct commit_graph *commit_graph; - unsigned commit_graph_attempted : 1; /* if loading has been attempted */ - /* * private data * diff --git a/packfile.c b/packfile.c index 5d73932f50..5d3a25816f 100644 --- a/packfile.c +++ b/packfile.c @@ -374,9 +374,8 @@ void close_object_store(struct object_database *o) if (source->midx) close_midx(source->midx); source->midx = NULL; + close_commit_graph(source); } - - close_commit_graph(o); } void unlink_pack_path(const char *pack_name, int force_delete) -- 2.51.0.417.g1ba7204a04.dirty