From 7cd9bdf45afaed60d85cae35dbcfe8570fedeb20 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 4 Sep 2025 14:50:00 +0200 Subject: [PATCH] odb: move commit-graph into the object sources 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 Signed-off-by: Junio C Hamano --- 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 @@ cleanup: 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)