1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-22 01:36:09 +02:00

Merge branch 'jt/commit-graph-per-object-store'

The singleton commit-graph in-core instance is made per in-core
repository instance.

* jt/commit-graph-per-object-store:
  commit-graph: add repo arg to graph readers
  commit-graph: store graph in struct object_store
  commit-graph: add free_commit_graph
  commit-graph: add missing forward declaration
  object-store: add missing include
  commit-graph: refactor preparing commit graph
This commit is contained in:
Junio C Hamano 2018-08-02 15:30:47 -07:00
commit 78a72ad4f8
16 changed files with 207 additions and 62 deletions

View File

@ -719,6 +719,7 @@ TEST_BUILTINS_OBJS += test-prio-queue.o
TEST_BUILTINS_OBJS += test-read-cache.o
TEST_BUILTINS_OBJS += test-ref-store.o
TEST_BUILTINS_OBJS += test-regex.o
TEST_BUILTINS_OBJS += test-repository.o
TEST_BUILTINS_OBJS += test-revision-walking.o
TEST_BUILTINS_OBJS += test-run-command.o
TEST_BUILTINS_OBJS += test-scrap-cache-tree.o

View File

@ -115,6 +115,8 @@ static int graph_read(int argc, const char **argv)
printf(" large_edges");
printf("\n");
free_commit_graph(graph);
return 0;
}

View File

