diff options
Diffstat (limited to 'commit-graph.c')
| -rw-r--r-- | commit-graph.c | 195 |
1 files changed, 120 insertions, 75 deletions
diff --git a/commit-graph.c b/commit-graph.c index 474454db73..9abe62bd5a 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -965,7 +965,7 @@ static int fill_commit_in_graph(struct commit *item, do { if (g->chunk_extra_edges_size / sizeof(uint32_t) <= parent_data_pos) { error(_("commit-graph extra-edges pointer out of bounds")); - free_commit_list(item->parents); + commit_list_free(item->parents); item->parents = NULL; item->object.parsed = 0; return 0; @@ -1127,18 +1127,12 @@ struct tree *get_commit_tree_in_graph(struct repository *r, const struct commit return get_commit_tree_in_graph_one(r->objects->commit_graph, c); } -struct packed_commit_list { - struct commit **list; - size_t nr; - size_t alloc; -}; - struct write_commit_graph_context { struct repository *r; struct odb_source *odb_source; char *graph_name; struct oid_array oids; - struct packed_commit_list commits; + struct commit_stack commits; int num_extra_edges; int num_generation_data_overflows; unsigned long approx_nr_objects; @@ -1180,7 +1174,7 @@ static int write_graph_chunk_fanout(struct hashfile *f, { struct write_commit_graph_context *ctx = data; int i, count = 0; - struct commit **list = ctx->commits.list; + struct commit **list = ctx->commits.items; /* * Write the first-level table (the list is sorted, @@ -1206,7 +1200,7 @@ static int write_graph_chunk_oids(struct hashfile *f, void *data) { struct write_commit_graph_context *ctx = data; - struct commit **list = ctx->commits.list; + struct commit **list = ctx->commits.items; int count; for (count = 0; count < ctx->commits.nr; count++, list++) { display_progress(ctx->progress, ++ctx->progress_cnt); @@ -1226,8 +1220,8 @@ static int write_graph_chunk_data(struct hashfile *f, void *data) { struct write_commit_graph_context *ctx = data; - struct commit **list = ctx->commits.list; - struct commit **last = ctx->commits.list + ctx->commits.nr; + struct commit **list = ctx->commits.items; + struct commit **last = ctx->commits.items + ctx->commits.nr; uint32_t num_extra_edges = 0; while (list < last) { @@ -1249,7 +1243,7 @@ static int write_graph_chunk_data(struct hashfile *f, edge_value = GRAPH_PARENT_NONE; else { edge_value = oid_pos(&parent->item->object.oid, - ctx->commits.list, + ctx->commits.items, ctx->commits.nr, commit_to_oid); @@ -1280,7 +1274,7 @@ static int write_graph_chunk_data(struct hashfile *f, edge_value = GRAPH_EXTRA_EDGES_NEEDED | num_extra_edges; else { edge_value = oid_pos(&parent->item->object.oid, - ctx->commits.list, + ctx->commits.items, ctx->commits.nr, commit_to_oid); @@ -1325,6 +1319,37 @@ static int write_graph_chunk_data(struct hashfile *f, return 0; } +/* + * Compute the generation offset between the commit date and its generation. + * This is what's ultimately stored as generation number in the commit graph. + * + * Note that the computation of the commit date is more involved than you might + * think. Instead of using the full commit date, we're in fact masking bits so + * that only the 34 lowest bits are considered. This results from the fact that + * commit graphs themselves only ever store 34 bits of the commit date + * themselves. + * + * This means that if we have a commit date that exceeds 34 bits we'll end up + * in situations where depending on whether the commit has been parsed from the + * object database or the commit graph we'll have different dates, where the + * ones parsed from the object database would have full 64 bit precision. + * + * But ultimately, we only ever want the offset to be relative to what we + * actually end up storing on disk, and hence we have to mask all the other + * bits. + */ +static timestamp_t compute_generation_offset(struct commit *c) +{ + timestamp_t masked_date; + + if (sizeof(timestamp_t) > 4) + masked_date = c->date & (((timestamp_t) 1 << 34) - 1); + else + masked_date = c->date; + + return commit_graph_data_at(c)->generation - masked_date; +} + static int write_graph_chunk_generation_data(struct hashfile *f, void *data) { @@ -1332,10 +1357,10 @@ static int write_graph_chunk_generation_data(struct hashfile *f, int i, num_generation_data_overflows = 0; for (i = 0; i < ctx->commits.nr; i++) { - struct commit *c = ctx->commits.list[i]; + struct commit *c = ctx->commits.items[i]; timestamp_t offset; repo_parse_commit(ctx->r, c); - offset = commit_graph_data_at(c)->generation - c->date; + offset = compute_generation_offset(c); display_progress(ctx->progress, ++ctx->progress_cnt); if (offset > GENERATION_NUMBER_V2_OFFSET_MAX) { @@ -1355,8 +1380,8 @@ static int write_graph_chunk_generation_data_overflow(struct hashfile *f, struct write_commit_graph_context *ctx = data; int i; 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; + struct commit *c = ctx->commits.items[i]; + timestamp_t offset = compute_generation_offset(c); display_progress(ctx->progress, ++ctx->progress_cnt); if (offset > GENERATION_NUMBER_V2_OFFSET_MAX) { @@ -1372,8 +1397,8 @@ static int write_graph_chunk_extra_edges(struct hashfile *f, void *data) { struct write_commit_graph_context *ctx = data; - struct commit **list = ctx->commits.list; - struct commit **last = ctx->commits.list + ctx->commits.nr; + struct commit **list = ctx->commits.items; + struct commit **last = ctx->commits.items + ctx->commits.nr; struct commit_list *parent; while (list < last) { @@ -1393,7 +1418,7 @@ static int write_graph_chunk_extra_edges(struct hashfile *f, /* Since num_parents > 2, this initializer is safe. */ for (parent = (*list)->parents->next; parent; parent = parent->next) { int edge_value = oid_pos(&parent->item->object.oid, - ctx->commits.list, + ctx->commits.items, ctx->commits.nr, commit_to_oid); @@ -1427,8 +1452,8 @@ static int write_graph_chunk_bloom_indexes(struct hashfile *f, void *data) { struct write_commit_graph_context *ctx = data; - struct commit **list = ctx->commits.list; - struct commit **last = ctx->commits.list + ctx->commits.nr; + struct commit **list = ctx->commits.items; + struct commit **last = ctx->commits.items + ctx->commits.nr; uint32_t cur_pos = 0; while (list < last) { @@ -1463,8 +1488,8 @@ static int write_graph_chunk_bloom_data(struct hashfile *f, void *data) { struct write_commit_graph_context *ctx = data; - struct commit **list = ctx->commits.list; - struct commit **last = ctx->commits.list + ctx->commits.nr; + struct commit **list = ctx->commits.items; + struct commit **last = ctx->commits.items + ctx->commits.nr; trace2_bloom_filter_settings(ctx); @@ -1485,24 +1510,16 @@ static int write_graph_chunk_bloom_data(struct hashfile *f, return 0; } -static int add_packed_commits(const struct object_id *oid, - struct packed_git *pack, - uint32_t pos, - void *data) +static int add_packed_commits_oi(const struct object_id *oid, + struct object_info *oi, + void *data) { struct write_commit_graph_context *ctx = (struct write_commit_graph_context*)data; - enum object_type type; - off_t offset = nth_packed_object_offset(pack, pos); - struct object_info oi = OBJECT_INFO_INIT; if (ctx->progress) display_progress(ctx->progress, ++ctx->progress_done); - oi.typep = &type; - if (packed_object_info(ctx->r, pack, offset, &oi) < 0) - die(_("unable to get type of object %s"), oid_to_hex(oid)); - - if (type != OBJ_COMMIT) + if (*oi->typep != OBJ_COMMIT) return 0; oid_array_append(&ctx->oids, oid); @@ -1511,6 +1528,22 @@ static int add_packed_commits(const struct object_id *oid, return 0; } +static int add_packed_commits(const struct object_id *oid, + struct packed_git *pack, + uint32_t pos, + void *data) +{ + enum object_type type; + off_t offset = nth_packed_object_offset(pack, pos); + struct object_info oi = OBJECT_INFO_INIT; + + oi.typep = &type; + if (packed_object_info(pack, offset, &oi) < 0) + die(_("unable to get type of object %s"), oid_to_hex(oid)); + + return add_packed_commits_oi(oid, &oi, data); +} + static void add_missing_parents(struct write_commit_graph_context *ctx, struct commit *commit) { struct commit_list *parent; @@ -1585,7 +1618,7 @@ static void close_reachable(struct write_commit_graph_context *ctx) struct compute_generation_info { struct repository *r; - struct packed_commit_list *commits; + struct commit_stack *commits; struct progress *progress; int progress_cnt; @@ -1622,7 +1655,7 @@ static void compute_reachable_generation_numbers( struct commit_list *list = NULL; for (i = 0; i < info->commits->nr; i++) { - struct commit *c = info->commits->list[i]; + struct commit *c = info->commits->items[i]; timestamp_t gen; repo_parse_commit(info->r, c); gen = info->get_generation(c, info->data); @@ -1729,7 +1762,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx) if (!ctx->trust_generation_numbers) { for (i = 0; i < ctx->commits.nr; i++) { - struct commit *c = ctx->commits.list[i]; + struct commit *c = ctx->commits.items[i]; repo_parse_commit(ctx->r, c); commit_graph_data_at(c)->generation = GENERATION_NUMBER_ZERO; } @@ -1738,8 +1771,8 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx) compute_reachable_generation_numbers(&info, 2); 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; + struct commit *c = ctx->commits.items[i]; + timestamp_t offset = compute_generation_offset(c); if (offset > GENERATION_NUMBER_V2_OFFSET_MAX) ctx->num_generation_data_overflows++; } @@ -1760,8 +1793,8 @@ void ensure_generations_valid(struct repository *r, struct commit **commits, size_t nr) { int generation_version = get_configured_generation_version(r); - struct packed_commit_list list = { - .list = commits, + struct commit_stack list = { + .items = commits, .alloc = nr, .nr = nr, }; @@ -1804,7 +1837,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx) _("Computing commit changed paths Bloom filters"), ctx->commits.nr); - DUP_ARRAY(sorted_commits, ctx->commits.list, ctx->commits.nr); + DUP_ARRAY(sorted_commits, ctx->commits.items, ctx->commits.nr); if (ctx->order_by_pack) QSORT(sorted_commits, ctx->commits.nr, commit_pos_cmp); @@ -1851,18 +1884,16 @@ struct refs_cb_data { struct progress *progress; }; -static int add_ref_to_set(const char *refname UNUSED, - const char *referent UNUSED, - const struct object_id *oid, - int flags UNUSED, void *cb_data) +static int add_ref_to_set(const struct reference *ref, void *cb_data) { + const struct object_id *maybe_peeled = ref->oid; struct object_id peeled; struct refs_cb_data *data = (struct refs_cb_data *)cb_data; - if (!peel_iterated_oid(data->repo, oid, &peeled)) - oid = &peeled; - if (odb_read_object_info(data->repo->objects, oid, NULL) == OBJ_COMMIT) - oidset_insert(data->commits, oid); + if (!reference_get_peeled_oid(data->repo, ref, &peeled)) + maybe_peeled = &peeled; + if (odb_read_object_info(data->repo->objects, maybe_peeled, NULL) == OBJ_COMMIT) + oidset_insert(data->commits, maybe_peeled); display_progress(data->progress, oidset_size(data->commits)); @@ -1935,7 +1966,7 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx, goto cleanup; } for_each_object_in_pack(p, add_packed_commits, ctx, - FOR_EACH_OBJECT_PACK_ORDER); + ODB_FOR_EACH_OBJECT_PACK_ORDER); close_pack(p); free(p); } @@ -1967,13 +1998,28 @@ static int fill_oids_from_commits(struct write_commit_graph_context *ctx, static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx) { + struct odb_source *source; + enum object_type type; + struct odb_for_each_object_options opts = { + .flags = ODB_FOR_EACH_OBJECT_PACK_ORDER, + }; + struct object_info oi = { + .typep = &type, + }; + if (ctx->report_progress) ctx->progress = start_delayed_progress( ctx->r, _("Finding commits for commit graph among packed objects"), ctx->approx_nr_objects); - for_each_packed_object(ctx->r, add_packed_commits, ctx, - FOR_EACH_OBJECT_PACK_ORDER); + + odb_prepare_alternates(ctx->r->objects); + for (source = ctx->r->objects->sources; source; source = source->next) { + struct odb_source_files *files = odb_source_files_downcast(source); + packfile_store_for_each_object(files->packed, &oi, add_packed_commits_oi, + ctx, &opts); + } + if (ctx->progress_done < ctx->approx_nr_objects) display_progress(ctx->progress, ctx->approx_nr_objects); stop_progress(&ctx->progress); @@ -1994,26 +2040,26 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx) oid_array_sort(&ctx->oids); for (i = 0; i < ctx->oids.nr; i = oid_array_next_unique(&ctx->oids, i)) { unsigned int num_parents; + struct commit *commit; display_progress(ctx->progress, i + 1); - ALLOC_GROW(ctx->commits.list, ctx->commits.nr + 1, ctx->commits.alloc); - ctx->commits.list[ctx->commits.nr] = lookup_commit(ctx->r, &ctx->oids.oid[i]); + commit = lookup_commit(ctx->r, &ctx->oids.oid[i]); if (ctx->split && flags != COMMIT_GRAPH_SPLIT_REPLACE && - commit_graph_position(ctx->commits.list[ctx->commits.nr]) != COMMIT_NOT_FROM_GRAPH) + commit_graph_position(commit) != COMMIT_NOT_FROM_GRAPH) continue; if (ctx->split && flags == COMMIT_GRAPH_SPLIT_REPLACE) - repo_parse_commit(ctx->r, ctx->commits.list[ctx->commits.nr]); + repo_parse_commit(ctx->r, commit); else - repo_parse_commit_no_graph(ctx->r, ctx->commits.list[ctx->commits.nr]); + repo_parse_commit_no_graph(ctx->r, commit); - num_parents = commit_list_count(ctx->commits.list[ctx->commits.nr]->parents); + num_parents = commit_list_count(commit->parents); if (num_parents > 2) ctx->num_extra_edges += num_parents - 1; - ctx->commits.nr++; + commit_stack_push(&ctx->commits, commit); } stop_progress(&ctx->progress); } @@ -2332,7 +2378,7 @@ static void merge_commit_graph(struct write_commit_graph_context *ctx, 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); + commit_stack_grow(&ctx->commits, g->num_commits); for (i = 0; i < g->num_commits; i++) { struct object_id oid; @@ -2345,10 +2391,8 @@ static void merge_commit_graph(struct write_commit_graph_context *ctx, /* only add commits if they still exist in the repo */ result = lookup_commit_reference_gently(ctx->r, &oid, 1); - if (result) { - ctx->commits.list[ctx->commits.nr] = result; - ctx->commits.nr++; - } + if (result) + commit_stack_push(&ctx->commits, result); } } @@ -2369,14 +2413,14 @@ static void sort_and_scan_merged_commits(struct write_commit_graph_context *ctx) _("Scanning merged commits"), ctx->commits.nr); - QSORT(ctx->commits.list, ctx->commits.nr, commit_compare); + QSORT(ctx->commits.items, ctx->commits.nr, commit_compare); ctx->num_extra_edges = 0; for (i = 0; i < ctx->commits.nr; i++) { display_progress(ctx->progress, i + 1); - if (i && oideq(&ctx->commits.list[i - 1]->object.oid, - &ctx->commits.list[i]->object.oid)) { + if (i && oideq(&ctx->commits.items[i - 1]->object.oid, + &ctx->commits.items[i]->object.oid)) { /* * Silently ignore duplicates. These were likely * created due to a commit appearing in multiple @@ -2387,10 +2431,10 @@ static void sort_and_scan_merged_commits(struct write_commit_graph_context *ctx) } else { unsigned int num_parents; - ctx->commits.list[dedup_i] = ctx->commits.list[i]; + ctx->commits.items[dedup_i] = ctx->commits.items[i]; dedup_i++; - num_parents = commit_list_count(ctx->commits.list[i]->parents); + num_parents = commit_list_count(ctx->commits.items[i]->parents); if (num_parents > 2) ctx->num_extra_edges += num_parents - 1; } @@ -2597,7 +2641,8 @@ int write_commit_graph(struct odb_source *source, replace = ctx.opts->split_flags & COMMIT_GRAPH_SPLIT_REPLACE; } - ctx.approx_nr_objects = repo_approximate_object_count(r); + if (odb_count_objects(r->objects, ODB_COUNT_OBJECTS_APPROXIMATE, &ctx.approx_nr_objects) < 0) + ctx.approx_nr_objects = 0; if (ctx.append && g) { for (i = 0; i < g->num_commits; i++) { @@ -2668,7 +2713,7 @@ int write_commit_graph(struct odb_source *source, cleanup: free(ctx.graph_name); free(ctx.base_graph_name); - free(ctx.commits.list); + commit_stack_clear(&ctx.commits); oid_array_clear(&ctx.oids); clear_topo_level_slab(&topo_levels); |
