merge-base --fork-point doc: clarify the example and failure modes
[gitweb.git] / fast-import.c
index 84a13756cc6387d7546ebda8d3c92a6c49a53cf8..4d5a7f58d011545061decbc70e824274091db3e5 100644 (file)
@@ -165,6 +165,7 @@ Format of STDIN stream:
 #include "csum-file.h"
 #include "quote.h"
 #include "dir.h"
+#include "run-command.h"
 
 #define PACK_ID_BITS 16
 #define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
@@ -281,9 +282,8 @@ struct recent_command {
 /* Configured limits on output */
 static unsigned long max_depth = 10;
 static off_t max_packsize;
+static int unpack_limit = 100;
 static int force_update;
-static int pack_compression_level = Z_DEFAULT_COMPRESSION;
-static int pack_compression_seen;
 
 /* Stats and misc. counters */
 static uintmax_t alloc_count;
@@ -595,6 +595,33 @@ static struct object_entry *insert_object(unsigned char *sha1)
        return e;
 }
 
+static void invalidate_pack_id(unsigned int id)
+{
+       unsigned int h;
+       unsigned long lu;
+       struct tag *t;
+
+       for (h = 0; h < ARRAY_SIZE(object_table); h++) {
+               struct object_entry *e;
+
+               for (e = object_table[h]; e; e = e->next)
+                       if (e->pack_id == id)
+                               e->pack_id = MAX_PACK_ID;
+       }
+
+       for (lu = 0; lu < branch_table_sz; lu++) {
+               struct branch *b;
+
+               for (b = branch_table[lu]; b; b = b->table_next_branch)
+                       if (b->pack_id == id)
+                               b->pack_id = MAX_PACK_ID;
+       }
+
+       for (t = first_tag; t; t = t->next_tag)
+               if (t->pack_id == id)
+                       t->pack_id = MAX_PACK_ID;
+}
+
 static unsigned int hc_str(const char *s, size_t len)
 {
        unsigned int r = 0;
@@ -913,41 +940,57 @@ static const char *create_index(void)
 
 static char *keep_pack(const char *curr_index_name)
 {
-       static char name[PATH_MAX];
        static const char *keep_msg = "fast-import";
+       struct strbuf name = STRBUF_INIT;
        int keep_fd;
 
-       keep_fd = odb_pack_keep(name, sizeof(name), pack_data->sha1);
+       odb_pack_name(&name, pack_data->sha1, "keep");
+       keep_fd = odb_pack_keep(name.buf);
        if (keep_fd < 0)
                die_errno("cannot create keep file");
        write_or_die(keep_fd, keep_msg, strlen(keep_msg));
        if (close(keep_fd))
                die_errno("failed to write keep file");
 
-       snprintf(name, sizeof(name), "%s/pack/pack-%s.pack",
-                get_object_directory(), sha1_to_hex(pack_data->sha1));
-       if (finalize_object_file(pack_data->pack_name, name))
+       odb_pack_name(&name, pack_data->sha1, "pack");
+       if (finalize_object_file(pack_data->pack_name, name.buf))
                die("cannot store pack file");
 
-       snprintf(name, sizeof(name), "%s/pack/pack-%s.idx",
-                get_object_directory(), sha1_to_hex(pack_data->sha1));
-       if (finalize_object_file(curr_index_name, name))
+       odb_pack_name(&name, pack_data->sha1, "idx");
+       if (finalize_object_file(curr_index_name, name.buf))
                die("cannot store index file");
        free((void *)curr_index_name);
-       return name;
+       return strbuf_detach(&name, NULL);
 }
 
 static void unkeep_all_packs(void)
 {
-       static char name[PATH_MAX];
+       struct strbuf name = STRBUF_INIT;
        int k;
 
        for (k = 0; k < pack_id; k++) {
                struct packed_git *p = all_packs[k];
-               snprintf(name, sizeof(name), "%s/pack/pack-%s.keep",
-                        get_object_directory(), sha1_to_hex(p->sha1));
-               unlink_or_warn(name);
+               odb_pack_name(&name, p->sha1, "keep");
+               unlink_or_warn(name.buf);
        }
+       strbuf_release(&name);
+}
+
+static int loosen_small_pack(const struct packed_git *p)
+{
+       struct child_process unpack = CHILD_PROCESS_INIT;
+
+       if (lseek(p->pack_fd, 0, SEEK_SET) < 0)
+               die_errno("Failed seeking to start of '%s'", p->pack_name);
+
+       unpack.in = p->pack_fd;
+       unpack.git_cmd = 1;
+       unpack.stdout_to_stderr = 1;
+       argv_array_push(&unpack.args, "unpack-objects");
+       if (!show_stats)
+               argv_array_push(&unpack.args, "-q");
+
+       return run_command(&unpack);
 }
 
 static void end_packfile(void)
@@ -972,6 +1015,14 @@ static void end_packfile(void)
                fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1,
                                    pack_data->pack_name, object_count,
                                    cur_pack_sha1, pack_size);
