Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- builtin/pack-objects.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index b38d3dc..69a22c1 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -18,6 +18,7 @@ #include "refs.h" #include "streaming.h" #include "thread-utils.h" +#include "packv4-create.h" static const char *pack_usage[] = { N_("git pack-objects --stdout [options...] [< ref-list | < object-list]"), @@ -61,6 +62,8 @@ static struct object_entry *objects; static struct pack_idx_entry **written_list; static uint32_t nr_objects, nr_alloc, nr_result, nr_written; +static struct packv4_tables v4; + static int non_empty; static int reuse_delta = 1, reuse_object = 1; static int keep_unreachable, unpack_unreachable, include_tag; @@ -2039,12 +2042,42 @@ static int add_ref_tag(const char *path, const unsigned char *sha1, int flag, vo return 0; } +static int sha1_idx_sort(const void *a_, const void *b_) +{ + const struct pack_idx_entry *a = a_; + const struct pack_idx_entry *b = b_; + return hashcmp(a->sha1, b->sha1); +} + +static void prepare_sha1_table(void) +{ + unsigned i; + /* + * This table includes SHA-1s that may not be present in the + * pack. One of the use of such SHA-1 is for completing thin + * packs, where index-pack does not need to add SHA-1 to the + * table at completion time. + */ + v4.all_objs = xmalloc(nr_objects * sizeof(*v4.all_objs)); + v4.all_objs_nr = nr_objects; + for (i = 0; i < nr_objects; i++) + v4.all_objs[i] = objects[i].idx; + qsort(v4.all_objs, nr_objects, sizeof(*v4.all_objs), + sha1_idx_sort); +} + static void prepare_pack(int window, int depth) { struct object_entry **delta_list; uint32_t i, nr_deltas; unsigned n; + if (pack_version == 4) { + sort_dict_entries_by_hits(v4.commit_ident_table); + sort_dict_entries_by_hits(v4.tree_path_table); + prepare_sha1_table(); + } + get_object_details(); /* @@ -2191,6 +2224,34 @@ static void read_object_list_from_stdin(void) add_preferred_base_object(line+41); add_object_entry(sha1, 0, line+41, 0); + + if (pack_version == 4) { + void *data; + enum object_type type; + unsigned long size; + int (*add_dict_entries)(struct dict_table *, void *, unsigned long); + struct dict_table *dict; + + switch (sha1_object_info(sha1, &size)) { + case OBJ_COMMIT: + add_dict_entries = add_commit_dict_entries; + dict = v4.commit_ident_table; + break; + case OBJ_TREE: + add_dict_entries = add_tree_dict_entries; + dict = v4.tree_path_table; + break; + default: + continue; + } + data = read_sha1_file(sha1, &type, &size); + if (!data) + die("cannot unpack %s", sha1_to_hex(sha1)); + if (add_dict_entries(dict, data, size) < 0) + die("can't process %s object %s", + typename(type), sha1_to_hex(sha1)); + free(data); + } } } @@ -2198,10 +2259,26 @@ static void read_object_list_from_stdin(void) static void show_commit(struct commit *commit, void *data) { + if (pack_version == 4) { + unsigned long size; + enum object_type type; + unsigned char *buf; + + /* commit->buffer is NULL most of the time, don't bother */ + buf = read_sha1_file(commit->object.sha1, &type, &size); + add_commit_dict_entries(v4.commit_ident_table, buf, size); + free(buf); + } add_object_entry(commit->object.sha1, OBJ_COMMIT, NULL, 0); commit->object.flags |= OBJECT_ADDED; } +static void show_tree_entry(const struct name_entry *entry, void *data) +{ + dict_add_entry(v4.tree_path_table, entry->mode, entry->path, + tree_entry_len(entry)); +} + static void show_object(struct object *obj, const struct name_path *path, const char *last, void *data) @@ -2380,7 +2457,9 @@ static void get_object_list(int ac, const char **av) if (prepare_revision_walk(&revs)) die("revision walk setup failed"); mark_edges_uninteresting(revs.commits, &revs, show_edge); - traverse_commit_list(&revs, show_commit, NULL, show_object, NULL); + traverse_commit_list(&revs, show_commit, + pack_version == 4 ? show_tree_entry : NULL, + show_object, NULL); if (keep_unreachable) add_objects_in_unpacked_packs(&revs); @@ -2527,7 +2606,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) } if (pack_to_stdout != !base_name || argc) usage_with_options(pack_usage, pack_objects_options); - if (pack_version != 2) + if (pack_version != 2 && pack_version != 4) die(_("pack version %d is not supported"), pack_version); rp_av[rp_ac++] = "pack-objects"; @@ -2579,6 +2658,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) progress = 2; prepare_packed_git(); + if (pack_version == 4) { + v4.commit_ident_table = create_dict_table(); + v4.tree_path_table = create_dict_table(); + } if (progress) progress_state = start_progress("Counting objects", 0); -- 1.8.2.83.gc99314b -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html