From d08437844d932920ce0550e2fb0bf27c3a30f4e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nar=C4=99bski?= Date: Sun, 15 Sep 2019 14:33:00 +0200 Subject: [PATCH] commit-graph: generation v5 (backward compatible date ceiling) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This generation number option is backward-compatible (with reachability index v0) version of the generation number v3, that is the corrected commit date. It takes the simple approach of faking "commit dates" being in the right order by adding an offset to the commit date (which is stored in the generation number column), so the modified commit date is always at least one more than the maximum modified commit date of all ancestors. Additionally the offset itself is adjusted in such way that the offset of a commit is always at least one more than the offsets of all ancestors. Two following conditions are satisfied on the offset of a commit C for every parent P: 1. committer_date(C) + offset(C) > committer_date(P) + offset(P) 2. offset(C) > offset(P) This reachability index is locally computable, which means it is compatible with incremental commit graph feature. It has the same problem as v3, namely that we have a "maximum clock skew" based on the maximum generation number we can store, only more so. Note: it includes incidental whitespace cleanups for v3 code. Signed-off-by: Jakub Narębski --- commit-graph.c | 126 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 95 insertions(+), 31 deletions(-) diff --git a/commit-graph.c b/commit-graph.c index 91863d4895a93e..633b4b24f8f814 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -99,10 +99,9 @@ int compare_generations(struct generation *a, struct generation *b) return 1; return 0; - case 3: - ta = a->date + a->value1; - tb = b->date + b->value1; - + case 3: /* V3: Corrected Commit Date */ + case 5: /* V5: Strictly Monotonic Corrected Commit Date */ + /* handle special cases, i.e. commits outside commit graph */ if (a->value1 == GENERATION_NUMBER_INFINITY) { if (b->value1 == GENERATION_NUMBER_INFINITY) return 0; @@ -112,6 +111,10 @@ int compare_generations(struct generation *a, struct generation *b) return -1; } + /* corrected commit date = date + offset (correction) */ + ta = a->date + a->value1; + tb = b->date + b->value1; + if (ta < tb) return -1; if (ta > tb) @@ -162,6 +165,7 @@ void get_generation_version_from_commit(const struct commit *c, case 1: case 3: + case 5: gen->value1 = c->generation; gen->date = c->date; break; @@ -212,9 +216,10 @@ void set_generation_below_commit(const struct commit *c, struct generation *g) break; case 3: + case 5: /* ??? */ if (g->value1 + g->date >= gc.value1 + gc.date) { g->value1 = 0; - g->date = gc.value1 + gc.date; + g->date = gc.value1 + gc.date; } break; @@ -363,7 +368,7 @@ struct commit_graph *load_commit_graph_one(const char *graph_file) else graph->chunk_large_edges = data + chunk_offset; break; - + case GRAPH_CHUNKID_FELINE: if (graph->chunk_feline_gen) chunk_repeated = 1; @@ -971,27 +976,27 @@ static void compute_generation_numbers_3(struct packed_commit_list *commits) int i; struct commit_list *list = NULL; - for (i = 0; i < commits->nr; i++) { - if (commits->list[i]->generation != GENERATION_NUMBER_INFINITY && - commits->list[i]->generation != GENERATION_NUMBER_ZERO) - continue; + for (i = 0; i < commits->nr; i++) { + if (commits->list[i]->generation != GENERATION_NUMBER_INFINITY && + commits->list[i]->generation != GENERATION_NUMBER_ZERO) + continue; - commit_list_insert(commits->list[i], &list); + commit_list_insert(commits->list[i], &list); - while (list) { - struct commit *current = list->item; - struct commit_list *parent; - int all_parents_computed = 1; + while (list) { + struct commit *current = list->item; + struct commit_list *parent; + int all_parents_computed = 1; - timestamp_t max_timestamp = current->date; + timestamp_t max_timestamp = current->date; - for (parent = current->parents; parent; parent = parent->next) { - if (parent->item->generation == GENERATION_NUMBER_INFINITY || - parent->item->generation == GENERATION_NUMBER_ZERO) { - all_parents_computed = 0; - commit_list_insert(parent->item, &list); - break; - } else { + for (parent = current->parents; parent; parent = parent->next) { + if (parent->item->generation == GENERATION_NUMBER_INFINITY || + parent->item->generation == GENERATION_NUMBER_ZERO) { + all_parents_computed = 0; + commit_list_insert(parent->item, &list); + break; + } else { struct generation pg; timestamp_t pt; get_generation_version_from_commit(parent->item, 3, &pg); @@ -1001,19 +1006,75 @@ static void compute_generation_numbers_3(struct packed_commit_list *commits) if (pt > max_timestamp) max_timestamp = pt + 1; } - } + } + + if (all_parents_computed) { + current->generation = (uint32_t)(max_timestamp - current->date) + 1; + pop_commit(&list); + + if (current->generation > GENERATION_NUMBER_MAX) + die(_("generation number gap is too high!")); + } + } + } +} + +static void compute_generation_numbers_5(struct packed_commit_list *commits) +{ + int i; + struct commit_list *list = NULL; + + for (i = 0; i < commits->nr; i++) { + /* skip already computed generation numbers */ + if (commits->list[i]->generation != GENERATION_NUMBER_INFINITY && + commits->list[i]->generation != GENERATION_NUMBER_ZERO) + continue; + + commit_list_insert(commits->list[i], &list); + + while (list) { + struct commit *current = list->item; + struct commit_list *parent; + int all_parents_computed = 1; + + timestamp_t max_timestamp = current->date; + uint32_t max_generation = 0; + + for (parent = current->parents; parent; parent = parent->next) { + if (parent->item->generation == GENERATION_NUMBER_INFINITY || + parent->item->generation == GENERATION_NUMBER_ZERO) { + all_parents_computed = 0; + commit_list_insert(parent->item, &list); + break; + + } else { + struct generation pg; + timestamp_t pt; + get_generation_version_from_commit(parent->item, 5, &pg); + + pt = pg.value1 + pg.date; + + if (pt > max_timestamp) + max_timestamp = pt + 1; + if (pg.value1 > max_generation) + max_generation = pg.value1; + } + } - if (all_parents_computed) { + if (all_parents_computed) { current->generation = (uint32_t)(max_timestamp - current->date) + 1; - pop_commit(&list); + if (current->generation < max_generation + 1) + current->generation = max_generation + 1; + pop_commit(&list); - if (current->generation > GENERATION_NUMBER_MAX) - die(_("generation number gap is too high!")); - } - } - } + if (current->generation > GENERATION_NUMBER_MAX) + die(_("generation number gap is too high!")); + } + } + } } + static void compute_generation_numbers(struct packed_commit_list *commits, int generation_version) { @@ -1038,6 +1099,9 @@ static void compute_generation_numbers(struct packed_commit_list *commits, case 4: /* compute at write time */ return; + case 5: + compute_generation_numbers_5(commits); + return; } }