/* Remember to update object flag allocation in object.h */
#define REACHABLE (1u<<15)
-char *get_commit_graph_filename(const char *obj_dir)
+char *get_commit_graph_filename(struct object_directory *odb)
{
- char *filename = xstrfmt("%s/info/commit-graph", obj_dir);
- char *normalized = xmalloc(strlen(filename) + 1);
- normalize_path_copy(normalized, filename);
- free(filename);
- return normalized;
+ return xstrfmt("%s/info/commit-graph", odb->path);
}
-static char *get_split_graph_filename(const char *obj_dir,
+static char *get_split_graph_filename(struct object_directory *odb,
const char *oid_hex)
{
- char *filename = xstrfmt("%s/info/commit-graphs/graph-%s.graph",
- obj_dir,
- oid_hex);
- char *normalized = xmalloc(strlen(filename) + 1);
- normalize_path_copy(normalized, filename);
- free(filename);
- return normalized;
+ return xstrfmt("%s/info/commit-graphs/graph-%s.graph", odb->path,
+ oid_hex);
}
-static char *get_chain_filename(const char *obj_dir)
+static char *get_chain_filename(struct object_directory *odb)
{
- return xstrfmt("%s/info/commit-graphs/commit-graph-chain", obj_dir);
+ return xstrfmt("%s/info/commit-graphs/commit-graph-chain", odb->path);
}
static uint8_t oid_version(void)
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(int fd, struct stat *st,
+ struct object_directory *odb)
{
void *graph_map;
size_t graph_size;
graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
ret = parse_commit_graph(graph_map, fd, graph_size);
- if (!ret) {
+ if (ret)
+ ret->odb = odb;
+ else {
munmap(graph_map, graph_size);
close(fd);
}
return graph;
}
-static struct commit_graph *load_commit_graph_one(const char *graph_file)
+static struct commit_graph *load_commit_graph_one(const char *graph_file,
+ struct object_directory *odb)
{
struct stat st;
if (!open_ok)
return NULL;
- g = load_commit_graph_one_fd_st(fd, &st);
+ g = load_commit_graph_one_fd_st(fd, &st, odb);
if (g)
g->filename = xstrdup(graph_file);
return g;
}
-static struct commit_graph *load_commit_graph_v1(struct repository *r, const char *obj_dir)
+static struct commit_graph *load_commit_graph_v1(struct repository *r,
+ struct object_directory *odb)
{
- char *graph_name = get_commit_graph_filename(obj_dir);
- struct commit_graph *g = load_commit_graph_one(graph_name);
+ char *graph_name = get_commit_graph_filename(odb);
+ struct commit_graph *g = load_commit_graph_one(graph_name, odb);
free(graph_name);
- if (g)
- g->obj_dir = obj_dir;
-
return g;
}
return 1;
}
-static struct commit_graph *load_commit_graph_chain(struct repository *r, const char *obj_dir)
+static struct commit_graph *load_commit_graph_chain(struct repository *r,
+ struct object_directory *odb)
{
struct commit_graph *graph_chain = NULL;
struct strbuf line = STRBUF_INIT;
struct stat st;
struct object_id *oids;
int i = 0, valid = 1, count;
- char *chain_name = get_chain_filename(obj_dir);
+ char *chain_name = get_chain_filename(odb);
FILE *fp;
int stat_res;
valid = 0;
for (odb = r->objects->odb; odb; odb = odb->next) {
- char *graph_name = get_split_graph_filename(odb->path, line.buf);
- struct commit_graph *g = load_commit_graph_one(graph_name);
+ char *graph_name = get_split_graph_filename(odb, line.buf);
+ struct commit_graph *g = load_commit_graph_one(graph_name, odb);
free(graph_name);
if (g) {
- g->obj_dir = odb->path;
-
if (add_graph_to_chain(g, graph_chain, oids, i)) {
graph_chain = g;
valid = 1;
return graph_chain;
}
-struct commit_graph *read_commit_graph_one(struct repository *r, const char *obj_dir)
+struct commit_graph *read_commit_graph_one(struct repository *r,
+ struct object_directory *odb)
{
- struct commit_graph *g = load_commit_graph_v1(r, obj_dir);
+ struct commit_graph *g = load_commit_graph_v1(r, odb);
if (!g)
- g = load_commit_graph_chain(r, obj_dir);
+ g = load_commit_graph_chain(r, odb);
return g;
}
-static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
+static void prepare_commit_graph_one(struct repository *r,
+ struct object_directory *odb)
{
if (r->objects->commit_graph)
return;
- r->objects->commit_graph = read_commit_graph_one(r, obj_dir);
+ r->objects->commit_graph = read_commit_graph_one(r, odb);
}
/*
for (odb = r->objects->odb;
!r->objects->commit_graph && odb;
odb = odb->next)
- prepare_commit_graph_one(r, odb->path);
+ prepare_commit_graph_one(r, odb);
return !!r->objects->commit_graph;
}
struct write_commit_graph_context {
struct repository *r;
- char *obj_dir;
+ struct object_directory *odb;
char *graph_name;
struct packed_oid_list oids;
struct packed_commit_list commits;
if (edge_value >= 0)
edge_value += ctx->new_num_commits_in_base;
- else {
+ else if (ctx->new_base_graph) {
uint32_t pos;
if (find_commit_in_graph(parent->item,
ctx->new_base_graph,
if (edge_value >= 0)
edge_value += ctx->new_num_commits_in_base;
- else {
+ else if (ctx->new_base_graph) {
uint32_t pos;
if (find_commit_in_graph(parent->item,
ctx->new_base_graph,
if (edge_value >= 0)
edge_value += ctx->new_num_commits_in_base;
- else {
+ else if (ctx->new_base_graph) {
uint32_t pos;
if (find_commit_in_graph(parent->item,
ctx->new_base_graph,
{
int i;
struct commit *commit;
+ enum commit_graph_split_flags flags = ctx->split_opts ?
+ ctx->split_opts->flags : COMMIT_GRAPH_SPLIT_UNSPECIFIED;
if (ctx->report_progress)
ctx->progress = start_delayed_progress(
if (!commit)
continue;
if (ctx->split) {
- if (!parse_commit(commit) &&
- commit->graph_pos == COMMIT_NOT_FROM_GRAPH)
+ if ((!parse_commit(commit) &&
+ commit->graph_pos == COMMIT_NOT_FROM_GRAPH) ||
+ flags == COMMIT_GRAPH_SPLIT_REPLACE)
add_missing_parents(ctx, commit);
} else if (!parse_commit_no_graph(commit))
add_missing_parents(ctx, commit);
return 0;
}
-int write_commit_graph_reachable(const char *obj_dir,
+int write_commit_graph_reachable(struct object_directory *odb,
enum commit_graph_write_flags flags,
const struct split_commit_graph_opts *split_opts)
{
int result;
for_each_ref(add_ref_to_list, &list);
- result = write_commit_graph(obj_dir, NULL, &list,
+ result = write_commit_graph(odb, NULL, &list,
flags, split_opts);
string_list_clear(&list, 0);
struct strbuf packname = STRBUF_INIT;
int dirlen;
- strbuf_addf(&packname, "%s/pack/", ctx->obj_dir);
+ strbuf_addf(&packname, "%s/pack/", ctx->odb->path);
dirlen = packname.len;
if (ctx->report_progress) {
strbuf_addf(&progress_title,
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;
ctx->num_extra_edges = 0;
if (ctx->report_progress)
ALLOC_GROW(ctx->commits.list, ctx->commits.nr + 1, ctx->commits.alloc);
ctx->commits.list[ctx->commits.nr] = lookup_commit(ctx->r, &ctx->oids.list[i]);
- if (ctx->split &&
+ if (ctx->split && flags != COMMIT_GRAPH_SPLIT_REPLACE &&
ctx->commits.list[ctx->commits.nr]->graph_pos != COMMIT_NOT_FROM_GRAPH)
continue;
- parse_commit_no_graph(ctx->commits.list[ctx->commits.nr]);
+ if (ctx->split && flags == COMMIT_GRAPH_SPLIT_REPLACE)
+ parse_commit(ctx->commits.list[ctx->commits.nr]);
+ else
+ parse_commit_no_graph(ctx->commits.list[ctx->commits.nr]);
num_parents = commit_list_count(ctx->commits.list[ctx->commits.nr]->parents);
if (num_parents > 2)
strbuf_addf(&tmp_file,
"%s/info/commit-graphs/tmp_graph_XXXXXX",
- ctx->obj_dir);
+ ctx->odb->path);
ctx->graph_name = strbuf_detach(&tmp_file, NULL);
} else {
- ctx->graph_name = get_commit_graph_filename(ctx->obj_dir);
+ ctx->graph_name = get_commit_graph_filename(ctx->odb);
}
if (safe_create_leading_directories(ctx->graph_name)) {
}
if (ctx->split) {
- char *lock_name = get_chain_filename(ctx->obj_dir);
+ char *lock_name = get_chain_filename(ctx->odb);
hold_lock_file_for_update(&lk, lock_name, LOCK_DIE_ON_ERROR);
if (ctx->split && ctx->base_graph_name && ctx->num_commit_graphs_after > 1) {
char *new_base_hash = xstrdup(oid_to_hex(&ctx->new_base_graph->oid));
- char *new_base_name = get_split_graph_filename(ctx->new_base_graph->obj_dir, new_base_hash);
+ char *new_base_name = get_split_graph_filename(ctx->new_base_graph->odb, new_base_hash);
free(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 2]);
free(ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 2]);
}
if (ctx->base_graph_name) {
- const char *dest = ctx->commit_graph_filenames_after[
- ctx->num_commit_graphs_after - 2];
+ const char *dest;
+ int idx = ctx->num_commit_graphs_after - 1;
+ if (ctx->num_commit_graphs_after > 1)
+ idx--;
+
+ dest = ctx->commit_graph_filenames_after[idx];
if (strcmp(ctx->base_graph_name, dest)) {
result = rename(ctx->base_graph_name, dest);
}
}
} else {
- char *graph_name = get_commit_graph_filename(ctx->obj_dir);
+ char *graph_name = get_commit_graph_filename(ctx->odb);
unlink(graph_name);
}
ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(oid_to_hex(&file_hash));
- final_graph_name = get_split_graph_filename(ctx->obj_dir,
+ final_graph_name = get_split_graph_filename(ctx->odb,
ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);
ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1] = final_graph_name;
{
struct commit_graph *g;
uint32_t num_commits;
+ enum commit_graph_split_flags flags = COMMIT_GRAPH_SPLIT_UNSPECIFIED;
uint32_t i;
int max_commits = 0;
if (ctx->split_opts) {
max_commits = ctx->split_opts->max_commits;
- size_mult = ctx->split_opts->size_multiple;
+
+ if (ctx->split_opts->size_multiple)
+ size_mult = ctx->split_opts->size_multiple;
+
+ flags = ctx->split_opts->flags;
}
g = ctx->r->objects->commit_graph;
num_commits = ctx->commits.nr;
- ctx->num_commit_graphs_after = ctx->num_commit_graphs_before + 1;
-
- while (g && (g->num_commits <= size_mult * num_commits ||
- (max_commits && num_commits > max_commits))) {
- if (strcmp(g->obj_dir, ctx->obj_dir))
- break;
+ if (flags == COMMIT_GRAPH_SPLIT_REPLACE)
+ ctx->num_commit_graphs_after = 1;
+ else
+ ctx->num_commit_graphs_after = ctx->num_commit_graphs_before + 1;
+
+ if (flags != COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED &&
+ flags != COMMIT_GRAPH_SPLIT_REPLACE) {
+ while (g && (g->num_commits <= size_mult * num_commits ||
+ (max_commits && num_commits > max_commits))) {
+ if (g->odb != ctx->odb)
+ break;
- num_commits += g->num_commits;
- g = g->base_graph;
+ num_commits += g->num_commits;
+ g = g->base_graph;
- ctx->num_commit_graphs_after--;
+ ctx->num_commit_graphs_after--;
+ }
}
- ctx->new_base_graph = g;
+ if (flags != COMMIT_GRAPH_SPLIT_REPLACE)
+ ctx->new_base_graph = g;
+ else if (ctx->num_commit_graphs_after != 1)
+ BUG("split_graph_merge_strategy: num_commit_graphs_after "
+ "should be 1 with --split=replace");
if (ctx->num_commit_graphs_after == 2) {
- char *old_graph_name = get_commit_graph_filename(g->obj_dir);
+ char *old_graph_name = get_commit_graph_filename(g->odb);
if (!strcmp(g->filename, old_graph_name) &&
- strcmp(g->obj_dir, ctx->obj_dir)) {
+ g->odb != ctx->odb) {
ctx->num_commit_graphs_after = 1;
ctx->new_base_graph = NULL;
}
if (ctx->split_opts && ctx->split_opts->expire_time)
expire_time -= ctx->split_opts->expire_time;
if (!ctx->split) {
- char *chain_file_name = get_chain_filename(ctx->obj_dir);
+ char *chain_file_name = get_chain_filename(ctx->odb);
unlink(chain_file_name);
free(chain_file_name);
ctx->num_commit_graphs_after = 0;
}
- strbuf_addstr(&path, ctx->obj_dir);
+ strbuf_addstr(&path, ctx->odb->path);
strbuf_addstr(&path, "/info/commit-graphs");
dir = opendir(path.buf);
strbuf_release(&path);
}
-int write_commit_graph(const char *obj_dir,
+int write_commit_graph(struct object_directory *odb,
struct string_list *pack_indexes,
struct string_list *commit_hex,
enum commit_graph_write_flags flags,
{
struct write_commit_graph_context *ctx;
uint32_t i, count_distinct = 0;
- size_t len;
int res = 0;
+ int replace = 0;
if (!commit_graph_compatible(the_repository))
return 0;
ctx = xcalloc(1, sizeof(struct write_commit_graph_context));
ctx->r = the_repository;
-
- /* normalize object dir with no trailing slash */
- ctx->obj_dir = xmallocz(strlen(obj_dir) + 1);
- normalize_path_copy(ctx->obj_dir, obj_dir);
- len = strlen(ctx->obj_dir);
- if (len && ctx->obj_dir[len - 1] == '/')
- ctx->obj_dir[len - 1] = 0;
-
+ ctx->odb = 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;
g = g->base_graph;
}
}
+
+ if (ctx->split_opts)
+ replace = ctx->split_opts->flags & COMMIT_GRAPH_SPLIT_REPLACE;
}
ctx->approx_nr_objects = approximate_object_count();
ctx->oids.alloc = split_opts->max_commits;
if (ctx->append) {
- prepare_commit_graph_one(ctx->r, ctx->obj_dir);
+ prepare_commit_graph_one(ctx->r, ctx->odb);
if (ctx->r->objects->commit_graph)
ctx->oids.alloc += ctx->r->objects->commit_graph->num_commits;
}
goto cleanup;
}
- if (!ctx->commits.nr)
+ if (!ctx->commits.nr && !replace)
goto cleanup;
if (ctx->split) {
split_graph_merge_strategy(ctx);
- merge_commit_graphs(ctx);
+ if (!replace)
+ merge_commit_graphs(ctx);
} else
ctx->num_commit_graphs_after = 1;
free(ctx->graph_name);
free(ctx->commits.list);
free(ctx->oids.list);
- free(ctx->obj_dir);
if (ctx->commit_graph_filenames_after) {
for (i = 0; i < ctx->num_commit_graphs_after; i++) {