]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'ds/commit-graph-genno-fix'
authorJunio C Hamano <gitster@pobox.com>
Thu, 18 Feb 2021 01:21:40 +0000 (17:21 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 18 Feb 2021 01:21:40 +0000 (17:21 -0800)
Fix incremental update of commit-graph file around corrected commit
date data.

* ds/commit-graph-genno-fix:
  commit-graph: prepare commit graph
  commit-graph: be extra careful about mixed generations
  commit-graph: compute generations separately
  commit-graph: validate layers for generation data
  commit-graph: always parse before commit_graph_data_at()
  commit-graph: use repo_parse_commit

commit-graph.c
commit.h
t/t5318-commit-graph.sh

index 36e481c67e7b9fed449193ff2a868144572bd80f..f70886c2d3d5dce59646253892e0c0adcaf5657c 100644 (file)
@@ -614,19 +614,29 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
        return graph_chain;
 }
 
-static void validate_mixed_generation_chain(struct commit_graph *g)
+/*
+ * returns 1 if and only if all graphs in the chain have
+ * corrected commit dates stored in the generation_data chunk.
+ */
+static int validate_mixed_generation_chain(struct commit_graph *g)
 {
-       int read_generation_data;
+       int read_generation_data = 1;
+       struct commit_graph *p = g;
 
-       if (!g)
-               return;
+       while (read_generation_data && p) {
+               read_generation_data = p->read_generation_data;
+               p = p->base_graph;
+       }
 
-       read_generation_data = !!g->chunk_generation_data;
+       if (read_generation_data)
+               return 1;
 
        while (g) {
-               g->read_generation_data = read_generation_data;
+               g->read_generation_data = 0;
                g = g->base_graph;
        }
+
+       return 0;
 }
 
 struct commit_graph *read_commit_graph_one(struct repository *r,
@@ -1026,7 +1036,8 @@ struct write_commit_graph_context {
                 split:1,
                 changed_paths:1,
                 order_by_pack:1,
-                write_generation_data:1;
+                write_generation_data:1,
+                trust_generation_numbers:1;
 
        struct topo_level_slab *topo_levels;
        const struct commit_graph_opts *opts;
@@ -1098,7 +1109,7 @@ static int write_graph_chunk_data(struct hashfile *f,
                uint32_t packedDate[2];
                display_progress(ctx->progress, ++ctx->progress_cnt);
 
-               if (parse_commit_no_graph(*list))
+               if (repo_parse_commit_no_graph(ctx->r, *list))
                        die(_("unable to parse commit %s"),
                                oid_to_hex(&(*list)->object.oid));
                tree = get_commit_tree_oid(*list);
@@ -1193,7 +1204,9 @@ static int write_graph_chunk_generation_data(struct hashfile *f,
 
        for (i = 0; i < ctx->commits.nr; i++) {
                struct commit *c = ctx->commits.list[i];
-               timestamp_t offset = commit_graph_data_at(c)->generation - c->date;
+               timestamp_t offset;
+               repo_parse_commit(ctx->r, c);
+               offset = commit_graph_data_at(c)->generation - c->date;
                display_progress(ctx->progress, ++ctx->progress_cnt);
 
                if (offset > GENERATION_NUMBER_V2_OFFSET_MAX) {
@@ -1411,11 +1424,11 @@ static void close_reachable(struct write_commit_graph_context *ctx)
                if (!commit)
                        continue;
                if (ctx->split) {
-                       if ((!parse_commit(commit) &&
+                       if ((!repo_parse_commit(ctx->r, commit) &&
                             commit_graph_position(commit) == COMMIT_NOT_FROM_GRAPH) ||
                            flags == COMMIT_GRAPH_SPLIT_REPLACE)
                                add_missing_parents(ctx, commit);
-               } else if (!parse_commit_no_graph(commit))
+               } else if (!repo_parse_commit_no_graph(ctx->r, commit))
                        add_missing_parents(ctx, commit);
        }
        stop_progress(&ctx->progress);
@@ -1434,38 +1447,38 @@ static void close_reachable(struct write_commit_graph_context *ctx)
        stop_progress(&ctx->progress);
 }
 
-static void compute_generation_numbers(struct write_commit_graph_context *ctx)
+static void compute_topological_levels(struct write_commit_graph_context *ctx)
 {
        int i;
        struct commit_list *list = NULL;
 
        if (ctx->report_progress)
                ctx->progress = start_delayed_progress(
-                                       _("Computing commit graph generation numbers"),
+                                       _("Computing commit graph topological levels"),
                                        ctx->commits.nr);
        for (i = 0; i < ctx->commits.nr; i++) {
-               uint32_t level = *topo_level_slab_at(ctx->topo_levels, ctx->commits.list[i]);
-               timestamp_t corrected_commit_date = commit_graph_data_at(ctx->commits.list[i])->generation;
+               struct commit *c = ctx->commits.list[i];
+               uint32_t level;
+
+               repo_parse_commit(ctx->r, c);
+               level = *topo_level_slab_at(ctx->topo_levels, c);
 
                display_progress(ctx->progress, i + 1);
-               if (level != GENERATION_NUMBER_ZERO &&
-                   corrected_commit_date != GENERATION_NUMBER_ZERO)
+               if (level != GENERATION_NUMBER_ZERO)
                        continue;
 
-               commit_list_insert(ctx->commits.list[i], &list);
+               commit_list_insert(c, &list);
                while (list) {
                        struct commit *current = list->item;
                        struct commit_list *parent;
                        int all_parents_computed = 1;
                        uint32_t max_level = 0;
-                       timestamp_t max_corrected_commit_date = 0;
 
                        for (parent = current->parents; parent; parent = parent->next) {
+                               repo_parse_commit(ctx->r, parent->item);
                                level = *topo_level_slab_at(ctx->topo_levels, parent->item);
-                               corrected_commit_date = commit_graph_data_at(parent->item)->generation;
 
-                               if (level == GENERATION_NUMBER_ZERO ||
-                                   corrected_commit_date == GENERATION_NUMBER_ZERO) {
+                               if (level == GENERATION_NUMBER_ZERO) {
                                        all_parents_computed = 0;
                                        commit_list_insert(parent->item, &list);
                                        break;
@@ -1473,9 +1486,6 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
 
                                if (level > max_level)
                                        max_level = level;
-
-                               if (corrected_commit_date > max_corrected_commit_date)
-                                       max_corrected_commit_date = corrected_commit_date;
                        }
 
                        if (all_parents_computed) {
@@ -1484,6 +1494,64 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
                                if (max_level > GENERATION_NUMBER_V1_MAX - 1)
                                        max_level = GENERATION_NUMBER_V1_MAX - 1;
                                *topo_level_slab_at(ctx->topo_levels, current) = max_level + 1;
+                       }
+               }
+       }
+       stop_progress(&ctx->progress);
+}
+
+static void compute_generation_numbers(struct write_commit_graph_context *ctx)
+{
+       int i;
+       struct commit_list *list = NULL;
+
+       if (ctx->report_progress)
+               ctx->progress = start_delayed_progress(
+                                       _("Computing commit graph generation numbers"),
+                                       ctx->commits.nr);
+
+       if (!ctx->trust_generation_numbers) {
+               for (i = 0; i < ctx->commits.nr; i++) {
+                       struct commit *c = ctx->commits.list[i];
+                       repo_parse_commit(ctx->r, c);
+                       commit_graph_data_at(c)->generation = GENERATION_NUMBER_ZERO;
+               }
+       }
+
+       for (i = 0; i < ctx->commits.nr; i++) {
+               struct commit *c = ctx->commits.list[i];
+               timestamp_t corrected_commit_date;
+
+               repo_parse_commit(ctx->r, c);
+               corrected_commit_date = commit_graph_data_at(c)->generation;
+
+               display_progress(ctx->progress, i + 1);
+               if (corrected_commit_date != GENERATION_NUMBER_ZERO)
+                       continue;
+
+               commit_list_insert(c, &list);
+               while (list) {
+                       struct commit *current = list->item;
+                       struct commit_list *parent;
+                       int all_parents_computed = 1;
+                       timestamp_t max_corrected_commit_date = 0;
+
+                       for (parent = current->parents; parent; parent = parent->next) {
+                               repo_parse_commit(ctx->r, parent->item);
+                               corrected_commit_date = commit_graph_data_at(parent->item)->generation;
+
+                               if (corrected_commit_date == GENERATION_NUMBER_ZERO) {
+                                       all_parents_computed = 0;
+                                       commit_list_insert(parent->item, &list);
+                                       break;
+                               }
+
+                               if (corrected_commit_date > max_corrected_commit_date)
+                                       max_corrected_commit_date = corrected_commit_date;
+                       }
+
+                       if (all_parents_computed) {
+                               pop_commit(&list);
 
                                if (current->date && current->date > max_corrected_commit_date)
                                        max_corrected_commit_date = current->date - 1;
@@ -1710,9 +1778,9 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx)
                        continue;
 
                if (ctx->split && flags == COMMIT_GRAPH_SPLIT_REPLACE)
-                       parse_commit(ctx->commits.list[ctx->commits.nr]);
+                       repo_parse_commit(ctx->r, ctx->commits.list[ctx->commits.nr]);
                else
-                       parse_commit_no_graph(ctx->commits.list[ctx->commits.nr]);
+                       repo_parse_commit_no_graph(ctx->r, ctx->commits.list[ctx->commits.nr]);
 
                num_parents = commit_list_count(ctx->commits.list[ctx->commits.nr]->parents);
                if (num_parents > 2)
@@ -2280,6 +2348,7 @@ int write_commit_graph(struct object_directory *odb,
        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;
 
@@ -2293,7 +2362,6 @@ int write_commit_graph(struct object_directory *odb,
                ctx->changed_paths = 1;
        if (!(flags & COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS)) {
                struct commit_graph *g;
-               prepare_commit_graph_one(ctx->r, ctx->odb);
 
                g = ctx->r->objects->commit_graph;
 
@@ -2305,10 +2373,7 @@ int write_commit_graph(struct object_directory *odb,
        }
 
        if (ctx->split) {
-               struct commit_graph *g;
-               prepare_commit_graph(ctx->r);
-
-               g = ctx->r->objects->commit_graph;
+               struct commit_graph *g = ctx->r->objects->commit_graph;
 
                while (g) {
                        ctx->num_commit_graphs_before++;
@@ -2332,9 +2397,6 @@ int write_commit_graph(struct object_directory *odb,
 
        ctx->approx_nr_objects = approximate_object_count();
 
-       if (ctx->append)
-               prepare_commit_graph_one(ctx->r, ctx->odb);
-
        if (ctx->append && ctx->r->objects->commit_graph) {
                struct commit_graph *g = ctx->r->objects->commit_graph;
                for (i = 0; i < g->num_commits; i++) {
@@ -2381,9 +2443,11 @@ int write_commit_graph(struct object_directory *odb,
        } else
                ctx->num_commit_graphs_after = 1;
 
-       validate_mixed_generation_chain(ctx->r->objects->commit_graph);
+       ctx->trust_generation_numbers = validate_mixed_generation_chain(ctx->r->objects->commit_graph);
 
-       compute_generation_numbers(ctx);
+       compute_topological_levels(ctx);
+       if (ctx->write_generation_data)
+               compute_generation_numbers(ctx);
 
        if (ctx->changed_paths)
                compute_bloom_filters(ctx);
index 0c9714827c6c2634954b41792e9ddc1b1e5352a5..9e0c157bea3a95bec08b6bc5db7d6d7d9677b228 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -89,9 +89,10 @@ static inline int repo_parse_commit(struct repository *r, struct commit *item)
        return repo_parse_commit_gently(r, item, 0);
 }
 
-static inline int parse_commit_no_graph(struct commit *commit)
+static inline int repo_parse_commit_no_graph(struct repository *r,
+                                            struct commit *commit)
 {
-       return repo_parse_commit_internal(the_repository, commit, 0, 0);
+       return repo_parse_commit_internal(r, commit, 0, 0);
 }
 
 #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
index fa27df579a579a02255a316c788051ea11980827..5b15f1aa0f60e819a6a2b12f376224f2ea1ef13f 100755 (executable)
@@ -446,6 +446,27 @@ test_expect_success 'warn on improper hash version' '
        )
 '
 
+test_expect_success 'lower layers have overflow chunk' '
+       cd "$TRASH_DIRECTORY/full" &&
+       UNIX_EPOCH_ZERO="@0 +0000" &&
+       FUTURE_DATE="@2147483646 +0000" &&
+       rm -f .git/objects/info/commit-graph &&
+       test_commit --date "$FUTURE_DATE" future-1 &&
+       test_commit --date "$UNIX_EPOCH_ZERO" old-1 &&
+       git commit-graph write --reachable &&
+       test_commit --date "$FUTURE_DATE" future-2 &&
+       test_commit --date "$UNIX_EPOCH_ZERO" old-2 &&
+       git commit-graph write --reachable --split=no-merge &&
+       test_commit extra &&
+       git commit-graph write --reachable --split=no-merge &&
+       git commit-graph write --reachable &&
+       graph_read_expect 16 "generation_data generation_data_overflow extra_edges" &&
+       mv .git/objects/info/commit-graph commit-graph-upgraded &&
+       git commit-graph write --reachable &&
+       graph_read_expect 16 "generation_data generation_data_overflow extra_edges" &&
+       test_cmp .git/objects/info/commit-graph commit-graph-upgraded
+'
+
 # the verify tests below expect the commit-graph to contain
 # exactly the commits reachable from the commits/8 branch.
 # If the file changes the set of commits in the list, then the