Merge branch 'jn/maint-fast-import-object-reuse'
authorJunio C Hamano <gitster@pobox.com>
Thu, 16 Dec 2010 20:49:16 +0000 (12:49 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 16 Dec 2010 20:49:16 +0000 (12:49 -0800)
* jn/maint-fast-import-object-reuse:
fast-import: insert new object entries at start of hash bucket

1  2 
fast-import.c
diff --combined fast-import.c
index 2b23635d607c871a67b7851aec8809822b284807,89d074bbe432440f84156a82164179ff53336058..3c58e6f04a878c14f398b0fbb501475e842ea0ac
@@@ -156,7 -156,6 +156,7 @@@ Format of STDIN stream
  #include "csum-file.h"
  #include "quote.h"
  #include "exec_cmd.h"
 +#include "dir.h"
  
  #define PACK_ID_BITS 16
  #define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
@@@ -268,7 -267,7 +268,7 @@@ struct hash_lis
  typedef enum {
        WHENSPEC_RAW = 1,
        WHENSPEC_RFC2822,
 -      WHENSPEC_NOW,
 +      WHENSPEC_NOW
  } whenspec_type;
  
  struct recent_command
@@@ -362,9 -361,6 +362,9 @@@ static uintmax_t next_mark
  static struct strbuf new_data = STRBUF_INIT;
  static int seen_data_command;
  
 +/* Signal handling */
 +static volatile sig_atomic_t checkpoint_requested;
 +
  static void parse_argv(void);
  
  static void write_branch_report(FILE *rpt, struct branch *b)
@@@ -504,32 -500,6 +504,32 @@@ static NORETURN void die_nicely(const c
        exit(128);
  }
  
 +#ifndef SIGUSR1       /* Windows, for example */
 +
 +static void set_checkpoint_signal(void)
 +{
 +}
 +
 +#else
 +
 +static void checkpoint_signal(int signo)
 +{
 +      checkpoint_requested = 1;
 +}
 +
 +static void set_checkpoint_signal(void)
 +{
 +      struct sigaction sa;
 +
 +      memset(&sa, 0, sizeof(sa));
 +      sa.sa_handler = checkpoint_signal;
 +      sigemptyset(&sa.sa_mask);
 +      sa.sa_flags = SA_RESTART;
 +      sigaction(SIGUSR1, &sa, NULL);
 +}
 +
 +#endif
 +
  static void alloc_objects(unsigned int cnt)
  {
        struct object_entry_pool *b;
@@@ -569,22 -539,17 +569,17 @@@ static struct object_entry *insert_obje
  {
        unsigned int h = sha1[0] << 8 | sha1[1];
        struct object_entry *e = object_table[h];
-       struct object_entry *p = NULL;
  
        while (e) {
                if (!hashcmp(sha1, e->idx.sha1))
                        return e;
-               p = e;
                e = e->next;
        }
  
        e = new_object(sha1);
-       e->next = NULL;
+       e->next = object_table[h];
        e->idx.offset = 0;
-       if (p)
-               p->next = e;
-       else
-               object_table[h] = e;
+       object_table[h] = e;
        return e;
  }
  
@@@ -1010,6 -975,29 +1005,6 @@@ static void cycle_packfile(void
        start_packfile();
  }
  
 -static size_t encode_header(
 -      enum object_type type,
 -      uintmax_t size,
 -      unsigned char *hdr)
 -{
 -      int n = 1;
 -      unsigned char c;
 -
 -      if (type < OBJ_COMMIT || type > OBJ_REF_DELTA)
 -              die("bad type %d", type);
 -
 -      c = (type << 4) | (size & 15);
 -      size >>= 4;
 -      while (size) {
 -              *hdr++ = c | 0x80;
 -              c = size & 0x7f;
 -              size >>= 7;
 -              n++;
 -      }
 -      *hdr = c;
 -      return n;
 -}
 -
  static int store_object(
        enum object_type type,
        struct strbuf *dat,
                delta_count_by_type[type]++;
                e->depth = last->depth + 1;
  
 -              hdrlen = encode_header(OBJ_OFS_DELTA, deltalen, hdr);
 +              hdrlen = encode_in_pack_object_header(OBJ_OFS_DELTA, deltalen, hdr);
                sha1write(pack_file, hdr, hdrlen);
                pack_size += hdrlen;
  
                pack_size += sizeof(hdr) - pos;
        } else {
                e->depth = 0;
 -              hdrlen = encode_header(type, dat->len, hdr);
 +              hdrlen = encode_in_pack_object_header(type, dat->len, hdr);
                sha1write(pack_file, hdr, hdrlen);
                pack_size += hdrlen;
        }
@@@ -1195,7 -1183,7 +1190,7 @@@ static void stream_blob(uintmax_t len, 
        memset(&s, 0, sizeof(s));
        deflateInit(&s, pack_compression_level);
  
 -      hdrlen = encode_header(OBJ_BLOB, len, out_buf);
 +      hdrlen = encode_in_pack_object_header(OBJ_BLOB, len, out_buf);
        if (out_sz <= hdrlen)
                die("impossibly large object header");
  
@@@ -1467,20 -1455,6 +1462,20 @@@ static void store_tree(struct tree_entr
        t->entry_count -= del;
  }
  
 +static void tree_content_replace(
 +      struct tree_entry *root,
 +      const unsigned char *sha1,
 +      const uint16_t mode,
 +      struct tree_content *newtree)
 +{
 +      if (!S_ISDIR(mode))
 +              die("Root cannot be a non-directory");
 +      hashcpy(root->versions[1].sha1, sha1);
 +      if (root->tree)
 +              release_tree_content_recursive(root->tree);
 +      root->tree = newtree;
 +}
 +
  static int tree_content_set(
        struct tree_entry *root,
        const char *p,
        const uint16_t mode,
        struct tree_content *subtree)
  {
 -      struct tree_content *t = root->tree;
 +      struct tree_content *t;
        const char *slash1;
        unsigned int i, n;
        struct tree_entry *e;
        if (!slash1 && !S_ISDIR(mode) && subtree)
                die("Non-directories cannot have subtrees");
  
 +      if (!root->tree)
 +              load_tree(root);
 +      t = root->tree;
        for (i = 0; i < t->entry_count; i++) {
                e = t->entries[i];
 -              if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {
 +              if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
                        if (!slash1) {
                                if (!S_ISDIR(mode)
                                                && e->versions[1].mode == mode
@@@ -1561,7 -1532,7 +1556,7 @@@ static int tree_content_remove
        const char *p,
        struct tree_entry *backup_leaf)
  {
 -      struct tree_content *t = root->tree;
 +      struct tree_content *t;
        const char *slash1;
        unsigned int i, n;
        struct tree_entry *e;
        else
                n = strlen(p);
  
 +      if (!root->tree)
 +              load_tree(root);
 +      t = root->tree;
        for (i = 0; i < t->entry_count; i++) {
                e = t->entries[i];
 -              if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {
 +              if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
 +                      if (slash1 && !S_ISDIR(e->versions[1].mode))
 +                              /*
 +                               * If p names a file in some subdirectory, and a
 +                               * file or symlink matching the name of the
 +                               * parent directory of p exists, then p cannot
 +                               * exist and need not be deleted.
 +                               */
 +                              return 1;
                        if (!slash1 || !S_ISDIR(e->versions[1].mode))
                                goto del_entry;
                        if (!e->tree)
@@@ -1622,7 -1582,7 +1617,7 @@@ static int tree_content_get
        const char *p,
        struct tree_entry *leaf)
  {
 -      struct tree_content *t = root->tree;
 +      struct tree_content *t;
        const char *slash1;
        unsigned int i, n;
        struct tree_entry *e;
        else
                n = strlen(p);
  
 +      if (!root->tree)
 +              load_tree(root);
 +      t = root->tree;
        for (i = 0; i < t->entry_count; i++) {
                e = t->entries[i];
 -              if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {
 +              if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
                        if (!slash1) {
                                memcpy(leaf, e, sizeof(*leaf));
                                if (e->tree && is_null_sha1(e->versions[1].sha1))
@@@ -1727,7 -1684,7 +1722,7 @@@ static void dump_marks_helper(FILE *f
        if (m->shift) {
                for (k = 0; k < 1024; k++) {
                        if (m->data.sets[k])
 -                              dump_marks_helper(f, (base + k) << m->shift,
 +                              dump_marks_helper(f, base + (k << m->shift),
                                        m->data.sets[k]);
                }
        } else {
@@@ -2192,7 -2149,6 +2187,7 @@@ static void file_change_m(struct branc
        case S_IFREG | 0644:
        case S_IFREG | 0755:
        case S_IFLNK:
 +      case S_IFDIR:
        case S_IFGITLINK:
                /* ok */
                break;
                 * another repository.
                 */
        } else if (inline_data) {
 +              if (S_ISDIR(mode))
 +                      die("Directories cannot be specified 'inline': %s",
 +                              command_buf.buf);
                if (p != uq.buf) {
                        strbuf_addstr(&uq, p);
                        p = uq.buf;
                }
                read_next_command();
                parse_and_store_blob(&last_blob, sha1, 0);
 -      } else if (oe) {
 -              if (oe->type != OBJ_BLOB)
 -                      die("Not a blob (actually a %s): %s",
 -                              typename(oe->type), command_buf.buf);
        } else {
 -              enum object_type type = sha1_object_info(sha1, NULL);
 +              enum object_type expected = S_ISDIR(mode) ?
 +                                              OBJ_TREE: OBJ_BLOB;
 +              enum object_type type = oe ? oe->type :
 +                                      sha1_object_info(sha1, NULL);
                if (type < 0)
 -                      die("Blob not found: %s", command_buf.buf);
 -              if (type != OBJ_BLOB)
 -                      die("Not a blob (actually a %s): %s",
 -                          typename(type), command_buf.buf);
 +                      die("%s not found: %s",
 +                                      S_ISDIR(mode) ?  "Tree" : "Blob",
 +                                      command_buf.buf);
 +              if (type != expected)
 +                      die("Not a %s (actually a %s): %s",
 +                              typename(expected), typename(type),
 +                              command_buf.buf);
        }
  
 +      if (!*p) {
 +              tree_content_replace(&b->branch_tree, sha1, mode, NULL);
 +              return;
 +      }
        tree_content_set(&b->branch_tree, p, sha1, mode, NULL);
  }
  
@@@ -2324,13 -2271,6 +2319,13 @@@ static void file_change_cr(struct branc
                tree_content_get(&b->branch_tree, s, &leaf);
        if (!leaf.versions[1].mode)
                die("Path %s not in branch", s);
 +      if (!*d) {      /* C "path/to/subdir" "" */
 +              tree_content_replace(&b->branch_tree,
 +                      leaf.versions[1].sha1,
 +                      leaf.versions[1].mode,
 +                      leaf.tree);
 +              return;
 +      }
        tree_content_set(&b->branch_tree, d,
                leaf.versions[1].sha1,
                leaf.versions[1].mode,
@@@ -2744,20 -2684,14 +2739,20 @@@ static void parse_reset_branch(void
                unread_command_buf = 1;
  }
  
 -static void parse_checkpoint(void)
 +static void checkpoint(void)
  {
 +      checkpoint_requested = 0;
        if (object_count) {
                cycle_packfile();
                dump_branches();
                dump_tags();
                dump_marks();
        }
 +}
 +
 +static void parse_checkpoint(void)
 +{
 +      checkpoint_requested = 1;
        skip_optional_lf();
  }
  
@@@ -2791,7 -2725,6 +2786,7 @@@ static void option_import_marks(const c
        }
  
        import_marks_file = make_fast_import_path(marks);
 +      safe_create_leading_directories_const(import_marks_file);
        import_marks_file_from_stream = from_stream;
  }
  
@@@ -2822,7 -2755,6 +2817,7 @@@ static void option_active_branches(cons
  static void option_export_marks(const char *marks)
  {
        export_marks_file = make_fast_import_path(marks);
 +      safe_create_leading_directories_const(export_marks_file);
  }
  
  static void option_export_pack_edges(const char *edges)
@@@ -2954,7 -2886,7 +2949,7 @@@ static int git_pack_config(const char *
  }
  
  static const char fast_import_usage[] =
 -"git fast-import [--date-format=f] [--max-pack-size=n] [--big-file-threshold=n] [--depth=n] [--active-branches=n] [--export-marks=marks.file]";
 +"git fast-import [--date-format=<f>] [--max-pack-size=<n>] [--big-file-threshold=<n>] [--depth=<n>] [--active-branches=<n>] [--export-marks=<marks.file>]";
  
  static void parse_argv(void)
  {
@@@ -3014,7 -2946,6 +3009,7 @@@ int main(int argc, const char **argv
        prepare_packed_git();
        start_packfile();
        set_die_routine(die_nicely);
 +      set_checkpoint_signal();
        while (read_next_command() != EOF) {
                if (!strcmp("blob", command_buf.buf))
                        parse_new_blob();
                        /* ignore non-git options*/;
                else
                        die("Unsupported command: %s", command_buf.buf);
 +
 +              if (checkpoint_requested)
 +                      checkpoint();
        }
  
        /* argv hasn't been parsed yet, do so */