From: Junio C Hamano Date: Thu, 7 Feb 2019 06:05:24 +0000 (-0800) Subject: Merge branch 'ds/push-sparse-tree-walk' X-Git-Tag: v2.21.0-rc0~18 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/5fda343321f36384892061b21dcbe1d477145d2c?hp=-c Merge branch 'ds/push-sparse-tree-walk' "git pack-objects" learned another algorithm to compute the set of objects to send, that trades the resulting packfile off to save traversal cost to favor small pushes. * ds/push-sparse-tree-walk: pack-objects: create GIT_TEST_PACK_SPARSE pack-objects: create pack.useSparse setting revision: implement sparse algorithm list-objects: consume sparse tree walk revision: add mark_tree_uninteresting_sparse --- 5fda343321f36384892061b21dcbe1d477145d2c diff --combined bisect.c index 6bf521138a,842f8b4b8f..3af955c4bc --- a/bisect.c +++ b/bisect.c @@@ -558,8 -558,7 +558,8 @@@ struct commit_list *filter_skipped(stru * is increased by one between each call, but that should not matter * for this application. */ -static unsigned get_prn(unsigned count) { +static unsigned get_prn(unsigned count) +{ count = count * 1103515245 + 12345; return (count/65536) % PRN_MODULO; } @@@ -627,15 -626,14 +627,15 @@@ static struct commit_list *managed_skip return skip_away(list, count); } -static void bisect_rev_setup(struct rev_info *revs, const char *prefix, +static void bisect_rev_setup(struct repository *r, struct rev_info *revs, + const char *prefix, const char *bad_format, const char *good_format, int read_paths) { struct argv_array rev_argv = ARGV_ARRAY_INIT; int i; - repo_init_revisions(the_repository, revs, prefix); + repo_init_revisions(r, revs, prefix); revs->abbrev = 0; revs->commit_format = CMIT_FMT_UNSPECIFIED; @@@ -658,7 -656,7 +658,7 @@@ static void bisect_common(struct rev_in if (prepare_revision_walk(revs)) die("revision walk setup failed"); if (revs->tree_objects) - mark_edges_uninteresting(revs, NULL); + mark_edges_uninteresting(revs, NULL, 0); } static void exit_if_skipped_commits(struct commit_list *tried, @@@ -725,25 -723,23 +725,25 @@@ static int bisect_checkout(const struc return run_command_v_opt(argv_show_branch, RUN_GIT_CMD); } -static struct commit *get_commit_reference(const struct object_id *oid) +static struct commit *get_commit_reference(struct repository *r, + const struct object_id *oid) { - struct commit *r = lookup_commit_reference(the_repository, oid); - if (!r) + struct commit *c = lookup_commit_reference(r, oid); + if (!c) die(_("Not a valid commit name %s"), oid_to_hex(oid)); - return r; + return c; } -static struct commit **get_bad_and_good_commits(int *rev_nr) +static struct commit **get_bad_and_good_commits(struct repository *r, + int *rev_nr) { struct commit **rev; int i, n = 0; ALLOC_ARRAY(rev, 1 + good_revs.nr); - rev[n++] = get_commit_reference(current_bad_oid); + rev[n++] = get_commit_reference(r, current_bad_oid); for (i = 0; i < good_revs.nr; i++) - rev[n++] = get_commit_reference(good_revs.oid + i); + rev[n++] = get_commit_reference(r, good_revs.oid + i); *rev_nr = n; return rev; @@@ -827,13 -823,12 +827,13 @@@ static void check_merge_bases(int rev_n free_commit_list(result); } -static int check_ancestors(int rev_nr, struct commit **rev, const char *prefix) +static int check_ancestors(struct repository *r, int rev_nr, + struct commit **rev, const char *prefix) { struct rev_info revs; int res; - bisect_rev_setup(&revs, prefix, "^%s", "%s", 0); + bisect_rev_setup(r, &revs, prefix, "^%s", "%s", 0); bisect_common(&revs); res = (revs.commits != NULL); @@@ -852,9 -847,7 +852,9 @@@ * If a merge base must be tested by the user, its source code will be * checked out to be tested by the user and we will exit. */ -static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout) +static void check_good_are_ancestors_of_bad(struct repository *r, + const char *prefix, + int no_checkout) { char *filename = git_pathdup("BISECT_ANCESTORS_OK"); struct stat st; @@@ -873,8 -866,8 +873,8 @@@ goto done; /* Check if all good revs are ancestor of the bad rev. */ - rev = get_bad_and_good_commits(&rev_nr); - if (check_ancestors(rev_nr, rev, prefix)) + rev = get_bad_and_good_commits(r, &rev_nr); + if (check_ancestors(r, rev_nr, rev, prefix)) check_merge_bases(rev_nr, rev, no_checkout); free(rev); @@@ -892,14 -885,12 +892,14 @@@ /* * This does "git diff-tree --pretty COMMIT" without one fork+exec. */ -static void show_diff_tree(const char *prefix, struct commit *commit) +static void show_diff_tree(struct repository *r, + const char *prefix, + struct commit *commit) { struct rev_info opt; /* diff-tree init */ - repo_init_revisions(the_repository, &opt, prefix); + repo_init_revisions(r, &opt, prefix); git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ opt.abbrev = 0; opt.diff = 1; @@@ -954,7 -945,7 +954,7 @@@ void read_bisect_terms(const char **rea * If no_checkout is non-zero, the bisection process does not * checkout the trial commit but instead simply updates BISECT_HEAD. */ -int bisect_next_all(const char *prefix, int no_checkout) +int bisect_next_all(struct repository *r, const char *prefix, int no_checkout) { struct rev_info revs; struct commit_list *tried; @@@ -966,9 -957,9 +966,9 @@@ if (read_bisect_refs()) die(_("reading bisect refs failed")); - check_good_are_ancestors_of_bad(prefix, no_checkout); + check_good_are_ancestors_of_bad(r, prefix, no_checkout); - bisect_rev_setup(&revs, prefix, "%s", "^%s", 1); + bisect_rev_setup(r, &revs, prefix, "%s", "^%s", 1); revs.limited = 1; bisect_common(&revs); @@@ -1002,7 -993,7 +1002,7 @@@ exit_if_skipped_commits(tried, current_bad_oid); printf("%s is the first %s commit\n", oid_to_hex(bisect_rev), term_bad); - show_diff_tree(prefix, revs.commits->item); + show_diff_tree(r, prefix, revs.commits->item); /* This means the bisection process succeeded. */ exit(10); } diff --combined builtin/pack-objects.c index ffef8dcf2f,507d381153..bd67491c16 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@@ -84,6 -84,7 +84,7 @@@ static unsigned long pack_size_limit static int depth = 50; static int delta_search_threads; static int pack_to_stdout; + static int sparse; static int thin; static int num_preferred_base; static struct progress *progress_state; @@@ -970,7 -971,7 +971,7 @@@ static int no_try_delta(const char *pat if (!check) check = attr_check_initl("delta", NULL); - git_check_attr(&the_index, path, check); + git_check_attr(the_repository->index, path, check); if (ATTR_FALSE(check->items[0].value)) return 1; return 0; @@@ -1334,7 -1335,7 +1335,7 @@@ static void add_pbase_object(struct tre if (cmp < 0) return; if (name[cmplen] != '/') { - add_object_entry(entry.oid, + add_object_entry(&entry.oid, object_type(entry.mode), fullname, 1); return; @@@ -1345,7 -1346,7 +1346,7 @@@ const char *down = name+cmplen+1; int downlen = name_cmp_len(down); - tree = pbase_tree_get(entry.oid); + tree = pbase_tree_get(&entry.oid); if (!tree) return; init_tree_desc(&sub, tree->tree_data, tree->tree_size); @@@ -1953,6 -1954,11 +1954,6 @@@ static int delta_cacheable(unsigned lon return 0; } -/* Protect access to object database */ -static pthread_mutex_t read_mutex; -#define read_lock() pthread_mutex_lock(&read_mutex) -#define read_unlock() pthread_mutex_unlock(&read_mutex) - /* Protect delta_cache_size */ static pthread_mutex_t cache_mutex; #define cache_lock() pthread_mutex_lock(&cache_mutex) @@@ -1988,11 -1994,11 +1989,11 @@@ unsigned long oe_get_size_slow(struct p unsigned long used, avail, size; if (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) { - read_lock(); + packing_data_lock(&to_pack); if (oid_object_info(the_repository, &e->idx.oid, &size) < 0) die(_("unable to get size of %s"), oid_to_hex(&e->idx.oid)); - read_unlock(); + packing_data_unlock(&to_pack); return size; } @@@ -2000,7 -2006,7 +2001,7 @@@ if (!p) BUG("when e->type is a delta, it must belong to a pack"); - read_lock(); + packing_data_lock(&to_pack); w_curs = NULL; buf = use_pack(p, &w_curs, e->in_pack_offset, &avail); used = unpack_object_header_buffer(buf, avail, &type, &size); @@@ -2009,7 -2015,7 +2010,7 @@@ oid_to_hex(&e->idx.oid)); unuse_pack(&w_curs); - read_unlock(); + packing_data_unlock(&to_pack); return size; } @@@ -2071,9 -2077,9 +2072,9 @@@ static int try_delta(struct unpacked *t /* Load data if not already done */ if (!trg->data) { - read_lock(); + packing_data_lock(&to_pack); trg->data = read_object_file(&trg_entry->idx.oid, &type, &sz); - read_unlock(); + packing_data_unlock(&to_pack); if (!trg->data) die(_("object %s cannot be read"), oid_to_hex(&trg_entry->idx.oid)); @@@ -2084,9 -2090,9 +2085,9 @@@ *mem_usage += sz; } if (!src->data) { - read_lock(); + packing_data_lock(&to_pack); src->data = read_object_file(&src_entry->idx.oid, &type, &sz); - read_unlock(); + packing_data_unlock(&to_pack); if (!src->data) { if (src_entry->preferred_base) { static int warned = 0; @@@ -2332,9 -2338,9 +2333,9 @@@ static void find_deltas(struct object_e static void try_to_free_from_threads(size_t size) { - read_lock(); + packing_data_lock(&to_pack); release_pack_memory(size); - read_unlock(); + packing_data_unlock(&to_pack); } static try_to_free_t old_try_to_free_routine; @@@ -2376,6 -2382,7 +2377,6 @@@ static pthread_cond_t progress_cond */ static void init_threaded_search(void) { - init_recursive_mutex(&read_mutex); pthread_mutex_init(&cache_mutex, NULL); pthread_mutex_init(&progress_mutex, NULL); pthread_cond_init(&progress_cond, NULL); @@@ -2386,6 -2393,7 +2387,6 @@@ static void cleanup_threaded_search(voi { set_try_to_free_routine(old_try_to_free_routine); pthread_cond_destroy(&progress_cond); - pthread_mutex_destroy(&read_mutex); pthread_mutex_destroy(&cache_mutex); pthread_mutex_destroy(&progress_mutex); } @@@ -2603,7 -2611,7 +2604,7 @@@ static void prepare_pack(int window, in unsigned n; if (use_delta_islands) - resolve_tree_islands(progress, &to_pack); + resolve_tree_islands(the_repository, progress, &to_pack); get_object_details(); @@@ -2703,6 -2711,10 +2704,10 @@@ static int git_pack_config(const char * use_bitmap_index_default = git_config_bool(k, v); return 0; } + if (!strcmp(k, "pack.usesparse")) { + sparse = git_config_bool(k, v); + return 0; + } if (!strcmp(k, "pack.threads")) { delta_search_threads = git_config_int(k, v); if (delta_search_threads < 0) @@@ -3077,16 -3089,14 +3082,16 @@@ static void record_recent_commit(struc static void get_object_list(int ac, const char **av) { struct rev_info revs; + struct setup_revision_opt s_r_opt = { + .allow_exclude_promisor_objects = 1, + }; char line[1000]; int flags = 0; int save_warning; repo_init_revisions(the_repository, &revs, NULL); save_commit_buffer = 0; - revs.allow_exclude_promisor_objects_opt = 1; - setup_revisions(ac, av, &revs, NULL); + setup_revisions(ac, av, &revs, &s_r_opt); /* make sure shallows are read */ is_repository_shallow(the_repository); @@@ -3126,11 -3136,11 +3131,11 @@@ return; if (use_delta_islands) - load_delta_islands(); + load_delta_islands(the_repository); if (prepare_revision_walk(&revs)) die(_("revision walk setup failed")); - mark_edges_uninteresting(&revs, show_edge); + mark_edges_uninteresting(&revs, show_edge, sparse); if (!fn_show_object) fn_show_object = show_object; @@@ -3287,6 -3297,8 +3292,8 @@@ int cmd_pack_objects(int argc, const ch { OPTION_CALLBACK, 0, "unpack-unreachable", NULL, N_("time"), N_("unpack unreachable objects newer than