summaryrefslogtreecommitdiff
path: root/commit-graph.c
diff options
context:
space:
mode:
Diffstat (limited to 'commit-graph.c')
-rw-r--r--commit-graph.c421
1 files changed, 278 insertions, 143 deletions
diff --git a/commit-graph.c b/commit-graph.c
index 1af68c297d..6f62a07313 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1,7 +1,5 @@
-#include "cache.h"
-#include "config.h"
-#include "dir.h"
#include "git-compat-util.h"
+#include "config.h"
#include "lockfile.h"
#include "pack.h"
#include "packfile.h"
@@ -19,6 +17,8 @@
#include "bloom.h"
#include "commit-slab.h"
#include "shallow.h"
+#include "json-writer.h"
+#include "trace2.h"
void git_test_write_commit_graph_or_die(void)
{
@@ -172,14 +172,21 @@ static char *get_split_graph_filename(struct object_directory *odb,
oid_hex);
}
-static char *get_chain_filename(struct object_directory *odb)
+char *get_commit_graph_chain_filename(struct object_directory *odb)
{
return xstrfmt("%s/info/commit-graphs/commit-graph-chain", odb->path);
}
static uint8_t oid_version(void)
{
- return 1;
+ switch (hash_algo_by_ptr(the_hash_algo)) {
+ case GIT_HASH_SHA1:
+ return 1;
+ case GIT_HASH_SHA256:
+ return 2;
+ default:
+ die(_("invalid hash version"));
+ }
}
static struct commit_graph *alloc_commit_graph(void)
@@ -224,7 +231,8 @@ int open_commit_graph(const char *graph_file, int *fd, struct stat *st)
return 1;
}
-struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st,
+struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,
+ int fd, struct stat *st,
struct object_directory *odb)
{
void *graph_map;
@@ -240,7 +248,7 @@ struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st,
}
graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
- ret = parse_commit_graph(graph_map, graph_size);
+ ret = parse_commit_graph(r, graph_map, graph_size);
if (ret)
ret->odb = odb;
@@ -280,13 +288,13 @@ static int verify_commit_graph_lite(struct commit_graph *g)
return 0;
}
-struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
+struct commit_graph *parse_commit_graph(struct repository *r,
+ void *graph_map, size_t graph_size)
{
const unsigned char *data, *chunk_lookup;
uint32_t i;
struct commit_graph *graph;
- uint64_t last_chunk_offset;
- uint32_t last_chunk_id;
+ uint64_t next_chunk_offset;
uint32_t graph_signature;
unsigned char graph_version, hash_version;
@@ -319,6 +327,8 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
return NULL;
}
+ prepare_repo_settings(r);
+
graph = alloc_commit_graph();
graph->hash_len = the_hash_algo->rawsz;
@@ -326,24 +336,26 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
graph->data = graph_map;
graph->data_len = graph_size;
- last_chunk_id = 0;
- last_chunk_offset = 8;
+ if (graph_size < GRAPH_HEADER_SIZE +
+ (graph->num_chunks + 1) * GRAPH_CHUNKLOOKUP_WIDTH +
+ GRAPH_FANOUT_SIZE + the_hash_algo->rawsz) {
+ error(_("commit-graph file is too small to hold %u chunks"),
+ graph->num_chunks);
+ free(graph);
+ return NULL;
+ }
+
chunk_lookup = data + 8;
+ next_chunk_offset = get_be64(chunk_lookup + 4);
for (i = 0; i < graph->num_chunks; i++) {
uint32_t chunk_id;
- uint64_t chunk_offset;
+ uint64_t chunk_offset = next_chunk_offset;
int chunk_repeated = 0;
- if (data + graph_size - chunk_lookup <
- GRAPH_CHUNKLOOKUP_WIDTH) {
- error(_("commit-graph chunk lookup table entry missing; file may be incomplete"));
- goto free_and_return;
- }
-
chunk_id = get_be32(chunk_lookup + 0);
- chunk_offset = get_be64(chunk_lookup + 4);
chunk_lookup += GRAPH_CHUNKLOOKUP_WIDTH;
+ next_chunk_offset = get_be64(chunk_lookup + 4);
if (chunk_offset > graph_size - the_hash_algo->rawsz) {
error(_("commit-graph improper chunk offset %08x%08x"), (uint32_t)(chunk_offset >> 32),
@@ -362,8 +374,11 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
case GRAPH_CHUNKID_OIDLOOKUP:
if (graph->chunk_oid_lookup)
chunk_repeated = 1;
- else
+ else {
graph->chunk_oid_lookup = data + chunk_offset;
+ graph->num_commits = (next_chunk_offset - chunk_offset)
+ / graph->hash_len;
+ }
break;
case GRAPH_CHUNKID_DATA:
@@ -390,14 +405,14 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
case GRAPH_CHUNKID_BLOOMINDEXES:
if (graph->chunk_bloom_indexes)
chunk_repeated = 1;
- else
+ else if (r->settings.commit_graph_read_changed_paths)
graph->chunk_bloom_indexes = data + chunk_offset;
break;
case GRAPH_CHUNKID_BLOOMDATA:
if (graph->chunk_bloom_data)
chunk_repeated = 1;
- else {
+ else if (r->settings.commit_graph_read_changed_paths) {
uint32_t hash_version;
graph->chunk_bloom_data = data + chunk_offset;
hash_version = get_be32(data + chunk_offset);
@@ -409,6 +424,7 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
graph->bloom_filter_settings->hash_version = hash_version;
graph->bloom_filter_settings->num_hashes = get_be32(data + chunk_offset + 4);
graph->bloom_filter_settings->bits_per_entry = get_be32(data + chunk_offset + 8);
+ graph->bloom_filter_settings->max_changed_paths = DEFAULT_BLOOM_MAX_CHANGES;
}
break;
}
@@ -417,15 +433,6 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
error(_("commit-graph chunk id %08x appears multiple times"), chunk_id);
goto free_and_return;
}
-
- if (last_chunk_id == GRAPH_CHUNKID_OIDLOOKUP)
- {
- graph->num_commits = (chunk_offset - last_chunk_offset)
- / graph->hash_len;
- }
-
- last_chunk_id = chunk_id;
- last_chunk_offset = chunk_offset;
}
if (graph->chunk_bloom_indexes && graph->chunk_bloom_data) {
@@ -450,7 +457,8 @@ free_and_return:
return NULL;
}
-static struct commit_graph *load_commit_graph_one(const char *graph_file,
+static struct commit_graph *load_commit_graph_one(struct repository *r,
+ const char *graph_file,
struct object_directory *odb)
{
@@ -462,7 +470,7 @@ static struct commit_graph *load_commit_graph_one(const char *graph_file,
if (!open_ok)
return NULL;
- g = load_commit_graph_one_fd_st(fd, &st, odb);
+ g = load_commit_graph_one_fd_st(r, fd, &st, odb);
if (g)
g->filename = xstrdup(graph_file);
@@ -474,7 +482,7 @@ static struct commit_graph *load_commit_graph_v1(struct repository *r,
struct object_directory *odb)
{
char *graph_name = get_commit_graph_filename(odb);
- struct commit_graph *g = load_commit_graph_one(graph_name, odb);
+ struct commit_graph *g = load_commit_graph_one(r, graph_name, odb);
free(graph_name);
return g;
@@ -521,7 +529,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
struct stat st;
struct object_id *oids;
int i = 0, valid = 1, count;
- char *chain_name = get_chain_filename(odb);
+ char *chain_name = get_commit_graph_chain_filename(odb);
FILE *fp;
int stat_res;
@@ -555,7 +563,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
valid = 0;
for (odb = r->objects->odb; odb; odb = odb->next) {
char *graph_name = get_split_graph_filename(odb, line.buf);
- struct commit_graph *g = load_commit_graph_one(graph_name, odb);
+ struct commit_graph *g = load_commit_graph_one(r, graph_name, odb);
free(graph_name);
@@ -624,10 +632,6 @@ static int prepare_commit_graph(struct repository *r)
return !!r->objects->commit_graph;
r->objects->commit_graph_attempted = 1;
- if (git_env_bool(GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD, 0))
- die("dying as requested by the '%s' variable on commit-graph load!",
- GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD);
-
prepare_repo_settings(r);
if (!git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
@@ -669,6 +673,17 @@ int generation_numbers_enabled(struct repository *r)
return !!first_generation;
}
+struct bloom_filter_settings *get_bloom_filter_settings(struct repository *r)
+{
+ struct commit_graph *g = r->objects->commit_graph;
+ while (g) {
+ if (g->bloom_filter_settings)
+ return g->bloom_filter_settings;
+ g = g->base_graph;
+ }
+ return NULL;
+}
+
static void close_commit_graph_one(struct commit_graph *g)
{
if (!g)
@@ -856,6 +871,14 @@ static int parse_commit_in_graph_one(struct repository *r,
int parse_commit_in_graph(struct repository *r, struct commit *item)
{
+ static int checked_env = 0;
+
+ if (!checked_env &&
+ git_env_bool(GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE, 0))
+ die("dying as requested by the '%s' variable on commit-graph parse!",
+ GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE);
+ checked_env = 1;
+
if (!prepare_commit_graph(r))
return 0;
return parse_commit_in_graph_one(r, r->objects->commit_graph, item);
@@ -946,12 +969,18 @@ struct write_commit_graph_context {
changed_paths:1,
order_by_pack:1;
- const struct split_commit_graph_opts *split_opts;
+ const struct commit_graph_opts *opts;
size_t total_bloom_filter_data_size;
+ const struct bloom_filter_settings *bloom_settings;
+
+ int count_bloom_filter_computed;
+ int count_bloom_filter_not_computed;
+ int count_bloom_filter_trunc_empty;
+ int count_bloom_filter_trunc_large;
};
-static void write_graph_chunk_fanout(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+static int write_graph_chunk_fanout(struct hashfile *f,
+ struct write_commit_graph_context *ctx)
{
int i, count = 0;
struct commit **list = ctx->commits.list;
@@ -972,17 +1001,21 @@ static void write_graph_chunk_fanout(struct hashfile *f,
hashwrite_be32(f, count);
}
+
+ return 0;
}
-static void write_graph_chunk_oids(struct hashfile *f, int hash_len,
- struct write_commit_graph_context *ctx)
+static int write_graph_chunk_oids(struct hashfile *f,
+ struct write_commit_graph_context *ctx)
{
struct commit **list = ctx->commits.list;
int count;
for (count = 0; count < ctx->commits.nr; count++, list++) {
display_progress(ctx->progress, ++ctx->progress_cnt);
- hashwrite(f, (*list)->object.oid.hash, (int)hash_len);
+ hashwrite(f, (*list)->object.oid.hash, the_hash_algo->rawsz);
}
+
+ return 0;
}
static const unsigned char *commit_to_sha1(size_t index, void *table)
@@ -991,8 +1024,8 @@ static const unsigned char *commit_to_sha1(size_t index, void *table)
return commits[index]->object.oid.hash;
}
-static void write_graph_chunk_data(struct hashfile *f, int hash_len,
- struct write_commit_graph_context *ctx)
+static int write_graph_chunk_data(struct hashfile *f,
+ struct write_commit_graph_context *ctx)
{
struct commit **list = ctx->commits.list;
struct commit **last = ctx->commits.list + ctx->commits.nr;
@@ -1009,7 +1042,7 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
die(_("unable to parse commit %s"),
oid_to_hex(&(*list)->object.oid));
tree = get_commit_tree_oid(*list);
- hashwrite(f, tree->hash, hash_len);
+ hashwrite(f, tree->hash, the_hash_algo->rawsz);
parent = (*list)->parents;
@@ -1089,10 +1122,12 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
list++;
}
+
+ return 0;
}
-static void write_graph_chunk_extra_edges(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+static int write_graph_chunk_extra_edges(struct hashfile *f,
+ struct write_commit_graph_context *ctx)
{
struct commit **list = ctx->commits.list;
struct commit **last = ctx->commits.list + ctx->commits.nr;
@@ -1141,41 +1176,68 @@ static void write_graph_chunk_extra_edges(struct hashfile *f,
list++;
}
+
+ return 0;
}
-static void write_graph_chunk_bloom_indexes(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+static int write_graph_chunk_bloom_indexes(struct hashfile *f,
+ struct write_commit_graph_context *ctx)
{
struct commit **list = ctx->commits.list;
struct commit **last = ctx->commits.list + ctx->commits.nr;
uint32_t cur_pos = 0;
while (list < last) {
- struct bloom_filter *filter = get_bloom_filter(ctx->r, *list, 0);
- cur_pos += filter->len;
+ struct bloom_filter *filter = get_bloom_filter(ctx->r, *list);
+ size_t len = filter ? filter->len : 0;
+ cur_pos += len;
display_progress(ctx->progress, ++ctx->progress_cnt);
hashwrite_be32(f, cur_pos);
list++;
}
+
+ return 0;
}
-static void write_graph_chunk_bloom_data(struct hashfile *f,
- struct write_commit_graph_context *ctx,
- const struct bloom_filter_settings *settings)
+static void trace2_bloom_filter_settings(struct write_commit_graph_context *ctx)
+{
+ struct json_writer jw = JSON_WRITER_INIT;
+
+ jw_object_begin(&jw, 0);
+ jw_object_intmax(&jw, "hash_version", ctx->bloom_settings->hash_version);
+ jw_object_intmax(&jw, "num_hashes", ctx->bloom_settings->num_hashes);
+ jw_object_intmax(&jw, "bits_per_entry", ctx->bloom_settings->bits_per_entry);
+ jw_object_intmax(&jw, "max_changed_paths", ctx->bloom_settings->max_changed_paths);
+ jw_end(&jw);
+
+ trace2_data_json("bloom", ctx->r, "settings", &jw);
+
+ jw_release(&jw);
+}
+
+static int write_graph_chunk_bloom_data(struct hashfile *f,
+ struct write_commit_graph_context *ctx)
{
struct commit **list = ctx->commits.list;
struct commit **last = ctx->commits.list + ctx->commits.nr;
- hashwrite_be32(f, settings->hash_version);
- hashwrite_be32(f, settings->num_hashes);
- hashwrite_be32(f, settings->bits_per_entry);
+ trace2_bloom_filter_settings(ctx);
+
+ hashwrite_be32(f, ctx->bloom_settings->hash_version);
+ hashwrite_be32(f, ctx->bloom_settings->num_hashes);
+ hashwrite_be32(f, ctx->bloom_settings->bits_per_entry);
while (list < last) {
- struct bloom_filter *filter = get_bloom_filter(ctx->r, *list, 0);
+ struct bloom_filter *filter = get_bloom_filter(ctx->r, *list);
+ size_t len = filter ? filter->len : 0;
+
display_progress(ctx->progress, ++ctx->progress_cnt);
- hashwrite(f, filter->data, filter->len * sizeof(unsigned char));
+ if (len)
+ hashwrite(f, filter->data, len * sizeof(unsigned char));
list++;
}
+
+ return 0;
}
static int oid_compare(const void *_a, const void *_b)
@@ -1231,8 +1293,8 @@ static void close_reachable(struct write_commit_graph_context *ctx)
{
int i;
struct commit *commit;
- enum commit_graph_split_flags flags = ctx->split_opts ?
- ctx->split_opts->flags : COMMIT_GRAPH_SPLIT_UNSPECIFIED;
+ enum commit_graph_split_flags flags = ctx->opts ?
+ ctx->opts->split_flags : COMMIT_GRAPH_SPLIT_UNSPECIFIED;
if (ctx->report_progress)
ctx->progress = start_delayed_progress(
@@ -1336,11 +1398,24 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
stop_progress(&ctx->progress);
}
+static void trace2_bloom_filter_write_statistics(struct write_commit_graph_context *ctx)
+{
+ trace2_data_intmax("commit-graph", ctx->r, "filter-computed",
+ ctx->count_bloom_filter_computed);
+ trace2_data_intmax("commit-graph", ctx->r, "filter-not-computed",
+ ctx->count_bloom_filter_not_computed);
+ trace2_data_intmax("commit-graph", ctx->r, "filter-trunc-empty",
+ ctx->count_bloom_filter_trunc_empty);
+ trace2_data_intmax("commit-graph", ctx->r, "filter-trunc-large",
+ ctx->count_bloom_filter_trunc_large);
+}
+
static void compute_bloom_filters(struct write_commit_graph_context *ctx)
{
int i;
struct progress *progress = NULL;
struct commit **sorted_commits;
+ int max_new_filters;
init_bloom_filters();
@@ -1357,13 +1432,34 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)
else
QSORT(sorted_commits, ctx->commits.nr, commit_gen_cmp);
+ max_new_filters = ctx->opts && ctx->opts->max_new_filters >= 0 ?
+ ctx->opts->max_new_filters : ctx->commits.nr;
+
for (i = 0; i < ctx->commits.nr; i++) {
+ enum bloom_filter_computed computed = 0;
struct commit *c = sorted_commits[i];
- struct bloom_filter *filter = get_bloom_filter(ctx->r, c, 1);
- ctx->total_bloom_filter_data_size += sizeof(unsigned char) * filter->len;
+ struct bloom_filter *filter = get_or_compute_bloom_filter(
+ ctx->r,
+ c,
+ ctx->count_bloom_filter_computed < max_new_filters,
+ ctx->bloom_settings,
+ &computed);
+ if (computed & BLOOM_COMPUTED) {
+ ctx->count_bloom_filter_computed++;
+ if (computed & BLOOM_TRUNC_EMPTY)
+ ctx->count_bloom_filter_trunc_empty++;
+ if (computed & BLOOM_TRUNC_LARGE)
+ ctx->count_bloom_filter_trunc_large++;
+ } else if (computed & BLOOM_NOT_COMPUTED)
+ ctx->count_bloom_filter_not_computed++;
+ ctx->total_bloom_filter_data_size += filter
+ ? sizeof(unsigned char) * filter->len : 0;
display_progress(progress, i + 1);
}
+ if (trace2_is_enabled())
+ trace2_bloom_filter_write_statistics(ctx);
+
free(sorted_commits);
stop_progress(&progress);
}
@@ -1392,7 +1488,7 @@ static int add_ref_to_set(const char *refname,
int write_commit_graph_reachable(struct object_directory *odb,
enum commit_graph_write_flags flags,
- const struct split_commit_graph_opts *split_opts)
+ const struct commit_graph_opts *opts)
{
struct oidset commits = OIDSET_INIT;
struct refs_cb_data data;
@@ -1409,7 +1505,7 @@ int write_commit_graph_reachable(struct object_directory *odb,
stop_progress(&data.progress);
result = write_commit_graph(odb, NULL, &commits,
- flags, split_opts);
+ flags, opts);
oidset_clear(&commits);
return result;
@@ -1524,8 +1620,8 @@ static uint32_t count_distinct_commits(struct write_commit_graph_context *ctx)
static void copy_oids_to_commits(struct write_commit_graph_context *ctx)
{
uint32_t i;
- enum commit_graph_split_flags flags = ctx->split_opts ?
- ctx->split_opts->flags : COMMIT_GRAPH_SPLIT_UNSPECIFIED;
+ enum commit_graph_split_flags flags = ctx->opts ?
+ ctx->opts->split_flags : COMMIT_GRAPH_SPLIT_UNSPECIFIED;
ctx->num_extra_edges = 0;
if (ctx->report_progress)
@@ -1586,19 +1682,27 @@ static int write_graph_chunk_base(struct hashfile *f,
return 0;
}
+typedef int (*chunk_write_fn)(struct hashfile *f,
+ struct write_commit_graph_context *ctx);
+
+struct chunk_info {
+ uint32_t id;
+ uint64_t size;
+ chunk_write_fn write_fn;
+};
+
static int write_commit_graph_file(struct write_commit_graph_context *ctx)
{
uint32_t i;
int fd;
struct hashfile *f;
struct lock_file lk = LOCK_INIT;
- uint32_t chunk_ids[MAX_NUM_CHUNKS + 1];
- uint64_t chunk_offsets[MAX_NUM_CHUNKS + 1];
+ struct chunk_info chunks[MAX_NUM_CHUNKS + 1];
const unsigned hashsz = the_hash_algo->rawsz;
struct strbuf progress_title = STRBUF_INIT;
int num_chunks = 3;
+ uint64_t chunk_offset;
struct object_id file_hash;
- const struct bloom_filter_settings bloom_settings = DEFAULT_BLOOM_FILTER_SETTINGS;
if (ctx->split) {
struct strbuf tmp_file = STRBUF_INIT;
@@ -1619,7 +1723,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
}
if (ctx->split) {
- char *lock_name = get_chain_filename(ctx->odb);
+ char *lock_name = get_commit_graph_chain_filename(ctx->odb);
hold_lock_file_for_update_mode(&lk, lock_name,
LOCK_DIE_ON_ERROR, 0444);
@@ -1644,51 +1748,41 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
}
- chunk_ids[0] = GRAPH_CHUNKID_OIDFANOUT;
- chunk_ids[1] = GRAPH_CHUNKID_OIDLOOKUP;
- chunk_ids[2] = GRAPH_CHUNKID_DATA;
+ chunks[0].id = GRAPH_CHUNKID_OIDFANOUT;
+ chunks[0].size = GRAPH_FANOUT_SIZE;
+ chunks[0].write_fn = write_graph_chunk_fanout;
+ chunks[1].id = GRAPH_CHUNKID_OIDLOOKUP;
+ chunks[1].size = hashsz * ctx->commits.nr;
+ chunks[1].write_fn = write_graph_chunk_oids;
+ chunks[2].id = GRAPH_CHUNKID_DATA;
+ chunks[2].size = (hashsz + 16) * ctx->commits.nr;
+ chunks[2].write_fn = write_graph_chunk_data;
if (ctx->num_extra_edges) {
- chunk_ids[num_chunks] = GRAPH_CHUNKID_EXTRAEDGES;
+ chunks[num_chunks].id = GRAPH_CHUNKID_EXTRAEDGES;
+ chunks[num_chunks].size = 4 * ctx->num_extra_edges;
+ chunks[num_chunks].write_fn = write_graph_chunk_extra_edges;
num_chunks++;
}
if (ctx->changed_paths) {
- chunk_ids[num_chunks] = GRAPH_CHUNKID_BLOOMINDEXES;
+ chunks[num_chunks].id = GRAPH_CHUNKID_BLOOMINDEXES;
+ chunks[num_chunks].size = sizeof(uint32_t) * ctx->commits.nr;
+ chunks[num_chunks].write_fn = write_graph_chunk_bloom_indexes;
num_chunks++;
- chunk_ids[num_chunks] = GRAPH_CHUNKID_BLOOMDATA;
+ chunks[num_chunks].id = GRAPH_CHUNKID_BLOOMDATA;
+ chunks[num_chunks].size = sizeof(uint32_t) * 3
+ + ctx->total_bloom_filter_data_size;
+ chunks[num_chunks].write_fn = write_graph_chunk_bloom_data;
num_chunks++;
}
if (ctx->num_commit_graphs_after > 1) {
- chunk_ids[num_chunks] = GRAPH_CHUNKID_BASE;
- num_chunks++;
- }
-
- chunk_ids[num_chunks] = 0;
-
- chunk_offsets[0] = 8 + (num_chunks + 1) * GRAPH_CHUNKLOOKUP_WIDTH;
- chunk_offsets[1] = chunk_offsets[0] + GRAPH_FANOUT_SIZE;
- chunk_offsets[2] = chunk_offsets[1] + hashsz * ctx->commits.nr;
- chunk_offsets[3] = chunk_offsets[2] + (hashsz + 16) * ctx->commits.nr;
-
- num_chunks = 3;
- if (ctx->num_extra_edges) {
- chunk_offsets[num_chunks + 1] = chunk_offsets[num_chunks] +
- 4 * ctx->num_extra_edges;
+ chunks[num_chunks].id = GRAPH_CHUNKID_BASE;
+ chunks[num_chunks].size = hashsz * (ctx->num_commit_graphs_after - 1);
+ chunks[num_chunks].write_fn = write_graph_chunk_base;
num_chunks++;
}
- if (ctx->changed_paths) {
- chunk_offsets[num_chunks + 1] = chunk_offsets[num_chunks] +
- sizeof(uint32_t) * ctx->commits.nr;
- num_chunks++;
- chunk_offsets[num_chunks + 1] = chunk_offsets[num_chunks] +
- sizeof(uint32_t) * 3 + ctx->total_bloom_filter_data_size;
- num_chunks++;
- }
- if (ctx->num_commit_graphs_after > 1) {
- chunk_offsets[num_chunks + 1] = chunk_offsets[num_chunks] +
- hashsz * (ctx->num_commit_graphs_after - 1);
- num_chunks++;
- }
+ chunks[num_chunks].id = 0;
+ chunks[num_chunks].size = 0;
hashwrite_be32(f, GRAPH_SIGNATURE);
@@ -1697,13 +1791,16 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
hashwrite_u8(f, num_chunks);
hashwrite_u8(f, ctx->num_commit_graphs_after - 1);
+ chunk_offset = 8 + (num_chunks + 1) * GRAPH_CHUNKLOOKUP_WIDTH;
for (i = 0; i <= num_chunks; i++) {
uint32_t chunk_write[3];
- chunk_write[0] = htonl(chunk_ids[i]);
- chunk_write[1] = htonl(chunk_offsets[i] >> 32);
- chunk_write[2] = htonl(chunk_offsets[i] & 0xffffffff);
+ chunk_write[0] = htonl(chunks[i].id);
+ chunk_write[1] = htonl(chunk_offset >> 32);
+ chunk_write[2] = htonl(chunk_offset & 0xffffffff);
hashwrite(f, chunk_write, 12);
+
+ chunk_offset += chunks[i].size;
}
if (ctx->report_progress) {
@@ -1716,19 +1813,19 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
progress_title.buf,
num_chunks * ctx->commits.nr);
}
- write_graph_chunk_fanout(f, ctx);
- write_graph_chunk_oids(f, hashsz, ctx);
- write_graph_chunk_data(f, hashsz, ctx);
- if (ctx->num_extra_edges)
- write_graph_chunk_extra_edges(f, ctx);
- if (ctx->changed_paths) {
- write_graph_chunk_bloom_indexes(f, ctx);
- write_graph_chunk_bloom_data(f, ctx, &bloom_settings);
- }
- if (ctx->num_commit_graphs_after > 1 &&
- write_graph_chunk_base(f, ctx)) {
- return -1;
+
+ for (i = 0; i < num_chunks; i++) {
+ uint64_t start_offset = f->total + f->offset;
+
+ if (chunks[i].write_fn(f, ctx))
+ return -1;
+
+ if (f->total + f->offset != start_offset + chunks[i].size)
+ BUG("expected to write %"PRId64" bytes to chunk %"PRIx32", but wrote %"PRId64" instead",
+ chunks[i].size, chunks[i].id,
+ f->total + f->offset - start_offset);
}
+
stop_progress(&ctx->progress);
strbuf_release(&progress_title);
@@ -1809,13 +1906,13 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
int max_commits = 0;
int size_mult = 2;
- if (ctx->split_opts) {
- max_commits = ctx->split_opts->max_commits;
+ if (ctx->opts) {
+ max_commits = ctx->opts->max_commits;
- if (ctx->split_opts->size_multiple)
- size_mult = ctx->split_opts->size_multiple;
+ if (ctx->opts->size_multiple)
+ size_mult = ctx->opts->size_multiple;
- flags = ctx->split_opts->flags;
+ flags = ctx->opts->split_flags;
}
g = ctx->r->objects->commit_graph;
@@ -1911,7 +2008,7 @@ static int commit_compare(const void *_a, const void *_b)
static void sort_and_scan_merged_commits(struct write_commit_graph_context *ctx)
{
- uint32_t i;
+ uint32_t i, dedup_i = 0;
if (ctx->report_progress)
ctx->progress = start_delayed_progress(
@@ -1926,17 +2023,27 @@ static void sort_and_scan_merged_commits(struct write_commit_graph_context *ctx)
if (i && oideq(&ctx->commits.list[i - 1]->object.oid,
&ctx->commits.list[i]->object.oid)) {
- die(_("unexpected duplicate commit id %s"),
- oid_to_hex(&ctx->commits.list[i]->object.oid));
+ /*
+ * Silently ignore duplicates. These were likely
+ * created due to a commit appearing in multiple
+ * layers of the chain, which is unexpected but
+ * not invalid. We should make sure there is a
+ * unique copy in the new layer.
+ */
} else {
unsigned int num_parents;
+ ctx->commits.list[dedup_i] = ctx->commits.list[i];
+ dedup_i++;
+
num_parents = commit_list_count(ctx->commits.list[i]->parents);
if (num_parents > 2)
ctx->num_extra_edges += num_parents - 1;
}
}
+ ctx->commits.nr = dedup_i;
+
stop_progress(&ctx->progress);
}
@@ -1993,10 +2100,10 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)
size_t dirnamelen;
timestamp_t expire_time = time(NULL);
- if (ctx->split_opts && ctx->split_opts->expire_time)
- expire_time = ctx->split_opts->expire_time;
+ if (ctx->opts && ctx->opts->expire_time)
+ expire_time = ctx->opts->expire_time;
if (!ctx->split) {
- char *chain_file_name = get_chain_filename(ctx->odb);
+ char *chain_file_name = get_commit_graph_chain_filename(ctx->odb);
unlink(chain_file_name);
free(chain_file_name);
ctx->num_commit_graphs_after = 0;
@@ -2045,13 +2152,19 @@ int write_commit_graph(struct object_directory *odb,
struct string_list *pack_indexes,
struct oidset *commits,
enum commit_graph_write_flags flags,
- const struct split_commit_graph_opts *split_opts)
+ const struct commit_graph_opts *opts)
{
struct write_commit_graph_context *ctx;
uint32_t i, count_distinct = 0;
int res = 0;
int replace = 0;
+ struct bloom_filter_settings bloom_settings = DEFAULT_BLOOM_FILTER_SETTINGS;
+ prepare_repo_settings(the_repository);
+ if (!the_repository->settings.core_commit_graph) {
+ warning(_("attempting to write a commit-graph, but 'core.commitGraph' is disabled"));
+ return 0;
+ }
if (!commit_graph_compatible(the_repository))
return 0;
@@ -2061,10 +2174,32 @@ int write_commit_graph(struct object_directory *odb,
ctx->append = flags & COMMIT_GRAPH_WRITE_APPEND ? 1 : 0;
ctx->report_progress = flags & COMMIT_GRAPH_WRITE_PROGRESS ? 1 : 0;
ctx->split = flags & COMMIT_GRAPH_WRITE_SPLIT ? 1 : 0;
- ctx->split_opts = split_opts;
- ctx->changed_paths = flags & COMMIT_GRAPH_WRITE_BLOOM_FILTERS ? 1 : 0;
+ ctx->opts = opts;
ctx->total_bloom_filter_data_size = 0;
+ bloom_settings.bits_per_entry = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_BITS_PER_ENTRY",
+ bloom_settings.bits_per_entry);
+ bloom_settings.num_hashes = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_NUM_HASHES",
+ bloom_settings.num_hashes);
+ bloom_settings.max_changed_paths = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS",
+ bloom_settings.max_changed_paths);
+ ctx->bloom_settings = &bloom_settings;
+
+ if (flags & COMMIT_GRAPH_WRITE_BLOOM_FILTERS)
+ 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;
+
+ /* We have changed-paths already. Keep them in the next graph */
+ if (g && g->chunk_bloom_data) {
+ ctx->changed_paths = 1;
+ ctx->bloom_settings = g->bloom_filter_settings;
+ }
+ }
+
if (ctx->split) {
struct commit_graph *g;
prepare_commit_graph(ctx->r);
@@ -2087,15 +2222,15 @@ int write_commit_graph(struct object_directory *odb,
}
}
- if (ctx->split_opts)
- replace = ctx->split_opts->flags & COMMIT_GRAPH_SPLIT_REPLACE;
+ if (ctx->opts)
+ replace = ctx->opts->split_flags & COMMIT_GRAPH_SPLIT_REPLACE;
}
ctx->approx_nr_objects = approximate_object_count();
ctx->oids.alloc = ctx->approx_nr_objects / 32;
- if (ctx->split && split_opts && ctx->oids.alloc > split_opts->max_commits)
- ctx->oids.alloc = split_opts->max_commits;
+ if (ctx->split && opts && ctx->oids.alloc > opts->max_commits)
+ ctx->oids.alloc = opts->max_commits;
if (ctx->append) {
prepare_commit_graph_one(ctx->r, ctx->odb);