+
+               if (object_count <= unpack_limit) {
+                       if (!loosen_small_pack(pack_data)) {
+                               invalidate_pack_id(pack_id);
+                               goto discard_pack;
+                       }
+               }
+
                close(pack_data->pack_fd);
                idx_name = keep_pack(create_index());
 
@@ -981,6 +1032,7 @@ static void end_packfile(void)
                        die("core git rejected index %s", idx_name);
                all_packs[pack_id] = new_p;
                install_packed_git(new_p);
+               free(idx_name);
 
                /* Print the boundary */
                if (pack_edges) {
@@ -1002,6 +1054,7 @@ static void end_packfile(void)
                pack_id++;
        }
        else {
+discard_pack:
                close(pack_data->pack_fd);
                unlink_or_warn(pack_data->pack_name);
        }
@@ -1405,9 +1458,9 @@ static void mktree(struct tree_content *t, int v, struct strbuf *b)
        unsigned int i;
 
        if (!v)
-               qsort(t->entries,t->entry_count,sizeof(t->entries[0]),tecmp0);
+               QSORT(t->entries, t->entry_count, tecmp0);
        else
-               qsort(t->entries,t->entry_count,sizeof(t->entries[0]),tecmp1);
+               QSORT(t->entries, t->entry_count, tecmp1);
 
        for (i = 0; i < t->entry_count; i++) {
                if (t->entries[i]->versions[v].mode)
@@ -2165,13 +2218,17 @@ static uintmax_t do_change_note_fanout(
                char *fullpath, unsigned int fullpath_len,
                unsigned char fanout)
 {
-       struct tree_content *t = root->tree;
+       struct tree_content *t;
        struct tree_entry *e, leaf;
        unsigned int i, tmp_hex_sha1_len, tmp_fullpath_len;
        uintmax_t num_notes = 0;
        unsigned char sha1[20];
        char realpath[60];
 
+       if (!root->tree)
+               load_tree(root);
+       t = root->tree;
+
        for (i = 0; t && i < t->entry_count; i++) {
                e = t->entries[i];
                tmp_hex_sha1_len = hex_sha1_len + e->name->str_len;
@@ -2223,8 +2280,6 @@ static uintmax_t do_change_note_fanout(
                                leaf.tree);
                } else if (S_ISDIR(e->versions[1].mode)) {
                        /* This is a subdir that may contain note entries */
-                       if (!e->tree)
-                               load_tree(e);
                        num_notes += do_change_note_fanout(orig_root, e,
                                hex_sha1, tmp_hex_sha1_len,
                                fullpath, tmp_fullpath_len, fanout);
@@ -3319,21 +3374,13 @@ static void parse_option(const char *option)
 static void git_pack_config(void)
 {
        int indexversion_value;
+       int limit;
        unsigned long packsizelimit_value;
 
        if (!git_config_get_ulong("pack.depth", &max_depth)) {
                if (max_depth > MAX_DEPTH)
                        max_depth = MAX_DEPTH;
        }
-       if (!git_config_get_int("pack.compression", &pack_compression_level)) {
-               if (pack_compression_level == -1)
-                       pack_compression_level = Z_DEFAULT_COMPRESSION;
-               else if (pack_compression_level < 0 ||
-                        pack_compression_level > Z_BEST_COMPRESSION)
-                       git_die_config("pack.compression",
-                                       "bad pack compression level %d", pack_compression_level);
-               pack_compression_seen = 1;
-       }
        if (!git_config_get_int("pack.indexversion", &indexversion_value)) {
                pack_idx_opts.version = indexversion_value;
                if (pack_idx_opts.version > 2)
@@ -3343,6 +3390,11 @@ static void git_pack_config(void)
        if (!git_config_get_ulong("pack.packsizelimit", &packsizelimit_value))
                max_packsize = packsizelimit_value;
 
+       if (!git_config_get_int("fastimport.unpacklimit", &limit))
+               unpack_limit = limit;
+       else if (!git_config_get_int("transfer.unpacklimit", &limit))
+               unpack_limit = limit;
+
        git_config(git_default_config, NULL);
 }
 
@@ -3393,8 +3445,6 @@ int cmd_main(int argc, const char **argv)
        setup_git_directory();
        reset_pack_idx_option(&pack_idx_opts);
        git_pack_config();
-       if (!pack_compression_seen && core_compression_seen)
-               pack_compression_level = core_compression_level;
 
        alloc_objects(object_entry_alloc);
        strbuf_init(&command_buf, 0);