From: Junio C Hamano Date: Tue, 4 Sep 2018 21:31:39 +0000 (-0700) Subject: Merge branch 'ds/commit-graph-lockfile-fix' X-Git-Tag: v2.19.0-rc2~4 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/0a866db570e520ce7b08d1eceefdeaa9d63b6704?ds=inline;hp=-c Merge branch 'ds/commit-graph-lockfile-fix' "git merge-base" in 2.19-rc1 has performance regression when the (experimental) commit-graph feature is in use, which has been mitigated. * ds/commit-graph-lockfile-fix: commit: don't use generation numbers if not needed --- 0a866db570e520ce7b08d1eceefdeaa9d63b6704 diff --combined commit.c index 1a6e632185,23db654d64..449c1f4920 --- a/commit.c +++ b/commit.c @@@ -2,21 -2,17 +2,21 @@@ #include "tag.h" #include "commit.h" #include "commit-graph.h" +#include "repository.h" +#include "object-store.h" #include "pkt-line.h" #include "utf8.h" #include "diff.h" #include "revision.h" #include "notes.h" +#include "alloc.h" #include "gpg-interface.h" #include "mergesort.h" #include "commit-slab.h" #include "prio-queue.h" #include "sha1-lookup.h" #include "wt-status.h" +#include "advice.h" static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **); @@@ -24,26 -20,24 +24,26 @@@ int save_commit_buffer = 1 const char *commit_type = "commit"; -struct commit *lookup_commit_reference_gently(const struct object_id *oid, - int quiet) +struct commit *lookup_commit_reference_gently(struct repository *r, + const struct object_id *oid, int quiet) { - struct object *obj = deref_tag(parse_object(oid), NULL, 0); + struct object *obj = deref_tag(r, + parse_object(r, oid), + NULL, 0); if (!obj) return NULL; - return object_as_type(obj, OBJ_COMMIT, quiet); + return object_as_type(r, obj, OBJ_COMMIT, quiet); } -struct commit *lookup_commit_reference(const struct object_id *oid) +struct commit *lookup_commit_reference(struct repository *r, const struct object_id *oid) { - return lookup_commit_reference_gently(oid, 0); + return lookup_commit_reference_gently(r, oid, 0); } struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name) { - struct commit *c = lookup_commit_reference(oid); + struct commit *c = lookup_commit_reference(the_repository, oid); if (!c) die(_("could not parse %s"), ref_name); if (oidcmp(oid, &c->object.oid)) { @@@ -53,13 -47,12 +53,13 @@@ return c; } -struct commit *lookup_commit(const struct object_id *oid) +struct commit *lookup_commit(struct repository *r, const struct object_id *oid) { - struct object *obj = lookup_object(oid->hash); + struct object *obj = lookup_object(r, oid->hash); if (!obj) - return create_object(oid->hash, alloc_commit_node()); - return object_as_type(obj, OBJ_COMMIT, 0); + return create_object(r, oid->hash, + alloc_commit_node(r)); + return object_as_type(r, obj, OBJ_COMMIT, 0); } struct commit *lookup_commit_reference_by_name(const char *name) @@@ -69,7 -62,7 +69,7 @@@ if (get_oid_committish(name, &oid)) return NULL; - commit = lookup_commit_reference(&oid); + commit = lookup_commit_reference(the_repository, &oid); if (parse_commit(commit)) return NULL; return commit; @@@ -102,44 -95,41 +102,44 @@@ static timestamp_t parse_commit_date(co return parse_timestamp(dateptr, NULL, 10); } -static struct commit_graft **commit_graft; -static int commit_graft_alloc, commit_graft_nr; - static const unsigned char *commit_graft_sha1_access(size_t index, void *table) { struct commit_graft **commit_graft_table = table; return commit_graft_table[index]->oid.hash; } -static int commit_graft_pos(const unsigned char *sha1) +static int commit_graft_pos(struct repository *r, const unsigned char *sha1) { - return sha1_pos(sha1, commit_graft, commit_graft_nr, + return sha1_pos(sha1, r->parsed_objects->grafts, + r->parsed_objects->grafts_nr, commit_graft_sha1_access); } -int register_commit_graft(struct commit_graft *graft, int ignore_dups) +int register_commit_graft(struct repository *r, struct commit_graft *graft, + int ignore_dups) { - int pos = commit_graft_pos(graft->oid.hash); + int pos = commit_graft_pos(r, graft->oid.hash); if (0 <= pos) { if (ignore_dups) free(graft); else { - free(commit_graft[pos]); - commit_graft[pos] = graft; + free(r->parsed_objects->grafts[pos]); + r->parsed_objects->grafts[pos] = graft; } return 1; } pos = -pos - 1; - ALLOC_GROW(commit_graft, commit_graft_nr + 1, commit_graft_alloc); - commit_graft_nr++; - if (pos < commit_graft_nr) - MOVE_ARRAY(commit_graft + pos + 1, commit_graft + pos, - commit_graft_nr - pos - 1); - commit_graft[pos] = graft; + ALLOC_GROW(r->parsed_objects->grafts, + r->parsed_objects->grafts_nr + 1, + r->parsed_objects->grafts_alloc); + r->parsed_objects->grafts_nr++; + if (pos < r->parsed_objects->grafts_nr) + memmove(r->parsed_objects->grafts + pos + 1, + r->parsed_objects->grafts + pos, + (r->parsed_objects->grafts_nr - pos - 1) * + sizeof(*r->parsed_objects->grafts)); + r->parsed_objects->grafts[pos] = graft; return 0; } @@@ -181,27 -171,18 +181,27 @@@ bad_graft_data return NULL; } -static int read_graft_file(const char *graft_file) +static int read_graft_file(struct repository *r, const char *graft_file) { FILE *fp = fopen_or_warn(graft_file, "r"); struct strbuf buf = STRBUF_INIT; if (!fp) return -1; + if (advice_graft_file_deprecated) + advise(_("Support for /info/grafts is deprecated\n" + "and will be removed in a future Git version.\n" + "\n" + "Please use \"git replace --convert-graft-file\"\n" + "to convert the grafts into replace refs.\n" + "\n" + "Turn this message off by running\n" + "\"git config advice.graftFileDeprecated false\"")); while (!strbuf_getwholeline(&buf, fp, '\n')) { /* The format is just "Commit Parent1 Parent2 ...\n" */ struct commit_graft *graft = read_graft_line(&buf); if (!graft) continue; - if (register_commit_graft(graft, 1)) + if (register_commit_graft(r, graft, 1)) error("duplicate graft data: %s", buf.buf); } fclose(fp); @@@ -209,50 -190,47 +209,50 @@@ return 0; } -static void prepare_commit_graft(void) +static void prepare_commit_graft(struct repository *r) { - static int commit_graft_prepared; char *graft_file; - if (commit_graft_prepared) + if (r->parsed_objects->commit_graft_prepared) + return; + if (!startup_info->have_repository) return; - graft_file = get_graft_file(); - read_graft_file(graft_file); + + graft_file = get_graft_file(r); + read_graft_file(r, graft_file); /* make sure shallows are read */ - is_repository_shallow(); - commit_graft_prepared = 1; + is_repository_shallow(r); + r->parsed_objects->commit_graft_prepared = 1; } -struct commit_graft *lookup_commit_graft(const struct object_id *oid) +struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid) { int pos; - prepare_commit_graft(); - pos = commit_graft_pos(oid->hash); + prepare_commit_graft(r); + pos = commit_graft_pos(r, oid->hash); if (pos < 0) return NULL; - return commit_graft[pos]; + return r->parsed_objects->grafts[pos]; } int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data) { int i, ret; - for (i = ret = 0; i < commit_graft_nr && !ret; i++) - ret = fn(commit_graft[i], cb_data); + for (i = ret = 0; i < the_repository->parsed_objects->grafts_nr && !ret; i++) + ret = fn(the_repository->parsed_objects->grafts[i], cb_data); return ret; } int unregister_shallow(const struct object_id *oid) { - int pos = commit_graft_pos(oid->hash); + int pos = commit_graft_pos(the_repository, oid->hash); if (pos < 0) return -1; - if (pos + 1 < commit_graft_nr) - MOVE_ARRAY(commit_graft + pos, commit_graft + pos + 1, - commit_graft_nr - pos - 1); - commit_graft_nr--; + if (pos + 1 < the_repository->parsed_objects->grafts_nr) + MOVE_ARRAY(the_repository->parsed_objects->grafts + pos, + the_repository->parsed_objects->grafts + pos + 1, + the_repository->parsed_objects->grafts_nr - pos - 1); + the_repository->parsed_objects->grafts_nr--; return 0; } @@@ -261,32 -239,18 +261,32 @@@ struct commit_buffer unsigned long size; }; define_commit_slab(buffer_slab, struct commit_buffer); -static struct buffer_slab buffer_slab = COMMIT_SLAB_INIT(1, buffer_slab); -void set_commit_buffer(struct commit *commit, void *buffer, unsigned long size) +struct buffer_slab *allocate_commit_buffer_slab(void) +{ + struct buffer_slab *bs = xmalloc(sizeof(*bs)); + init_buffer_slab(bs); + return bs; +} + +void free_commit_buffer_slab(struct buffer_slab *bs) { - struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + clear_buffer_slab(bs); + free(bs); +} + +void set_commit_buffer(struct repository *r, struct commit *commit, void *buffer, unsigned long size) +{ + struct commit_buffer *v = buffer_slab_at( + r->parsed_objects->buffer_slab, commit); v->buffer = buffer; v->size = size; } -const void *get_cached_commit_buffer(const struct commit *commit, unsigned long *sizep) +const void *get_cached_commit_buffer(struct repository *r, const struct commit *commit, unsigned long *sizep) { - struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit); + struct commit_buffer *v = buffer_slab_peek( + r->parsed_objects->buffer_slab, commit); if (!v) { if (sizep) *sizep = 0; @@@ -299,11 -263,11 +299,11 @@@ const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep) { - const void *ret = get_cached_commit_buffer(commit, sizep); + const void *ret = get_cached_commit_buffer(the_repository, commit, sizep); if (!ret) { enum object_type type; unsigned long size; - ret = read_sha1_file(commit->object.oid.hash, &type, &size); + ret = read_object_file(&commit->object.oid, &type, &size); if (!ret) die("cannot read commit object %s", oid_to_hex(&commit->object.oid)); @@@ -318,16 -282,14 +318,16 @@@ void unuse_commit_buffer(const struct commit *commit, const void *buffer) { - struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit); + struct commit_buffer *v = buffer_slab_peek( + the_repository->parsed_objects->buffer_slab, commit); if (!(v && v->buffer == buffer)) free((void *)buffer); } void free_commit_buffer(struct commit *commit) { - struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit); + struct commit_buffer *v = buffer_slab_peek( + the_repository->parsed_objects->buffer_slab, commit); if (v) { FREE_AND_NULL(v->buffer); v->size = 0; @@@ -342,7 -304,7 +342,7 @@@ struct tree *get_commit_tree(const stru 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) @@@ -350,21 -312,9 +350,21 @@@ return &get_commit_tree(commit)->object.oid; } +void release_commit_memory(struct commit *c) +{ + c->maybe_tree = NULL; + c->index = 0; + free_commit_buffer(c); + free_commit_list(c->parents); + /* TODO: what about commit->util? */ + + c->object.parsed = 0; +} + const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep) { - struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit); + struct commit_buffer *v = buffer_slab_peek( + the_repository->parsed_objects->buffer_slab, commit); void *ret; if (!v) { @@@ -381,15 -331,15 +381,15 @@@ return ret; } -int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size, int check_graph) +int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, unsigned long size, int check_graph) { const char *tail = buffer; const char *bufptr = buffer; struct object_id parent; struct commit_list **pptr; struct commit_graft *graft; - const int tree_entry_len = GIT_SHA1_HEXSZ + 5; - const int parent_entry_len = GIT_SHA1_HEXSZ + 7; + const int tree_entry_len = the_hash_algo->hexsz + 5; + const int parent_entry_len = the_hash_algo->hexsz + 7; if (item->object.parsed) return 0; @@@ -398,19 -348,19 +398,19 @@@ if (tail <= bufptr + tree_entry_len + 1 || memcmp(bufptr, "tree ", 5) || bufptr[tree_entry_len] != '\n') return error("bogus commit object %s", oid_to_hex(&item->object.oid)); - if (get_sha1_hex(bufptr + 5, parent.hash) < 0) + if (get_oid_hex(bufptr + 5, &parent) < 0) return error("bad tree pointer in commit %s", oid_to_hex(&item->object.oid)); - item->maybe_tree = lookup_tree(&parent); + item->maybe_tree = lookup_tree(r, &parent); bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */ pptr = &item->parents; - graft = lookup_commit_graft(&item->object.oid); + graft = lookup_commit_graft(r, &item->object.oid); while (bufptr + parent_entry_len < tail && !memcmp(bufptr, "parent ", 7)) { struct commit *new_parent; if (tail <= bufptr + parent_entry_len + 1 || - get_sha1_hex(bufptr + 7, parent.hash) || + get_oid_hex(bufptr + 7, &parent) || bufptr[parent_entry_len] != '\n') return error("bad parents in commit %s", oid_to_hex(&item->object.oid)); bufptr += parent_entry_len + 1; @@@ -420,7 -370,7 +420,7 @@@ */ if (graft && (graft->nr_parent < 0 || grafts_replace_parents)) continue; - new_parent = lookup_commit(&parent); + new_parent = lookup_commit(r, &parent); if (new_parent) pptr = &commit_list_insert(new_parent, pptr)->next; } @@@ -428,8 -378,7 +428,8 @@@ int i; struct commit *new_parent; for (i = 0; i < graft->nr_parent; i++) { - new_parent = lookup_commit(&graft->parent[i]); + new_parent = lookup_commit(r, + &graft->parent[i]); if (!new_parent) continue; pptr = &commit_list_insert(new_parent, pptr)->next; @@@ -438,12 -387,12 +438,12 @@@ item->date = parse_commit_date(bufptr, tail); if (check_graph) - load_commit_graph_info(item); + load_commit_graph_info(the_repository, item); return 0; } -int parse_commit_gently(struct commit *item, int quiet_on_missing) +int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_commit_graph) { enum object_type type; void *buffer; @@@ -454,9 -403,9 +454,9 @@@ return -1; if (item->object.parsed) return 0; - if (parse_commit_in_graph(item)) + if (use_commit_graph && parse_commit_in_graph(the_repository, item)) return 0; - buffer = read_sha1_file(item->object.oid.hash, &type, &size); + buffer = read_object_file(&item->object.oid, &type, &size); if (!buffer) return quiet_on_missing ? -1 : error("Could not read %s", @@@ -466,21 -415,15 +466,21 @@@ return error("Object %s not a commit", oid_to_hex(&item->object.oid)); } - ret = parse_commit_buffer(item, buffer, size, 0); + + ret = parse_commit_buffer(the_repository, item, buffer, size, 0); if (save_commit_buffer && !ret) { - set_commit_buffer(item, buffer, size); + set_commit_buffer(the_repository, item, buffer, size); return 0; } free(buffer); return ret; } +int parse_commit_gently(struct commit *item, int quiet_on_missing) +{ + return parse_commit_internal(item, quiet_on_missing, 1); +} + void parse_commit_or_die(struct commit *item) { if (parse_commit(item)) @@@ -656,7 -599,7 +656,7 @@@ struct commit *pop_commit(struct commit define_commit_slab(indegree_slab, int); /* record author-date for each commit object */ -define_commit_slab(author_date_slab, unsigned long); +define_commit_slab(author_date_slab, timestamp_t); static void record_author_date(struct author_date_slab *author_date, struct commit *commit) @@@ -874,6 -817,9 +874,9 @@@ static struct commit_list *paint_down_t int i; uint32_t last_gen = GENERATION_NUMBER_INFINITY; + if (!min_generation) + queue.compare = compare_commits_by_commit_date; + one->object.flags |= PARENT1; if (!n) { commit_list_append(one, &result); @@@ -891,7 -837,7 +894,7 @@@ struct commit_list *parents; int flags; - if (commit->generation > last_gen) + if (min_generation && commit->generation > last_gen) BUG("bad generation skip %8x > %8x at %s", commit->generation, last_gen, oid_to_hex(&commit->object.oid)); @@@ -1327,7 -1273,7 +1330,7 @@@ static void handle_signed_tag(struct co desc = merge_remote_util(parent); if (!desc || !desc->obj) return; - buf = read_sha1_file(desc->obj->oid.hash, &type, &size); + buf = read_object_file(&desc->obj->oid, &type, &size); if (!buf || type != OBJ_TAG) goto free_return; len = parse_signature(buf, size); @@@ -1409,19 -1355,17 +1412,19 @@@ struct commit_extra_header *read_commit return extra; } -void for_each_mergetag(each_mergetag_fn fn, struct commit *commit, void *data) +int for_each_mergetag(each_mergetag_fn fn, struct commit *commit, void *data) { struct commit_extra_header *extra, *to_free; + int res = 0; to_free = read_commit_extra_headers(commit, NULL); - for (extra = to_free; extra; extra = extra->next) { + for (extra = to_free; !res && extra; extra = extra->next) { if (strcmp(extra->key, "mergetag")) continue; /* not a merge tag */ - fn(commit, extra, data); + res = fn(commit, extra, data); } free_commit_extra_headers(to_free); + return res; } static inline int standard_header_field(const char *field, size_t len) @@@ -1640,7 -1584,7 +1643,7 @@@ int commit_tree_extended(const char *ms int encoding_is_utf8; struct strbuf buffer; - assert_sha1_type(tree->hash, OBJ_TREE); + assert_oid_type(tree, OBJ_TREE); if (memchr(msg, '\0', msg_len)) return error("a NUL byte in commit log message not allowed."); @@@ -1694,21 -1638,13 +1697,21 @@@ out return result; } +define_commit_slab(merge_desc_slab, struct merge_remote_desc *); +static struct merge_desc_slab merge_desc_slab = COMMIT_SLAB_INIT(1, merge_desc_slab); + +struct merge_remote_desc *merge_remote_util(struct commit *commit) +{ + return *merge_desc_slab_at(&merge_desc_slab, commit); +} + void set_merge_remote_desc(struct commit *commit, const char *name, struct object *obj) { struct merge_remote_desc *desc; FLEX_ALLOC_STR(desc, name, name); desc->obj = obj; - commit->util = desc; + *merge_desc_slab_at(&merge_desc_slab, commit) = desc; } struct commit *get_merge_parent(const char *name) @@@ -1718,9 -1654,9 +1721,9 @@@ struct object_id oid; if (get_oid(name, &oid)) return NULL; - obj = parse_object(&oid); + obj = parse_object(the_repository, &oid); commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT); - if (commit && !commit->util) + if (commit && !merge_remote_util(commit)) set_merge_remote_desc(commit, name, obj); return commit; }