From e3fb6c1407823ff6fd42a5c65b88c0d1b9ce0d5b Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 4 Sep 2025 08:20:47 +0200 Subject: [PATCH 1/7] odb: track commit graphs via object source Hi, commit graphs are currently stored on the object database level. This doesn't really make much sense conceptually, given that commit graphs are specific to one object source. Furthermore, with the upcoming pluggable object database effort, an object source's backend may not evene have a commit graph in the first place but store that information in a different format altogether. This patch series prepares for that by moving the commit graph from `struct object_database` into `struct odb_source`. Thanks! Patrick --- b4-submit-tracking --- # This section is used internally by b4 prep for tracking purposes. { "series": { "revision": 1, "change-id": "20250904-b4-pks-commit-graph-via-source-b4e1a1edd214", "prefixes": [] } } -- GitLab From e0fec04bb1c2eb2a844512604410bfd5ba9ee401 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 18 Aug 2025 08:28:08 +0200 Subject: [PATCH 2/7] blame: drop explicit check for commit graph Our blaming subsystem knows to use bloom filters from commit graphs to speed up the whole computation. The setup of this happens in `setup_blame_bloom_data()`, where we first verify that we even have a commit graph in the first place. This check is redundant though, as we call `get_bloom_filter_settings()` immediately afterwards which, which already knows to return a `NULL` pointer in case we don't have a commit graph. Drop the redundant check. Signed-off-by: Patrick Steinhardt --- blame.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/blame.c b/blame.c index f1c0670144b..cb0b0834230 100644 --- a/blame.c +++ b/blame.c @@ -2909,9 +2909,6 @@ void setup_blame_bloom_data(struct blame_scoreboard *sb) struct blame_bloom_data *bd; struct bloom_filter_settings *bs; - if (!sb->repo->objects->commit_graph) - return; - bs = get_bloom_filter_settings(sb->repo); if (!bs) return; -- GitLab From 169b90aee04acd83b8eb6cff816fbc6e2c486761 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 18 Aug 2025 09:17:30 +0200 Subject: [PATCH 3/7] revision: drop explicit check for commit graph When filtering down revisions by paths we know to use bloom filters from the commit graph, if we have any. The entry point for this is in `check_maybe_different_in_bloom_filter()`, where we first verify that: - We do have a commit graph. - That the commit is contained therein by checking that we have a proper generation number. - And that the graph contains a bloom filter. The first check is somewhat redundant though: if we don't have a commit graph, then the second check would already tell us that we don't have a generation number for the specific commit. In theory this could be seen as a performance optimization to short-circuit for scenarios where there is no commit graph. But in practice this shouldn't matter: if there is no commit graph, then the commit graph data slab would also be unpopulated and thus a lookup of the commit should happen in constant time. Drop the unnecessary check. Signed-off-by: Patrick Steinhardt --- revision.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/revision.c b/revision.c index 6ba8f670542..6018f30a99e 100644 --- a/revision.c +++ b/revision.c @@ -774,9 +774,6 @@ static int check_maybe_different_in_bloom_filter(struct rev_info *revs, struct bloom_filter *filter; int result = 0; - if (!revs->repo->objects->commit_graph) - return -1; - if (commit_graph_generation(commit) == GENERATION_NUMBER_INFINITY) return -1; -- GitLab From 1a81e108b46926501e543ab67bf10181522adaef Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 18 Aug 2025 08:26:06 +0200 Subject: [PATCH 4/7] commit-graph: return the prepared commit graph from `prepare_commit_graph()` When making use of commit graphs, one needs to first prepare them by calling `prepare_commit_graph()`. Once that function was called and the commit graph was prepared successfully, the caller is now expected to access the graph directly via `struct object_database::commit_graph`. In a subsequent change, we're going to move the commit graph pointer from `struct object_database` into `struct odb_source`. With this change, semantics will change so that we use the commit graph of the first source that has one. Consequently, all callers that currently deference the `commit_graph` pointer would now have to loop around the list of sources to find the commit graph. This would become quite unwieldy. So instead of shifting the burden onto such callers, adapt `prepare_commit_graph()` to return the prepared commit graph, if any. Like this, callers are expected to call that function and then use the returned commit graph. Signed-off-by: Patrick Steinhardt --- commit-graph.c | 82 ++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 50 deletions(-) diff --git a/commit-graph.c b/commit-graph.c index 3cd9e73e2aa..62260a2026d 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -735,7 +735,7 @@ struct commit_graph *read_commit_graph_one(struct odb_source *source) * On the first invocation, this function attempts to load the commit * graph if the repository is configured to have one. */ -static int prepare_commit_graph(struct repository *r) +static struct commit_graph *prepare_commit_graph(struct repository *r) { struct odb_source *source; @@ -747,10 +747,10 @@ static int prepare_commit_graph(struct repository *r) * we want to disable even an already-loaded graph file. */ if (!r->gitdir || r->commit_graph_disabled) - return 0; + return NULL; if (r->objects->commit_graph_attempted) - return !!r->objects->commit_graph; + return r->objects->commit_graph; r->objects->commit_graph_attempted = 1; prepare_repo_settings(r); @@ -763,10 +763,10 @@ static int prepare_commit_graph(struct repository *r) * so that commit graph loading is not attempted again for this * repository.) */ - return 0; + return NULL; if (!commit_graph_compatible(r)) - return 0; + return NULL; odb_prepare_alternates(r->objects); for (source = r->objects->sources; source; source = source->next) { @@ -775,20 +775,17 @@ static int prepare_commit_graph(struct repository *r) break; } - return !!r->objects->commit_graph; + return r->objects->commit_graph; } int generation_numbers_enabled(struct repository *r) { uint32_t first_generation; struct commit_graph *g; - if (!prepare_commit_graph(r)) - return 0; - g = r->objects->commit_graph; - - if (!g->num_commits) - return 0; + g = prepare_commit_graph(r); + if (!g || !g->num_commits) + return 0; first_generation = get_be32(g->chunk_commit_data + g->hash_algo->rawsz + 8) >> 2; @@ -799,12 +796,9 @@ int generation_numbers_enabled(struct repository *r) int corrected_commit_dates_enabled(struct repository *r) { struct commit_graph *g; - if (!prepare_commit_graph(r)) - return 0; - g = r->objects->commit_graph; - - if (!g->num_commits) + g = prepare_commit_graph(r); + if (!g || !g->num_commits) return 0; return g->read_generation_data; @@ -1012,23 +1006,26 @@ static int find_commit_pos_in_graph(struct commit *item, struct commit_graph *g, int repo_find_commit_pos_in_graph(struct repository *r, struct commit *c, uint32_t *pos) { - if (!prepare_commit_graph(r)) + struct commit_graph *g = prepare_commit_graph(r); + if (!g) return 0; - return find_commit_pos_in_graph(c, r->objects->commit_graph, pos); + return find_commit_pos_in_graph(c, g, pos); } struct commit *lookup_commit_in_graph(struct repository *repo, const struct object_id *id) { static int commit_graph_paranoia = -1; + struct commit_graph *g; struct commit *commit; uint32_t pos; if (commit_graph_paranoia == -1) commit_graph_paranoia = git_env_bool(GIT_COMMIT_GRAPH_PARANOIA, 0); - if (!prepare_commit_graph(repo)) + g = prepare_commit_graph(repo); + if (!g) return NULL; - if (!search_commit_pos_in_graph(id, repo->objects->commit_graph, &pos)) + if (!search_commit_pos_in_graph(id, g, &pos)) return NULL; if (commit_graph_paranoia && !odb_has_object(repo->objects, id, 0)) return NULL; @@ -1039,7 +1036,7 @@ struct commit *lookup_commit_in_graph(struct repository *repo, const struct obje if (commit->object.parsed) return commit; - if (!fill_commit_in_graph(commit, repo->objects->commit_graph, pos)) + if (!fill_commit_in_graph(commit, g, pos)) return NULL; return commit; @@ -1062,6 +1059,7 @@ static int parse_commit_in_graph_one(struct commit_graph *g, int parse_commit_in_graph(struct repository *r, struct commit *item) { static int checked_env = 0; + struct commit_graph *g; if (!checked_env && git_env_bool(GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE, 0)) @@ -1069,9 +1067,10 @@ int parse_commit_in_graph(struct repository *r, struct commit *item) GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE); checked_env = 1; - if (!prepare_commit_graph(r)) + g = prepare_commit_graph(r); + if (!g) return 0; - return parse_commit_in_graph_one(r->objects->commit_graph, item); + return parse_commit_in_graph_one(g, item); } void load_commit_graph_info(struct repository *r, struct commit *item) @@ -2519,6 +2518,7 @@ int write_commit_graph(struct odb_source *source, int replace = 0; struct bloom_filter_settings bloom_settings = DEFAULT_BLOOM_FILTER_SETTINGS; struct topo_level_slab topo_levels; + struct commit_graph *g; prepare_repo_settings(r); if (!r->settings.core_commit_graph) { @@ -2547,23 +2547,13 @@ int write_commit_graph(struct odb_source *source, init_topo_level_slab(&topo_levels); ctx.topo_levels = &topo_levels; - prepare_commit_graph(ctx.r); - if (ctx.r->objects->commit_graph) { - struct commit_graph *g = ctx.r->objects->commit_graph; - - while (g) { - g->topo_levels = &topo_levels; - g = g->base_graph; - } - } + g = prepare_commit_graph(ctx.r); + for (struct commit_graph *chain = g; chain; chain = chain->base_graph) + g->topo_levels = &topo_levels; if (flags & COMMIT_GRAPH_WRITE_BLOOM_FILTERS) ctx.changed_paths = 1; if (!(flags & COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS)) { - struct commit_graph *g; - - g = ctx.r->objects->commit_graph; - /* We have changed-paths already. Keep them in the next graph */ if (g && g->bloom_filter_settings) { ctx.changed_paths = 1; @@ -2580,22 +2570,15 @@ int write_commit_graph(struct odb_source *source, bloom_settings.hash_version = bloom_settings.hash_version == 2 ? 2 : 1; if (ctx.split) { - struct commit_graph *g = ctx.r->objects->commit_graph; - - while (g) { + for (struct commit_graph *chain = g; chain; chain = chain->base_graph) ctx.num_commit_graphs_before++; - g = g->base_graph; - } if (ctx.num_commit_graphs_before) { ALLOC_ARRAY(ctx.commit_graph_filenames_before, ctx.num_commit_graphs_before); i = ctx.num_commit_graphs_before; - g = ctx.r->objects->commit_graph; - while (g) { - ctx.commit_graph_filenames_before[--i] = xstrdup(g->filename); - g = g->base_graph; - } + for (struct commit_graph *chain = g; chain; chain = chain->base_graph) + ctx.commit_graph_filenames_before[--i] = xstrdup(chain->filename); } if (ctx.opts) @@ -2604,8 +2587,7 @@ int write_commit_graph(struct odb_source *source, ctx.approx_nr_objects = repo_approximate_object_count(r); - if (ctx.append && ctx.r->objects->commit_graph) { - struct commit_graph *g = ctx.r->objects->commit_graph; + if (ctx.append && g) { for (i = 0; i < g->num_commits; i++) { struct object_id oid; oidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i), @@ -2651,7 +2633,7 @@ int write_commit_graph(struct odb_source *source, } else ctx.num_commit_graphs_after = 1; - ctx.trust_generation_numbers = validate_mixed_generation_chain(ctx.r->objects->commit_graph); + ctx.trust_generation_numbers = validate_mixed_generation_chain(g); compute_topological_levels(&ctx); if (ctx.write_generation_data) -- GitLab From a54a413c43cfd57c00e99c9aff9280a01b39d4d5 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 18 Aug 2025 09:10:19 +0200 Subject: [PATCH 5/7] commit-graph: return commit graph from `repo_find_commit_pos_in_graph()` The function `repo_find_commit_pos_in_graph()` takes a commit as input and tries to figure out whether the given repository has a commit graph that contains that specific commit. If so, it returns the corresponding position of that commit inside the graph. Right now though we only return the position, but not the actual graph that the commit has been found in. This is sensible as repositories always have the graph in `struct repository::objects::commit_graph`. Consequently, the caller always knows where to find it. But in a subsequent change we're going to move the graph into the object sources. This would require callers of the function to loop through all sources to find the relevant commit graph. Refactor the code so that we instead return the commit-graph that the commit has been found with. Signed-off-by: Patrick Steinhardt --- bloom.c | 8 +++++--- commit-graph.c | 18 ++++++++++++------ commit-graph.h | 12 ++++++------ 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/bloom.c b/bloom.c index b86015f6d1b..2d7b951e5bf 100644 --- a/bloom.c +++ b/bloom.c @@ -452,10 +452,12 @@ struct bloom_filter *get_or_compute_bloom_filter(struct repository *r, filter = bloom_filter_slab_at(&bloom_filters, c); if (!filter->data) { + struct commit_graph *g; uint32_t graph_pos; - if (repo_find_commit_pos_in_graph(r, c, &graph_pos)) - load_bloom_filter_from_graph(r->objects->commit_graph, - filter, graph_pos); + + g = repo_find_commit_pos_in_graph(r, c, &graph_pos); + if (g) + load_bloom_filter_from_graph(g, filter, graph_pos); } if (filter->data && filter->len) { diff --git a/commit-graph.c b/commit-graph.c index 62260a2026d..16dfe582295 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -1003,13 +1003,16 @@ static int find_commit_pos_in_graph(struct commit *item, struct commit_graph *g, } } -int repo_find_commit_pos_in_graph(struct repository *r, struct commit *c, - uint32_t *pos) +struct commit_graph *repo_find_commit_pos_in_graph(struct repository *r, + struct commit *c, + uint32_t *pos) { struct commit_graph *g = prepare_commit_graph(r); if (!g) - return 0; - return find_commit_pos_in_graph(c, g, pos); + return NULL; + if (!find_commit_pos_in_graph(c, g, pos)) + return NULL; + return g; } struct commit *lookup_commit_in_graph(struct repository *repo, const struct object_id *id) @@ -1075,9 +1078,12 @@ int parse_commit_in_graph(struct repository *r, struct commit *item) void load_commit_graph_info(struct repository *r, struct commit *item) { + struct commit_graph *g; uint32_t pos; - if (repo_find_commit_pos_in_graph(r, item, &pos)) - fill_commit_graph_info(item, r->objects->commit_graph, pos); + + g = repo_find_commit_pos_in_graph(r, item, &pos); + if (g) + fill_commit_graph_info(item, g, pos); } static struct tree *load_tree_for_commit(struct commit_graph *g, diff --git a/commit-graph.h b/commit-graph.h index 4899b54ef88..f6a54336415 100644 --- a/commit-graph.h +++ b/commit-graph.h @@ -48,10 +48,9 @@ int open_commit_graph_chain(const char *chain_file, int *fd, struct stat *st, int parse_commit_in_graph(struct repository *r, struct commit *item); /* - * Fills `*pos` with the graph position of `c`, and returns 1 if `c` is - * found in the commit-graph belonging to `r`, or 0 otherwise. - * Initializes the commit-graph belonging to `r` if it hasn't been - * already. + * Fills `*pos` with the graph position of `c`, and returns the graph `c` is + * found in, or NULL otherwise. Initializes the commit-graphs belonging to + * `r` if it hasn't been already. * * Note: this is a low-level helper that does not alter any slab data * associated with `c`. Useful in circumstances where the slab data is @@ -59,8 +58,9 @@ int parse_commit_in_graph(struct repository *r, struct commit *item); * * In most cases, callers should use `parse_commit_in_graph()` instead. */ -int repo_find_commit_pos_in_graph(struct repository *r, struct commit *c, - uint32_t *pos); +struct commit_graph *repo_find_commit_pos_in_graph(struct repository *r, + struct commit *c, + uint32_t *pos); /* * Look up the given commit ID in the commit-graph. This will only return a -- GitLab From b99ea07530e68eac622aa63b47358a978b0b10f9 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 4 Sep 2025 06:39:28 +0200 Subject: [PATCH 6/7] commit-graph: pass graphs that are to be merged as parameter When determining whether or not we want to merge a commit graph chain we retrieve the graph that is to be merged via the context's repository. With an upcoming change though it will become a bit more complex to figure out the commit graph, which would lead to code duplication. Prepare for this change by passing the graph that is to be merged as a parameter. Signed-off-by: Patrick Steinhardt --- commit-graph.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/commit-graph.c b/commit-graph.c index 16dfe582295..0e25b140766 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -2226,7 +2226,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx) return 0; } -static void split_graph_merge_strategy(struct write_commit_graph_context *ctx) +static void split_graph_merge_strategy(struct write_commit_graph_context *ctx, + struct commit_graph *graph_to_merge) { struct commit_graph *g; uint32_t num_commits; @@ -2245,7 +2246,7 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx) flags = ctx->opts->split_flags; } - g = ctx->r->objects->commit_graph; + g = graph_to_merge; num_commits = ctx->commits.nr; if (flags == COMMIT_GRAPH_SPLIT_REPLACE) ctx->num_commit_graphs_after = 1; @@ -2297,7 +2298,7 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx) ctx->commit_graph_filenames_after[i] = xstrdup(ctx->commit_graph_filenames_before[i]); i = ctx->num_commit_graphs_before - 1; - g = ctx->r->objects->commit_graph; + g = graph_to_merge; while (g) { if (i < ctx->num_commit_graphs_after) @@ -2395,9 +2396,9 @@ static void sort_and_scan_merged_commits(struct write_commit_graph_context *ctx) stop_progress(&ctx->progress); } -static void merge_commit_graphs(struct write_commit_graph_context *ctx) +static void merge_commit_graphs(struct write_commit_graph_context *ctx, + struct commit_graph *g) { - struct commit_graph *g = ctx->r->objects->commit_graph; uint32_t current_graph_number = ctx->num_commit_graphs_before; while (g && current_graph_number >= ctx->num_commit_graphs_after) { @@ -2632,12 +2633,13 @@ int write_commit_graph(struct odb_source *source, goto cleanup; if (ctx.split) { - split_graph_merge_strategy(&ctx); + split_graph_merge_strategy(&ctx, g); if (!replace) - merge_commit_graphs(&ctx); - } else + merge_commit_graphs(&ctx, g); + } else { ctx.num_commit_graphs_after = 1; + } ctx.trust_generation_numbers = validate_mixed_generation_chain(g); -- GitLab From 703ff7221d49af49115223953086721eb70a19d1 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 4 Sep 2025 06:39:35 +0200 Subject: [PATCH 7/7] 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 --- 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 0e25b140766..9929c1ed875 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 f6a54336415..33cb6a75774 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 2a92a018c42..fdcc6849a8c 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 3dfc66d75a3..a4835db6855 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 5d73932f50c..5d3a25816f3 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) -- GitLab