diff options
Diffstat (limited to 'builtin/index-pack.c')
-rw-r--r-- | builtin/index-pack.c | 125 |
1 files changed, 85 insertions, 40 deletions
diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 54c7faf6ee..d773809c4c 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -157,11 +157,11 @@ static int input_fd, output_fd; static const char *curr_pack; /* - * local_links is guarded by read_mutex, and record_local_links is read-only in - * a thread. + * outgoing_links is guarded by read_mutex, and record_outgoing_links is + * read-only in a thread. */ -static struct oidset local_links = OIDSET_INIT; -static int record_local_links; +static struct oidset outgoing_links = OIDSET_INIT; +static int record_outgoing_links; static struct thread_local_data *thread_data; static int nr_dispatched; @@ -814,18 +814,41 @@ static int check_collison(struct object_entry *entry) return 0; } -static void record_if_local_object(const struct object_id *oid) +static void record_outgoing_link(const struct object_id *oid) { - struct object_info info = OBJECT_INFO_INIT; - if (oid_object_info_extended(the_repository, oid, &info, 0)) - /* Missing; assume it is a promisor object */ - return; - if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor) - return; - oidset_insert(&local_links, oid); + oidset_insert(&outgoing_links, oid); +} + +static void maybe_record_name_entry(const struct name_entry *entry) +{ + /* + * Checking only trees here results in a significantly faster packfile + * indexing, but the drawback is that if the packfile to be indexed + * references a local blob only directly (that is, never through a + * local tree), that local blob is in danger of being garbage + * collected. Such a situation may arise if we push local commits, + * including one with a change to a blob in the root tree, and then the + * server incorporates them into its main branch through a "rebase" or + * "squash" merge strategy, and then we fetch the new main branch from + * the server. + * + * This situation has not been observed yet - we have only noticed + * missing commits, not missing trees or blobs. (In fact, if it were + * believed that only missing commits are problematic, one could argue + * that we should also exclude trees during the outgoing link check; + * but it is safer to include them.) + * + * Due to the rarity of the situation (it has not been observed to + * happen in real life), and because the "penalty" in such a situation + * is merely to refetch the missing blob when it's needed (and this + * happens only once - when refetched, the blob goes into a promisor + * pack, so it won't be GC-ed, the tradeoff seems worth it. + */ + if (S_ISDIR(entry->mode)) + record_outgoing_link(&entry->oid); } -static void do_record_local_links(struct object *obj) +static void do_record_outgoing_links(struct object *obj) { if (obj->type == OBJ_TREE) { struct tree *tree = (struct tree *)obj; @@ -839,16 +862,17 @@ static void do_record_local_links(struct object *obj) */ return; while (tree_entry_gently(&desc, &entry)) - record_if_local_object(&entry.oid); + maybe_record_name_entry(&entry); } else if (obj->type == OBJ_COMMIT) { struct commit *commit = (struct commit *) obj; struct commit_list *parents = commit->parents; + record_outgoing_link(get_commit_tree_oid(commit)); for (; parents; parents = parents->next) - record_if_local_object(&parents->item->object.oid); + record_outgoing_link(&parents->item->object.oid); } else if (obj->type == OBJ_TAG) { struct tag *tag = (struct tag *) obj; - record_if_local_object(get_tagged_oid(tag)); + record_outgoing_link(get_tagged_oid(tag)); } } @@ -898,7 +922,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, free(has_data); } - if (strict || do_fsck_object || record_local_links) { + if (strict || do_fsck_object || record_outgoing_links) { read_lock(); if (type == OBJ_BLOB) { struct blob *blob = lookup_blob(the_repository, oid); @@ -930,8 +954,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, die(_("fsck error in packed object")); if (strict && fsck_walk(obj, NULL, &fsck_options)) die(_("Not all child objects of %s are reachable"), oid_to_hex(&obj->oid)); - if (record_local_links) - do_record_local_links(obj); + if (record_outgoing_links) + do_record_outgoing_links(obj); if (obj->type == OBJ_TREE) { struct tree *item = (struct tree *) obj; @@ -1293,7 +1317,7 @@ static void parse_pack_objects(unsigned char *hash) * recursively checking if the resulting object is used as a base * for some more deltas. */ -static void resolve_deltas(void) +static void resolve_deltas(struct pack_idx_option *opts) { int i; @@ -1309,7 +1333,7 @@ static void resolve_deltas(void) nr_ref_deltas + nr_ofs_deltas); nr_dispatched = 0; - base_cache_limit = delta_base_cache_limit * nr_threads; + base_cache_limit = opts->delta_base_cache_limit * nr_threads; if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) { init_thread(); work_lock(); @@ -1534,7 +1558,7 @@ static void write_special_file(const char *suffix, const char *msg, if (pack_name) filename = derive_filename(pack_name, "pack", suffix, &name_buf); else - filename = odb_pack_name(&name_buf, hash, suffix); + filename = odb_pack_name(the_repository, &name_buf, hash, suffix); fd = odb_pack_keep(filename); if (fd < 0) { @@ -1562,7 +1586,7 @@ static void rename_tmp_packfile(const char **final_name, { if (!*final_name || strcmp(*final_name, curr_name)) { if (!*final_name) - *final_name = odb_pack_name(name, hash, ext); + *final_name = odb_pack_name(the_repository, name, hash, ext); if (finalize_object_file(curr_name, *final_name)) die(_("unable to rename temporary '*.%s' file to '%s'"), ext, *final_name); @@ -1607,7 +1631,8 @@ static void final(const char *final_pack_name, const char *curr_pack_name, if (do_fsck_object) { struct packed_git *p; - p = add_packed_git(final_index_name, strlen(final_index_name), 0); + p = add_packed_git(the_repository, final_index_name, + strlen(final_index_name), 0); if (p) install_packed_git(the_repository, p); } @@ -1658,6 +1683,10 @@ static int git_index_pack_config(const char *k, const char *v, else opts->flags &= ~WRITE_REV; } + if (!strcmp(k, "core.deltabasecachelimit")) { + opts->delta_base_cache_limit = git_config_ulong(k, v, ctx->kvi); + return 0; + } return git_default_config(k, v, ctx, cb); } @@ -1705,7 +1734,8 @@ static void read_v2_anomalous_offsets(struct packed_git *p, static void read_idx_option(struct pack_idx_option *opts, const char *pack_name) { - struct packed_git *p = add_packed_git(pack_name, strlen(pack_name), 1); + struct packed_git *p = add_packed_git(the_repository, pack_name, + strlen(pack_name), 1); if (!p) die(_("Cannot open existing pack file '%s'"), pack_name); @@ -1781,28 +1811,43 @@ static void repack_local_links(void) struct strbuf line = STRBUF_INIT; struct oidset_iter iter; struct object_id *oid; - char *base_name; + char *base_name = NULL; - if (!oidset_size(&local_links)) + if (!oidset_size(&outgoing_links)) return; - base_name = mkpathdup("%s/pack/pack", repo_get_object_directory(the_repository)); + oidset_iter_init(&outgoing_links, &iter); + while ((oid = oidset_iter_next(&iter))) { + struct object_info info = OBJECT_INFO_INIT; + if (oid_object_info_extended(the_repository, oid, &info, 0)) + /* Missing; assume it is a promisor object */ + continue; + if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor) + continue; - strvec_push(&cmd.args, "pack-objects"); - strvec_push(&cmd.args, "--exclude-promisor-objects-best-effort"); - strvec_push(&cmd.args, base_name); - cmd.git_cmd = 1; - cmd.in = -1; - cmd.out = -1; - if (start_command(&cmd)) - die(_("could not start pack-objects to repack local links")); + if (!cmd.args.nr) { + base_name = mkpathdup( + "%s/pack/pack", + repo_get_object_directory(the_repository)); + strvec_push(&cmd.args, "pack-objects"); + strvec_push(&cmd.args, + "--exclude-promisor-objects-best-effort"); + strvec_push(&cmd.args, base_name); + cmd.git_cmd = 1; + cmd.in = -1; + cmd.out = -1; + if (start_command(&cmd)) + die(_("could not start pack-objects to repack local links")); + } - oidset_iter_init(&local_links, &iter); - while ((oid = oidset_iter_next(&iter))) { if (write_in_full(cmd.in, oid_to_hex(oid), the_hash_algo->hexsz) < 0 || write_in_full(cmd.in, "\n", 1) < 0) die(_("failed to feed local object to pack-objects")); } + + if (!cmd.args.nr) + return; + close(cmd.in); out = xfdopen(cmd.out, "r"); @@ -1901,7 +1946,7 @@ int cmd_index_pack(int argc, } else if (skip_to_optional_arg(arg, "--keep", &keep_msg)) { ; /* nothing to do */ } else if (skip_to_optional_arg(arg, "--promisor", &promisor_msg)) { - record_local_links = 1; + record_outgoing_links = 1; } else if (starts_with(arg, "--threads=")) { char *end; nr_threads = strtoul(arg+10, &end, 0); @@ -2037,7 +2082,7 @@ int cmd_index_pack(int argc, parse_pack_objects(pack_hash); if (report_end_of_input) write_in_full(2, "\0", 1); - resolve_deltas(); + resolve_deltas(&opts); conclude_pack(fix_thin_pack, curr_pack, pack_hash); free(ofs_deltas); free(ref_deltas); |