last_chunk_offset = chunk_offset;
}
- if (verify_commit_graph_lite(graph))
+ if (verify_commit_graph_lite(graph)) {
+ free(graph);
return NULL;
+ }
return graph;
}
item->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
}
+static inline void set_commit_tree(struct commit *c, struct tree *t)
+{
+ c->maybe_tree = t;
+}
+
static int fill_commit_in_graph(struct repository *r,
struct commit *item,
struct commit_graph *g, uint32_t pos)
item->object.parsed = 1;
item->graph_pos = pos;
- item->maybe_tree = NULL;
+ set_commit_tree(item, NULL);
date_high = get_be32(commit_data + g->hash_len + 8) & 0x3;
date_low = get_be32(commit_data + g->hash_len + 12);
GRAPH_DATA_WIDTH * (c->graph_pos);
hashcpy(oid.hash, commit_data);
- c->maybe_tree = lookup_tree(r, &oid);
+ set_commit_tree(c, lookup_tree(r, &oid));
return c->maybe_tree;
}
return result;
}
-int write_commit_graph(const char *obj_dir,
- struct string_list *pack_indexes,
- struct string_list *commit_hex,
- unsigned int flags)
+static int fill_oids_from_packs(struct write_commit_graph_context *ctx,
+ struct string_list *pack_indexes)
{
- struct write_commit_graph_context *ctx;
- struct hashfile *f;
- uint32_t i, count_distinct = 0;
- char *graph_name = NULL;
- struct lock_file lk = LOCK_INIT;
- uint32_t chunk_ids[5];
- uint64_t chunk_offsets[5];
- int num_chunks;
- struct commit_list *parent;
- const unsigned hashsz = the_hash_algo->rawsz;
+ uint32_t i;
struct strbuf progress_title = STRBUF_INIT;
- int res = 0;
+ struct strbuf packname = STRBUF_INIT;
+ int dirlen;
- if (!commit_graph_compatible(the_repository))
- return 0;
-
- ctx = xcalloc(1, sizeof(struct write_commit_graph_context));
- ctx->r = the_repository;
- ctx->obj_dir = obj_dir;
- ctx->append = flags & COMMIT_GRAPH_APPEND ? 1 : 0;
- ctx->report_progress = flags & COMMIT_GRAPH_PROGRESS ? 1 : 0;
+ strbuf_addf(&packname, "%s/pack/", ctx->obj_dir);
+ dirlen = packname.len;
+ if (ctx->report_progress) {
+ strbuf_addf(&progress_title,
+ Q_("Finding commits for commit graph in %d pack",
+ "Finding commits for commit graph in %d packs",
+ pack_indexes->nr),
+ pack_indexes->nr);
+ ctx->progress = start_delayed_progress(progress_title.buf, 0);
+ ctx->progress_done = 0;
+ }
+ for (i = 0; i < pack_indexes->nr; i++) {
+ struct packed_git *p;
+ strbuf_setlen(&packname, dirlen);
+ strbuf_addstr(&packname, pack_indexes->items[i].string);
+ p = add_packed_git(packname.buf, packname.len, 1);
+ if (!p) {
+ error(_("error adding pack %s"), packname.buf);
+ return -1;
+ }
+ if (open_pack_index(p)) {
+ error(_("error opening index for %s"), packname.buf);
+ return -1;
+ }
+ for_each_object_in_pack(p, add_packed_commits, ctx,
+ FOR_EACH_OBJECT_PACK_ORDER);
+ close_pack(p);
+ free(p);
+ }
- ctx->approx_nr_objects = approximate_object_count();
- ctx->oids.alloc = ctx->approx_nr_objects / 32;
+ stop_progress(&ctx->progress);
+ strbuf_reset(&progress_title);
+ strbuf_release(&packname);
- if (ctx->append) {
- prepare_commit_graph_one(ctx->r, ctx->obj_dir);
- if (ctx->r->objects->commit_graph)
- ctx->oids.alloc += ctx->r->objects->commit_graph->num_commits;
- }
+ return 0;
+}
- if (ctx->oids.alloc < 1024)
- ctx->oids.alloc = 1024;
- ALLOC_ARRAY(ctx->oids.list, ctx->oids.alloc);
+static void fill_oids_from_commit_hex(struct write_commit_graph_context *ctx,
+ struct string_list *commit_hex)
+{
+ uint32_t i;
+ struct strbuf progress_title = STRBUF_INIT;
- 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++) {
- const unsigned char *hash = g->chunk_oid_lookup + g->hash_len * i;
- hashcpy(ctx->oids.list[ctx->oids.nr++].hash, hash);
- }
+ if (ctx->report_progress) {
+ strbuf_addf(&progress_title,
+ Q_("Finding commits for commit graph from %d ref",
+ "Finding commits for commit graph from %d refs",
+ commit_hex->nr),
+ commit_hex->nr);
+ ctx->progress = start_delayed_progress(
+ progress_title.buf,
+ commit_hex->nr);
}
+ for (i = 0; i < commit_hex->nr; i++) {
+ const char *end;
+ struct object_id oid;
+ struct commit *result;
- if (pack_indexes) {
- struct strbuf packname = STRBUF_INIT;
- int dirlen;
- strbuf_addf(&packname, "%s/pack/", obj_dir);
- dirlen = packname.len;
- if (ctx->report_progress) {
- strbuf_addf(&progress_title,
- Q_("Finding commits for commit graph in %d pack",
- "Finding commits for commit graph in %d packs",
- pack_indexes->nr),
- pack_indexes->nr);
- ctx->progress = start_delayed_progress(progress_title.buf, 0);
- ctx->progress_done = 0;
- }
- for (i = 0; i < pack_indexes->nr; i++) {
- struct packed_git *p;
- strbuf_setlen(&packname, dirlen);
- strbuf_addstr(&packname, pack_indexes->items[i].string);
- p = add_packed_git(packname.buf, packname.len, 1);
- if (!p) {
- error(_("error adding pack %s"), packname.buf);
- res = -1;
- goto cleanup;
- }
- if (open_pack_index(p)) {
- error(_("error opening index for %s"), packname.buf);
- res = -1;
- goto cleanup;
- }
- for_each_object_in_pack(p, add_packed_commits, ctx,
- FOR_EACH_OBJECT_PACK_ORDER);
- close_pack(p);
- free(p);
- }
- stop_progress(&ctx->progress);
- strbuf_reset(&progress_title);
- strbuf_release(&packname);
- }
+ display_progress(ctx->progress, i + 1);
+ if (commit_hex->items[i].string &&
+ parse_oid_hex(commit_hex->items[i].string, &oid, &end))
+ continue;
- if (commit_hex) {
- if (ctx->report_progress) {
- strbuf_addf(&progress_title,
- Q_("Finding commits for commit graph from %d ref",
- "Finding commits for commit graph from %d refs",
- commit_hex->nr),
- commit_hex->nr);
- ctx->progress = start_delayed_progress(
- progress_title.buf,
- commit_hex->nr);
- }
- for (i = 0; i < commit_hex->nr; i++) {
- const char *end;
- struct object_id oid;
- struct commit *result;
-
- display_progress(ctx->progress, i + 1);
- if (commit_hex->items[i].string &&
- parse_oid_hex(commit_hex->items[i].string, &oid, &end))
- continue;
-
- result = lookup_commit_reference_gently(ctx->r, &oid, 1);
-
- if (result) {
- ALLOC_GROW(ctx->oids.list, ctx->oids.nr + 1, ctx->oids.alloc);
- oidcpy(&ctx->oids.list[ctx->oids.nr], &(result->object.oid));
- ctx->oids.nr++;
- }
+ result = lookup_commit_reference_gently(ctx->r, &oid, 1);
+
+ if (result) {
+ ALLOC_GROW(ctx->oids.list, ctx->oids.nr + 1, ctx->oids.alloc);
+ oidcpy(&ctx->oids.list[ctx->oids.nr], &(result->object.oid));
+ ctx->oids.nr++;
}
- stop_progress(&ctx->progress);
- strbuf_reset(&progress_title);
}
+ stop_progress(&ctx->progress);
+ strbuf_release(&progress_title);
+}
- if (!pack_indexes && !commit_hex) {
- if (ctx->report_progress)
- ctx->progress = start_delayed_progress(
- _("Finding commits for commit graph among packed objects"),
- ctx->approx_nr_objects);
- for_each_packed_object(add_packed_commits, ctx,
- FOR_EACH_OBJECT_PACK_ORDER);
- if (ctx->progress_done < ctx->approx_nr_objects)
- display_progress(ctx->progress, ctx->approx_nr_objects);
- stop_progress(&ctx->progress);
- }
+static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
+{
+ if (ctx->report_progress)
+ ctx->progress = start_delayed_progress(
+ _("Finding commits for commit graph among packed objects"),
+ ctx->approx_nr_objects);
+ for_each_packed_object(add_packed_commits, ctx,
+ FOR_EACH_OBJECT_PACK_ORDER);
+ if (ctx->progress_done < ctx->approx_nr_objects)
+ display_progress(ctx->progress, ctx->approx_nr_objects);
+ stop_progress(&ctx->progress);
+}
- close_reachable(ctx);
+static uint32_t count_distinct_commits(struct write_commit_graph_context *ctx)
+{
+ uint32_t i, count_distinct = 1;
if (ctx->report_progress)
ctx->progress = start_delayed_progress(
ctx->oids.nr);
display_progress(ctx->progress, 0); /* TODO: Measure QSORT() progress */
QSORT(ctx->oids.list, ctx->oids.nr, commit_compare);
- count_distinct = 1;
+
for (i = 1; i < ctx->oids.nr; i++) {
display_progress(ctx->progress, i + 1);
if (!oideq(&ctx->oids.list[i - 1], &ctx->oids.list[i]))
}
stop_progress(&ctx->progress);
- if (count_distinct >= GRAPH_EDGE_LAST_MASK) {
- error(_("the commit graph format cannot write %d commits"), count_distinct);
- res = -1;
- goto cleanup;
- }
+ return count_distinct;
+}
- ctx->commits.alloc = count_distinct;
- ALLOC_ARRAY(ctx->commits.list, ctx->commits.alloc);
+static void copy_oids_to_commits(struct write_commit_graph_context *ctx)
+{
+ uint32_t i;
+ struct commit_list *parent;
ctx->num_extra_edges = 0;
if (ctx->report_progress)
ctx->commits.nr++;
}
stop_progress(&ctx->progress);
+}
- if (ctx->commits.nr >= GRAPH_EDGE_LAST_MASK) {
- error(_("too many commits to write graph"));
- res = -1;
- goto cleanup;
- }
-
- compute_generation_numbers(ctx);
-
- num_chunks = ctx->num_extra_edges ? 4 : 3;
+static int write_commit_graph_file(struct write_commit_graph_context *ctx)
+{
+ uint32_t i;
+ struct hashfile *f;
+ struct lock_file lk = LOCK_INIT;
+ uint32_t chunk_ids[5];
+ uint64_t chunk_offsets[5];
+ const unsigned hashsz = the_hash_algo->rawsz;
+ struct strbuf progress_title = STRBUF_INIT;
+ int num_chunks = ctx->num_extra_edges ? 4 : 3;
ctx->graph_name = get_commit_graph_filename(ctx->obj_dir);
if (safe_create_leading_directories(ctx->graph_name)) {
UNLEAK(ctx->graph_name);
error(_("unable to create leading directories of %s"),
ctx->graph_name);
- res = -1;
- goto cleanup;
+ return -1;
}
hold_lock_file_for_update(&lk, ctx->graph_name, LOCK_DIE_ON_ERROR);
finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_FSYNC);
commit_lock_file(&lk);
+ return 0;
+}
+
+int write_commit_graph(const char *obj_dir,
+ struct string_list *pack_indexes,
+ struct string_list *commit_hex,
+ unsigned int flags)
+{
+ struct write_commit_graph_context *ctx;
+ uint32_t i, count_distinct = 0;
+ int res = 0;
+
+ if (!commit_graph_compatible(the_repository))
+ return 0;
+
+ ctx = xcalloc(1, sizeof(struct write_commit_graph_context));
+ ctx->r = the_repository;
+ ctx->obj_dir = obj_dir;
+ ctx->append = flags & COMMIT_GRAPH_APPEND ? 1 : 0;
+ ctx->report_progress = flags & COMMIT_GRAPH_PROGRESS ? 1 : 0;
+
+ ctx->approx_nr_objects = approximate_object_count();
+ ctx->oids.alloc = ctx->approx_nr_objects / 32;
+
+ if (ctx->append) {
+ prepare_commit_graph_one(ctx->r, ctx->obj_dir);
+ if (ctx->r->objects->commit_graph)
+ ctx->oids.alloc += ctx->r->objects->commit_graph->num_commits;
+ }
+
+ if (ctx->oids.alloc < 1024)
+ ctx->oids.alloc = 1024;
+ ALLOC_ARRAY(ctx->oids.list, ctx->oids.alloc);
+
+ 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++) {
+ const unsigned char *hash = g->chunk_oid_lookup + g->hash_len * i;
+ hashcpy(ctx->oids.list[ctx->oids.nr++].hash, hash);
+ }
+ }
+
+ if (pack_indexes) {
+ if ((res = fill_oids_from_packs(ctx, pack_indexes)))
+ goto cleanup;
+ }
+
+ if (commit_hex)
+ fill_oids_from_commit_hex(ctx, commit_hex);
+
+ if (!pack_indexes && !commit_hex)
+ fill_oids_from_all_packs(ctx);
+
+ close_reachable(ctx);
+
+ count_distinct = count_distinct_commits(ctx);
+
+ if (count_distinct >= GRAPH_EDGE_LAST_MASK) {
+ error(_("the commit graph format cannot write %d commits"), count_distinct);
+ res = -1;
+ goto cleanup;
+ }
+
+ ctx->commits.alloc = count_distinct;
+ ALLOC_ARRAY(ctx->commits.list, ctx->commits.alloc);
+
+ copy_oids_to_commits(ctx);
+
+ if (ctx->commits.nr >= GRAPH_EDGE_LAST_MASK) {
+ error(_("too many commits to write graph"));
+ res = -1;
+ goto cleanup;
+ }
+
+ compute_generation_numbers(ctx);
+
+ res = write_commit_graph_file(ctx);
+
cleanup:
- free(graph_name);
+ free(ctx->graph_name);
free(ctx->commits.list);
free(ctx->oids.list);
free(ctx);