@ -830,7 +830,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
check_connectivity();
if (core_commit_graph) {
if (!git_config_get_bool("core.commitgraph", &i) && i) {
struct child_process commit_graph_verify = CHILD_PROCESS_INIT;
const char *verify_argv[] = { "commit-graph", "verify", NULL, NULL, NULL };

View File

@ -877,7 +877,6 @@ extern char *git_replace_ref_base;
extern int fsync_object_files;
extern int core_preload_index;
extern int core_commit_graph;
extern int core_apply_sparse_checkout;
extern int precomposed_unicode;
extern int protect_hfs;

View File

@ -183,53 +183,60 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
exit(1);
}
/* global storage */
static struct commit_graph *commit_graph = NULL;
static void prepare_commit_graph_one(const char *obj_dir)
static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
{
char *graph_name;
if (commit_graph)
if (r->objects->commit_graph)
return;
graph_name = get_commit_graph_filename(obj_dir);
commit_graph = load_commit_graph_one(graph_name);
r->objects->commit_graph =
load_commit_graph_one(graph_name);
FREE_AND_NULL(graph_name);
}
static int prepare_commit_graph_run_once = 0;
static void prepare_commit_graph(void)
/*
* Return 1 if commit_graph is non-NULL, and 0 otherwise.
*
* On the first invocation, this function attemps to load the commit
* graph if the_repository is configured to have one.
*/
static int prepare_commit_graph(struct repository *r)
{
struct alternate_object_database *alt;
char *obj_dir;
int config_value;
if (prepare_commit_graph_run_once)
return;
prepare_commit_graph_run_once = 1;
if (r->objects->commit_graph_attempted)
return !!r->objects->commit_graph;
r->objects->commit_graph_attempted = 1;
obj_dir = get_object_directory();
prepare_commit_graph_one(obj_dir);
prepare_alt_odb(the_repository);
for (alt = the_repository->objects->alt_odb_list;
!commit_graph && alt;
if (repo_config_get_bool(r, "core.commitgraph", &config_value) ||
!config_value)
/*
* This repository is not configured to use commit graphs, so
* do not load one. (But report commit_graph_attempted anyway
* so that commit graph loading is not attempted again for this
* repository.)
*/
return 0;
obj_dir = r->objects->objectdir;
prepare_commit_graph_one(r, obj_dir);
prepare_alt_odb(r);
for (alt = r->objects->alt_odb_list;
!r->objects->commit_graph && alt;
alt = alt->next)
prepare_commit_graph_one(alt->path);
prepare_commit_graph_one(r, alt->path);
return !!r->objects->commit_graph;
}
static void close_commit_graph(void)
{
if (!commit_graph)
return;
if (commit_graph->graph_fd >= 0) {
munmap((void *)commit_graph->data, commit_graph->data_len);
commit_graph->data = NULL;
close(commit_graph->graph_fd);
}
FREE_AND_NULL(commit_graph);
free_commit_graph(the_repository->objects->commit_graph);
the_repository->objects->commit_graph = NULL;
}
static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t *pos)
@ -324,8 +331,6 @@ static int parse_commit_in_graph_one(struct commit_graph *g, struct commit *item
{
uint32_t pos;
if (!core_commit_graph)
return 0;
if (item->object.parsed)
return 1;
@ -335,25 +340,20 @@ static int parse_commit_in_graph_one(struct commit_graph *g, struct commit *item
return 0;
}
int parse_commit_in_graph(struct commit *item)
int parse_commit_in_graph(struct repository *r, struct commit *item)
{
if (!core_commit_graph)
if (!prepare_commit_graph(r))
return 0;
prepare_commit_graph();
if (commit_graph)
return parse_commit_in_graph_one(commit_graph, item);
return 0;
return parse_commit_in_graph_one(r->objects->commit_graph, item);
}
void load_commit_graph_info(struct commit *item)
void load_commit_graph_info(struct repository *r, struct commit *item)
{
uint32_t pos;
if (!core_commit_graph)
if (!prepare_commit_graph(r))
return;
prepare_commit_graph();
if (commit_graph && find_commit_in_graph(item, commit_graph, &pos))
fill_commit_graph_info(item, commit_graph, pos);
if (find_commit_in_graph(item, r->objects->commit_graph, &pos))
fill_commit_graph_info(item, r->objects->commit_graph, pos);
}
static struct tree *load_tree_for_commit(struct commit_graph *g, struct commit *c)
@ -379,9 +379,9 @@ static struct tree *get_commit_tree_in_graph_one(struct commit_graph *g,
return load_tree_for_commit(g, (struct commit *)c);
}
struct tree *get_commit_tree_in_graph(const struct commit *c)
struct tree *get_commit_tree_in_graph(struct repository *r, const struct commit *c)
{
return get_commit_tree_in_graph_one(commit_graph, c);
return get_commit_tree_in_graph_one(r->objects->commit_graph, c);
}
static void write_graph_chunk_fanout(struct hashfile *f,
@ -697,16 +697,18 @@ void write_commit_graph(const char *obj_dir,
oids.alloc = approximate_object_count() / 4;
if (append) {
prepare_commit_graph_one(obj_dir);
if (commit_graph)
oids.alloc += commit_graph->num_commits;
prepare_commit_graph_one(the_repository, obj_dir);
if (the_repository->objects->commit_graph)
oids.alloc += the_repository->objects->commit_graph->num_commits;
}
if (oids.alloc < 1024)
oids.alloc = 1024;
ALLOC_ARRAY(oids.list, oids.alloc);
if (append && commit_graph) {
if (append && the_repository->objects->commit_graph) {
struct commit_graph *commit_graph =
the_repository->objects->commit_graph;
for (i = 0; i < commit_graph->num_commits; i++) {
const unsigned char *hash = commit_graph->chunk_oid_lookup +
commit_graph->hash_len * i;
@ -1027,3 +1029,15 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
return verify_commit_graph_error;
}
void free_commit_graph(struct commit_graph *g)
{
if (!g)
return;
if (g->graph_fd >= 0) {
munmap((void *)g->data, g->data_len);
g->data = NULL;
close(g->graph_fd);
}
free(g);
}

View File

@ -5,6 +5,8 @@
#include "repository.h"
#include "string-list.h"
struct commit;
char *get_commit_graph_filename(const char *obj_dir);
/*
@ -17,7 +19,7 @@ char *get_commit_graph_filename(const char *obj_dir);
*
* See parse_commit_buffer() for the fallback after this call.
*/
int parse_commit_in_graph(struct commit *item);
int parse_commit_in_graph(struct repository *r, struct commit *item);
/*
* It is possible that we loaded commit contents from the commit buffer,
@ -25,9 +27,10 @@ int parse_commit_in_graph(struct commit *item);
* checked and filled. Fill the graph_pos and generation members of
* the given commit.
*/
void load_commit_graph_info(struct commit *item);
void load_commit_graph_info(struct repository *r, struct commit *item);
struct tree *get_commit_tree_in_graph(const struct commit *c);
struct tree *get_commit_tree_in_graph(struct repository *r,
const struct commit *c);
struct commit_graph {
int graph_fd;
@ -56,4 +59,6 @@ void write_commit_graph(const char *obj_dir,
int verify_commit_graph(struct repository *r, struct commit_graph *g);
void free_commit_graph(struct commit_graph *);
#endif

View File

@ -342,7 +342,7 @@ struct tree *get_commit_tree(const struct commit *commit)
if (commit->graph_pos == COMMIT_NOT_FROM_GRAPH)
BUG("commit has NULL tree, but was not loaded from commit-graph");
return get_commit_tree_in_graph(commit);
return get_commit_tree_in_graph(the_repository, commit);
}
struct object_id *get_commit_tree_oid(const struct commit *commit)
@ -438,7 +438,7 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
item->date = parse_commit_date(bufptr, tail);
if (check_graph)
load_commit_graph_info(item);
load_commit_graph_info(the_repository, item);
return 0;
}
@ -454,7 +454,7 @@ int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_com
return -1;
if (item->object.parsed)
return 0;
if (use_commit_graph && parse_commit_in_graph(item))
if (use_commit_graph && parse_commit_in_graph(the_repository, item))
return 0;
buffer = read_object_file(&item->object.oid, &type, &size);
if (!buffer)

View File

@ -1320,11 +1320,6 @@ static int git_default_core_config(const char *var, const char *value)
return 0;
}
if (!strcmp(var, "core.commitgraph")) {
core_commit_graph = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "core.sparsecheckout")) {
core_apply_sparse_checkout = git_config_bool(var, value);
return 0;

View File

@ -66,7 +66,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
char *notes_ref_name;
int grafts_replace_parents = 1;
int core_commit_graph;
int core_apply_sparse_checkout;
int merge_log_config = -1;
int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */

View File

@ -2,6 +2,9 @@
#define OBJECT_STORE_H
#include "oidmap.h"
#include "list.h"
#include "sha1-array.h"
#include "strbuf.h"
struct alternate_object_database {
struct alternate_object_database *next;
@ -103,6 +106,9 @@ struct raw_object_store {
*/
struct oidmap *replace_map;
struct commit_graph *commit_graph;
unsigned commit_graph_attempted : 1; /* if loading has been attempted */
/*
* private data
*

View File

@ -9,6 +9,7 @@
#include "alloc.h"
#include "object-store.h"
#include "packfile.h"
#include "commit-graph.h"
unsigned int get_max_object_index(void)
{
@ -507,6 +508,10 @@ void raw_object_store_clear(struct raw_object_store *o)
oidmap_free(o->replace_map, 1);
FREE_AND_NULL(o->replace_map);
free_commit_graph(o->commit_graph);
o->commit_graph = NULL;
o->commit_graph_attempted = 0;
free_alt_odbs(o);
o->alt_odb_tail = NULL;

View File

@ -1713,7 +1713,7 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
for (p = want; p; p = p->next) {
struct commit *c = p->item;
load_commit_graph_info(c);
load_commit_graph_info(the_repository, c);
if (c->generation < cutoff)
cutoff = c->generation;
}

View File

@ -0,0 +1,82 @@
#include "test-tool.h"
#include "cache.h"
#include "commit-graph.h"
#include "commit.h"
#include "config.h"
#include "object-store.h"
#include "object.h"
#include "repository.h"
#include "tree.h"
static void test_parse_commit_in_graph(const char *gitdir, const char *worktree,
const struct object_id *commit_oid)
{
struct repository r;
struct commit *c;
struct commit_list *parent;
repo_init(&r, gitdir, worktree);
c = lookup_commit(&r, commit_oid);
if (!parse_commit_in_graph(&r, c))
die("Couldn't parse commit");
printf("%"PRItime, c->date);
for (parent = c->parents; parent; parent = parent->next)
printf(" %s", oid_to_hex(&parent->item->object.oid));
printf("\n");
repo_clear(&r);
}
static void test_get_commit_tree_in_graph(const char *gitdir,
const char *worktree,
const struct object_id *commit_oid)
{
struct repository r;
struct commit *c;
struct tree *tree;
repo_init(&r, gitdir, worktree);
c = lookup_commit(&r, commit_oid);
/*
* get_commit_tree_in_graph does not automatically parse the commit, so
* parse it first.
*/
if (!parse_commit_in_graph(&r, c))
die("Couldn't parse commit");
tree = get_commit_tree_in_graph(&r, c);
if (!tree)
die("Couldn't get commit tree");
printf("%s\n", oid_to_hex(&tree->object.oid));
repo_clear(&r);
}
int cmd__repository(int argc, const char **argv)
{
if (argc < 2)
die("must have at least 2 arguments");
if (!strcmp(argv[1], "parse_commit_in_graph")) {
struct object_id oid;
if (argc < 5)
die("not enough arguments");
if (parse_oid_hex(argv[4], &oid, &argv[4]))
die("cannot parse oid '%s'", argv[4]);
test_parse_commit_in_graph(argv[2], argv[3], &oid);
} else if (!strcmp(argv[1], "get_commit_tree_in_graph")) {
struct object_id oid;
if (argc < 5)
die("not enough arguments");
if (parse_oid_hex(argv[4], &oid, &argv[4]))
die("cannot parse oid '%s'", argv[4]);
test_get_commit_tree_in_graph(argv[2], argv[3], &oid);
} else {
die("unrecognized '%s'", argv[1]);
}
return 0;
}

View File

@ -29,6 +29,7 @@ static struct test_cmd cmds[] = {
{ "read-cache", cmd__read_cache },
{ "ref-store", cmd__ref_store },
{ "regex", cmd__regex },
{ "repository", cmd__repository },
{ "revision-walking", cmd__revision_walking },
{ "run-command", cmd__run_command },
{ "scrap-cache-tree", cmd__scrap_cache_tree },

View File

@ -23,6 +23,7 @@ int cmd__prio_queue(int argc, const char **argv);
int cmd__read_cache(int argc, const char **argv);
int cmd__ref_store(int argc, const char **argv);
int cmd__regex(int argc, const char **argv);
int cmd__repository(int argc, const char **argv);
int cmd__revision_walking(int argc, const char **argv);
int cmd__run_command(int argc, const char **argv);
int cmd__scrap_cache_tree(int argc, const char **argv);

View File

@ -431,4 +431,39 @@ test_expect_success 'git fsck (checks commit-graph)' '
test_must_fail git fsck
'
test_expect_success 'setup non-the_repository tests' '
rm -rf repo &&
git init repo &&
test_commit -C repo one &&
test_commit -C repo two &&
git -C repo config core.commitGraph true &&
git -C repo rev-parse two | \
git -C repo commit-graph write --stdin-commits
'
test_expect_success 'parse_commit_in_graph works for non-the_repository' '
test-tool repository parse_commit_in_graph \
repo/.git repo "$(git -C repo rev-parse two)" >actual &&
echo $(git -C repo log --pretty="%ct" -1) \
$(git -C repo rev-parse one) >expect &&
test_cmp expect actual &&
test-tool repository parse_commit_in_graph \
repo/.git repo "$(git -C repo rev-parse one)" >actual &&
echo $(git -C repo log --pretty="%ct" -1 one) >expect &&
test_cmp expect actual
'
test_expect_success 'get_commit_tree_in_graph works for non-the_repository' '
test-tool repository get_commit_tree_in_graph \
repo/.git repo "$(git -C repo rev-parse two)" >actual &&
echo $(git -C repo rev-parse two^{tree}) >expect &&
test_cmp expect actual &&
test-tool repository get_commit_tree_in_graph \
repo/.git repo "$(git -C repo rev-parse one)" >actual &&
echo $(git -C repo rev-parse one^{tree}) >expect &&
test_cmp expect actual
'
test_done