diff options
Diffstat (limited to 'commit-graph.c')
-rw-r--r-- | commit-graph.c | 160 |
1 files changed, 101 insertions, 59 deletions
diff --git a/commit-graph.c b/commit-graph.c index 843bdb458d..9e6eaa8a46 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -12,8 +12,9 @@ #include "hash-lookup.h" #include "commit-graph.h" #include "object-file.h" -#include "object-store.h" +#include "object-store-ll.h" #include "oid-array.h" +#include "path.h" #include "alloc.h" #include "hashmap.h" #include "replace-object.h" @@ -25,7 +26,6 @@ #include "trace2.h" #include "tree.h" #include "chunk-format.h" -#include "wrapper.h" void git_test_write_commit_graph_or_die(void) { @@ -128,6 +128,16 @@ timestamp_t commit_graph_generation(const struct commit *c) return GENERATION_NUMBER_INFINITY; } +static timestamp_t commit_graph_generation_from_graph(const struct commit *c) +{ + struct commit_graph_data *data = + commit_graph_data_slab_peek(&commit_graph_data_slab, c); + + if (!data || data->graph_pos == COMMIT_NOT_FROM_GRAPH) + return GENERATION_NUMBER_INFINITY; + return data->generation; +} + static struct commit_graph_data *commit_graph_data_at(const struct commit *c) { unsigned int i, nth_slab; @@ -204,14 +214,12 @@ static struct commit_graph *alloc_commit_graph(void) return g; } -extern int read_replace_refs; - static int commit_graph_compatible(struct repository *r) { if (!r->gitdir) return 0; - if (read_replace_refs) { + if (replace_refs_enabled(r)) { prepare_replace_object(r); if (hashmap_get_size(&r->objects->replace_map->map)) return 0; @@ -482,7 +490,7 @@ static int add_graph_to_chain(struct commit_graph *g, if (!cur_g || !oideq(&oids[n], &cur_g->oid) || - !hasheq(oids[n].hash, g->chunk_base_graphs + g->hash_len * n)) { + !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_len, n))) { warning(_("commit-graph chain does not match")); return 0; } @@ -492,8 +500,15 @@ static int add_graph_to_chain(struct commit_graph *g, g->base_graph = chain; - if (chain) + if (chain) { + if (unsigned_add_overflows(chain->num_commits, + chain->num_commits_in_base)) { + warning(_("commit count in base graph too high: %"PRIuMAX), + (uintmax_t)chain->num_commits_in_base); + return 0; + } g->num_commits_in_base = chain->num_commits + chain->num_commits_in_base; + } return 1; } @@ -747,7 +762,7 @@ static void load_oid_from_graph(struct commit_graph *g, lex_index = pos - g->num_commits_in_base; - oidread(oid, g->chunk_oid_lookup + g->hash_len * lex_index); + oidread(oid, g->chunk_oid_lookup + st_mult(g->hash_len, lex_index)); } static struct commit_list **insert_parent_or_die(struct repository *r, @@ -783,7 +798,7 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g, die(_("invalid commit position. commit-graph is likely corrupt")); lex_index = pos - g->num_commits_in_base; - commit_data = g->chunk_commit_data + GRAPH_DATA_WIDTH * lex_index; + commit_data = g->chunk_commit_data + st_mult(GRAPH_DATA_WIDTH, lex_index); graph_data = commit_graph_data_at(item); graph_data->graph_pos = pos; @@ -793,14 +808,14 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g, item->date = (timestamp_t)((date_high << 32) | date_low); if (g->read_generation_data) { - offset = (timestamp_t)get_be32(g->chunk_generation_data + sizeof(uint32_t) * lex_index); + offset = (timestamp_t)get_be32(g->chunk_generation_data + st_mult(sizeof(uint32_t), lex_index)); if (offset & CORRECTED_COMMIT_DATE_OFFSET_OVERFLOW) { if (!g->chunk_generation_data_overflow) die(_("commit-graph requires overflow generation data but has none")); offset_pos = offset ^ CORRECTED_COMMIT_DATE_OFFSET_OVERFLOW; - graph_data->generation = item->date + get_be64(g->chunk_generation_data_overflow + 8 * offset_pos); + graph_data->generation = item->date + get_be64(g->chunk_generation_data_overflow + st_mult(8, offset_pos)); } else graph_data->generation = item->date + offset; } else @@ -831,7 +846,7 @@ static int fill_commit_in_graph(struct repository *r, fill_commit_graph_info(item, g, pos); lex_index = pos - g->num_commits_in_base; - commit_data = g->chunk_commit_data + (g->hash_len + 16) * lex_index; + commit_data = g->chunk_commit_data + st_mult(g->hash_len + 16, lex_index); item->object.parsed = 1; @@ -853,7 +868,7 @@ static int fill_commit_in_graph(struct repository *r, } parent_data_ptr = (uint32_t*)(g->chunk_extra_edges + - 4 * (uint64_t)(edge_value & GRAPH_EDGE_LAST_MASK)); + st_mult(4, edge_value & GRAPH_EDGE_LAST_MASK)); do { edge_value = get_be32(parent_data_ptr); pptr = insert_parent_or_die(r, g, @@ -973,7 +988,7 @@ static struct tree *load_tree_for_commit(struct repository *r, g = g->base_graph; commit_data = g->chunk_commit_data + - GRAPH_DATA_WIDTH * (graph_pos - g->num_commits_in_base); + st_mult(GRAPH_DATA_WIDTH, graph_pos - g->num_commits_in_base); oidread(&oid, commit_data); set_commit_tree(c, lookup_tree(r, &oid)); @@ -1953,35 +1968,35 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx) add_chunk(cf, GRAPH_CHUNKID_OIDFANOUT, GRAPH_FANOUT_SIZE, write_graph_chunk_fanout); - add_chunk(cf, GRAPH_CHUNKID_OIDLOOKUP, hashsz * ctx->commits.nr, + add_chunk(cf, GRAPH_CHUNKID_OIDLOOKUP, st_mult(hashsz, ctx->commits.nr), write_graph_chunk_oids); - add_chunk(cf, GRAPH_CHUNKID_DATA, (hashsz + 16) * ctx->commits.nr, + add_chunk(cf, GRAPH_CHUNKID_DATA, st_mult(hashsz + 16, ctx->commits.nr), write_graph_chunk_data); if (ctx->write_generation_data) add_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA, - sizeof(uint32_t) * ctx->commits.nr, + st_mult(sizeof(uint32_t), ctx->commits.nr), write_graph_chunk_generation_data); if (ctx->num_generation_data_overflows) add_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW, - sizeof(timestamp_t) * ctx->num_generation_data_overflows, + st_mult(sizeof(timestamp_t), ctx->num_generation_data_overflows), write_graph_chunk_generation_data_overflow); if (ctx->num_extra_edges) add_chunk(cf, GRAPH_CHUNKID_EXTRAEDGES, - 4 * ctx->num_extra_edges, + st_mult(4, ctx->num_extra_edges), write_graph_chunk_extra_edges); if (ctx->changed_paths) { add_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES, - sizeof(uint32_t) * ctx->commits.nr, + st_mult(sizeof(uint32_t), ctx->commits.nr), write_graph_chunk_bloom_indexes); add_chunk(cf, GRAPH_CHUNKID_BLOOMDATA, - sizeof(uint32_t) * 3 - + ctx->total_bloom_filter_data_size, + st_add(sizeof(uint32_t) * 3, + ctx->total_bloom_filter_data_size), write_graph_chunk_bloom_data); } if (ctx->num_commit_graphs_after > 1) add_chunk(cf, GRAPH_CHUNKID_BASE, - hashsz * (ctx->num_commit_graphs_after - 1), + st_mult(hashsz, ctx->num_commit_graphs_after - 1), write_graph_chunk_base); hashwrite_be32(f, GRAPH_SIGNATURE); @@ -1999,7 +2014,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx) get_num_chunks(cf)); ctx->progress = start_delayed_progress( progress_title.buf, - get_num_chunks(cf) * ctx->commits.nr); + st_mult(get_num_chunks(cf), ctx->commits.nr)); } write_chunkfile(cf, ctx); @@ -2105,11 +2120,16 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx) if (flags != COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED && flags != COMMIT_GRAPH_SPLIT_REPLACE) { - while (g && (g->num_commits <= size_mult * num_commits || + while (g && (g->num_commits <= st_mult(size_mult, num_commits) || (max_commits && num_commits > max_commits))) { if (g->odb != ctx->odb) break; + if (unsigned_add_overflows(num_commits, g->num_commits)) + die(_("cannot merge graphs with %"PRIuMAX", " + "%"PRIuMAX" commits"), + (uintmax_t)num_commits, + (uintmax_t)g->num_commits); num_commits += g->num_commits; g = g->base_graph; @@ -2167,6 +2187,11 @@ static void merge_commit_graph(struct write_commit_graph_context *ctx, uint32_t i; uint32_t offset = g->num_commits_in_base; + if (unsigned_add_overflows(ctx->commits.nr, g->num_commits)) + die(_("cannot merge graph %s, too many commits: %"PRIuMAX), + oid_to_hex(&g->oid), + (uintmax_t)st_add(ctx->commits.nr, g->num_commits)); + ALLOC_GROW(ctx->commits.list, ctx->commits.nr + g->num_commits, ctx->commits.alloc); for (i = 0; i < g->num_commits; i++) { @@ -2437,7 +2462,7 @@ int write_commit_graph(struct object_directory *odb, struct commit_graph *g = ctx->r->objects->commit_graph; for (i = 0; i < g->num_commits; i++) { struct object_id oid; - oidread(&oid, g->chunk_oid_lookup + g->hash_len * i); + oidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_len, i)); oid_array_append(&ctx->oids, &oid); } } @@ -2535,26 +2560,20 @@ static void graph_report(const char *fmt, ...) va_end(ap); } -#define GENERATION_ZERO_EXISTS 1 -#define GENERATION_NUMBER_EXISTS 2 - static int commit_graph_checksum_valid(struct commit_graph *g) { return hashfile_checksum_valid(g->data, g->data_len); } -int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags) +static int verify_one_commit_graph(struct repository *r, + struct commit_graph *g, + struct progress *progress, + uint64_t *seen) { uint32_t i, cur_fanout_pos = 0; struct object_id prev_oid, cur_oid; - int generation_zero = 0; - struct progress *progress = NULL; - int local_error = 0; - - if (!g) { - graph_report("no commit-graph file loaded"); - return 1; - } + struct commit *seen_gen_zero = NULL; + struct commit *seen_gen_non_zero = NULL; verify_commit_graph_error = verify_commit_graph_lite(g); if (verify_commit_graph_error) @@ -2568,7 +2587,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags) for (i = 0; i < g->num_commits; i++) { struct commit *graph_commit; - oidread(&cur_oid, g->chunk_oid_lookup + g->hash_len * i); + oidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i)); if (i && oidcmp(&prev_oid, &cur_oid) >= 0) graph_report(_("commit-graph has incorrect OID order: %s then %s"), @@ -2605,18 +2624,14 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags) if (verify_commit_graph_error & ~VERIFY_COMMIT_GRAPH_ERROR_HASH) return verify_commit_graph_error; - if (flags & COMMIT_GRAPH_WRITE_PROGRESS) - progress = start_progress(_("Verifying commits in commit graph"), - g->num_commits); - for (i = 0; i < g->num_commits; i++) { struct commit *graph_commit, *odb_commit; struct commit_list *graph_parents, *odb_parents; timestamp_t max_generation = 0; timestamp_t generation; - display_progress(progress, i + 1); - oidread(&cur_oid, g->chunk_oid_lookup + g->hash_len * i); + display_progress(progress, ++(*seen)); + oidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i)); graph_commit = lookup_commit(r, &cur_oid); odb_commit = (struct commit *)create_object(r, &cur_oid, alloc_commit_node(r)); @@ -2652,7 +2667,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags) oid_to_hex(&graph_parents->item->object.oid), oid_to_hex(&odb_parents->item->object.oid)); - generation = commit_graph_generation(graph_parents->item); + generation = commit_graph_generation_from_graph(graph_parents->item); if (generation > max_generation) max_generation = generation; @@ -2664,16 +2679,12 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags) graph_report(_("commit-graph parent list for commit %s terminates early"), oid_to_hex(&cur_oid)); - if (!commit_graph_generation(graph_commit)) { - if (generation_zero == GENERATION_NUMBER_EXISTS) - graph_report(_("commit-graph has generation number zero for commit %s, but non-zero elsewhere"), - oid_to_hex(&cur_oid)); - generation_zero = GENERATION_ZERO_EXISTS; - } else if (generation_zero == GENERATION_ZERO_EXISTS) - graph_report(_("commit-graph has non-zero generation number for commit %s, but zero elsewhere"), - oid_to_hex(&cur_oid)); + if (commit_graph_generation_from_graph(graph_commit)) + seen_gen_non_zero = graph_commit; + else + seen_gen_zero = graph_commit; - if (generation_zero == GENERATION_ZERO_EXISTS) + if (seen_gen_zero) continue; /* @@ -2698,12 +2709,43 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags) graph_commit->date, odb_commit->date); } - stop_progress(&progress); - local_error = verify_commit_graph_error; + if (seen_gen_zero && seen_gen_non_zero) + graph_report(_("commit-graph has both zero and non-zero " + "generations (e.g., commits '%s' and '%s')"), + oid_to_hex(&seen_gen_zero->object.oid), + oid_to_hex(&seen_gen_non_zero->object.oid)); + + return verify_commit_graph_error; +} + +int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags) +{ + struct progress *progress = NULL; + int local_error = 0; + uint64_t seen = 0; + + if (!g) { + graph_report("no commit-graph file loaded"); + return 1; + } + + if (flags & COMMIT_GRAPH_WRITE_PROGRESS) { + uint64_t total = g->num_commits; + if (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW)) + total += g->num_commits_in_base; + + progress = start_progress(_("Verifying commits in commit graph"), + total); + } + + for (; g; g = g->base_graph) { + local_error |= verify_one_commit_graph(r, g, progress, &seen); + if (flags & COMMIT_GRAPH_VERIFY_SHALLOW) + break; + } - if (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW) && g->base_graph) - local_error |= verify_commit_graph(r, g->base_graph, flags); + stop_progress(&progress); return local_error; } |