Merge branch 'ds/commit-graph-genno-fix'

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
This commit is contained in:
Junio C Hamano 2021-02-17 17:21:40 -08:00
commit 5bd0b21bf7
3 changed files with 127 additions and 41 deletions

View 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,6 +1447,59 @@ static void close_reachable(struct write_commit_graph_context *ctx)
stop_progress(&ctx->progress);
}
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 topological levels"),
ctx->commits.nr);
for (i = 0; i < ctx->commits.nr; i++) {
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)
continue;
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;
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);
if (level == GENERATION_NUMBER_ZERO) {
all_parents_computed = 0;
commit_list_insert(parent->item, &list);
break;
}
if (level > max_level)
max_level = level;
}
if (all_parents_computed) {
pop_commit(&list);
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;
@ -1443,37 +1509,43 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
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++) {
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];
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 (level != GENERATION_NUMBER_ZERO &&
corrected_commit_date != GENERATION_NUMBER_ZERO)
if (corrected_commit_date != 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) {
level = *topo_level_slab_at(ctx->topo_levels, parent->item);
repo_parse_commit(ctx->r, parent->item);
corrected_commit_date = commit_graph_data_at(parent->item)->generation;
if (level == GENERATION_NUMBER_ZERO ||
corrected_commit_date == GENERATION_NUMBER_ZERO) {
if (corrected_commit_date == GENERATION_NUMBER_ZERO) {
all_parents_computed = 0;
commit_list_insert(parent->item, &list);
break;
}
if (level > max_level)
max_level = level;
if (corrected_commit_date > max_corrected_commit_date)
max_corrected_commit_date = corrected_commit_date;
}
@ -1481,10 +1553,6 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
if (all_parents_computed) {
pop_commit(&list);
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;
if (current->date && current->date > max_corrected_commit_date)
max_corrected_commit_date = current->date - 1;
commit_graph_data_at(current)->generation = max_corrected_commit_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);

View File

@ -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

View File

@ -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