Merge branch 'maint-1.7.6' into maint-1.7.7
authorJunio C Hamano <gitster@pobox.com>
Fri, 13 Jan 2012 07:31:05 +0000 (23:31 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 13 Jan 2012 07:31:05 +0000 (23:31 -0800)
* maint-1.7.6:
Update draft release notes to 1.7.6.6
thin-pack: try harder to use preferred base objects as base

1  2 
builtin/pack-objects.c
diff --combined builtin/pack-objects.c
index 80ab6c39f91b30be90203da777fd8e3989abdc2c,8bfe3a6ffb11fb2fc0956043dfafc2f3f66adccf..638d43da0e61c67a374ee124faf9391180171b21
@@@ -51,8 -51,6 +51,8 @@@ struct object_entry 
                                       * objects against.
                                       */
        unsigned char no_try_delta;
 +      unsigned char tagged; /* near the very tip of refs */
 +      unsigned char filled; /* assigned write-order */
  };
  
  /*
@@@ -72,7 -70,6 +72,7 @@@ static int local
  static int incremental;
  static int ignore_packed_keep;
  static int allow_ofs_delta;
 +static struct pack_idx_option pack_idx_opts;
  static const char *base_name;
  static int progress = 1;
  static int window = 10;
@@@ -98,7 -95,6 +98,7 @@@ static unsigned long window_memory_limi
   */
  static int *object_ix;
  static int object_ix_hashsz;
 +static struct object_entry *locate_object_entry(const unsigned char *sha1);
  
  /*
   * stats
@@@ -203,7 -199,6 +203,7 @@@ static void copy_pack_data(struct sha1f
        }
  }
  
 +/* Return 0 if we will bust the pack-size limit */
  static unsigned long write_object(struct sha1file *f,
                                  struct object_entry *entry,
                                  off_t write_offset)
@@@ -438,170 -433,6 +438,170 @@@ static int write_one(struct sha1file *f
        return 1;
  }
  
 +static int mark_tagged(const char *path, const unsigned char *sha1, int flag,
 +                     void *cb_data)
 +{
 +      unsigned char peeled[20];
 +      struct object_entry *entry = locate_object_entry(sha1);
 +
 +      if (entry)
 +              entry->tagged = 1;
 +      if (!peel_ref(path, peeled)) {
 +              entry = locate_object_entry(peeled);
 +              if (entry)
 +                      entry->tagged = 1;
 +      }
 +      return 0;
 +}
 +
 +static inline void add_to_write_order(struct object_entry **wo,
 +                             unsigned int *endp,
 +                             struct object_entry *e)
 +{
 +      if (e->filled)
 +              return;
 +      wo[(*endp)++] = e;
 +      e->filled = 1;
 +}
 +
 +static void add_descendants_to_write_order(struct object_entry **wo,
 +                                         unsigned int *endp,
 +                                         struct object_entry *e)
 +{
 +      int add_to_order = 1;
 +      while (e) {
 +              if (add_to_order) {
 +                      struct object_entry *s;
 +                      /* add this node... */
 +                      add_to_write_order(wo, endp, e);
 +                      /* all its siblings... */
 +                      for (s = e->delta_sibling; s; s = s->delta_sibling) {
 +                              add_to_write_order(wo, endp, s);
 +                      }
 +              }
 +              /* drop down a level to add left subtree nodes if possible */
 +              if (e->delta_child) {
 +                      add_to_order = 1;
 +                      e = e->delta_child;
 +              } else {
 +                      add_to_order = 0;
 +                      /* our sibling might have some children, it is next */
 +                      if (e->delta_sibling) {
 +                              e = e->delta_sibling;
 +                              continue;
 +                      }
 +                      /* go back to our parent node */
 +                      e = e->delta;
 +                      while (e && !e->delta_sibling) {
 +                              /* we're on the right side of a subtree, keep
 +                               * going up until we can go right again */
 +                              e = e->delta;
 +                      }
 +                      if (!e) {
 +                              /* done- we hit our original root node */
 +                              return;
 +                      }
 +                      /* pass it off to sibling at this level */
 +                      e = e->delta_sibling;
 +              }
 +      };
 +}
 +
 +static void add_family_to_write_order(struct object_entry **wo,
 +                                    unsigned int *endp,
 +                                    struct object_entry *e)
 +{
 +      struct object_entry *root;
 +
 +      for (root = e; root->delta; root = root->delta)
 +              ; /* nothing */
 +      add_descendants_to_write_order(wo, endp, root);
 +}
 +
 +static struct object_entry **compute_write_order(void)
 +{
 +      unsigned int i, wo_end, last_untagged;
 +
 +      struct object_entry **wo = xmalloc(nr_objects * sizeof(*wo));
 +
 +      for (i = 0; i < nr_objects; i++) {
 +              objects[i].tagged = 0;
 +              objects[i].filled = 0;
 +              objects[i].delta_child = NULL;
 +              objects[i].delta_sibling = NULL;
 +      }
 +
 +      /*
 +       * Fully connect delta_child/delta_sibling network.
 +       * Make sure delta_sibling is sorted in the original
 +       * recency order.
 +       */
 +      for (i = nr_objects; i > 0;) {
 +              struct object_entry *e = &objects[--i];
 +              if (!e->delta)
 +                      continue;
 +              /* Mark me as the first child */
 +              e->delta_sibling = e->delta->delta_child;
 +              e->delta->delta_child = e;
 +      }
 +
 +      /*
 +       * Mark objects that are at the tip of tags.
 +       */
 +      for_each_tag_ref(mark_tagged, NULL);
 +
 +      /*
 +       * Give the objects in the original recency order until
 +       * we see a tagged tip.
 +       */
 +      for (i = wo_end = 0; i < nr_objects; i++) {
 +              if (objects[i].tagged)
 +                      break;
 +              add_to_write_order(wo, &wo_end, &objects[i]);
 +      }
 +      last_untagged = i;
 +
 +      /*
 +       * Then fill all the tagged tips.
 +       */
 +      for (; i < nr_objects; i++) {
 +              if (objects[i].tagged)
 +                      add_to_write_order(wo, &wo_end, &objects[i]);
 +      }
 +
 +      /*
 +       * And then all remaining commits and tags.
 +       */
 +      for (i = last_untagged; i < nr_objects; i++) {
 +              if (objects[i].type != OBJ_COMMIT &&
 +                  objects[i].type != OBJ_TAG)
 +                      continue;
 +              add_to_write_order(wo, &wo_end, &objects[i]);
 +      }
 +
 +      /*
 +       * And then all the trees.
 +       */
 +      for (i = last_untagged; i < nr_objects; i++) {
 +              if (objects[i].type != OBJ_TREE)
 +                      continue;
 +              add_to_write_order(wo, &wo_end, &objects[i]);
 +      }
 +
 +      /*
 +       * Finally all the rest in really tight order
 +       */
 +      for (i = last_untagged; i < nr_objects; i++) {
 +              if (!objects[i].filled)
 +                      add_family_to_write_order(wo, &wo_end, &objects[i]);
 +      }
 +
 +      if (wo_end != nr_objects)
 +              die("ordered %u objects, expected %"PRIu32, wo_end, nr_objects);
 +
 +      return wo;
 +}
 +
  static void write_pack_file(void)
  {
        uint32_t i = 0, j;
        struct pack_header hdr;
        uint32_t nr_remaining = nr_result;
        time_t last_mtime = 0;
 +      struct object_entry **write_order;
  
        if (progress > pack_to_stdout)
                progress_state = start_progress("Writing objects", nr_result);
        written_list = xmalloc(nr_objects * sizeof(*written_list));
 +      write_order = compute_write_order();
  
        do {
                unsigned char sha1[20];
                offset = sizeof(hdr);
                nr_written = 0;
                for (; i < nr_objects; i++) {
 -                      if (!write_one(f, objects + i, &offset))
 +                      struct object_entry *e = write_order[i];
 +                      if (!write_one(f, e, &offset))
                                break;
                        display_progress(progress_state, written);
                }
                        const char *idx_tmp_name;
                        char tmpname[PATH_MAX];
  
 -                      idx_tmp_name = write_idx_file(NULL, written_list,
 -                                                    nr_written, sha1);
 +                      idx_tmp_name = write_idx_file(NULL, written_list, nr_written,
 +                                                    &pack_idx_opts, sha1);
  
                        snprintf(tmpname, sizeof(tmpname), "%s-%s.pack",
                                 base_name, sha1_to_hex(sha1));
        } while (nr_remaining && i < nr_objects);
  
        free(written_list);
 +      free(write_order);
        stop_progress(&progress_state);
        if (written != nr_result)
                die("wrote %"PRIu32" objects while expecting %"PRIu32,
@@@ -806,7 -633,7 +806,7 @@@ static int no_try_delta(const char *pat
        struct git_attr_check check[1];
  
        setup_delta_attr_check(check);
 -      if (git_checkattr(path, ARRAY_SIZE(check), check))
 +      if (git_check_attr(path, ARRAY_SIZE(check), check))
                return 0;
        if (ATTR_FALSE(check->value))
                return 1;
@@@ -1421,11 -1248,16 +1421,16 @@@ static int try_delta(struct unpacked *t
                return -1;
  
        /*
-        * We do not bother to try a delta that we discarded
-        * on an earlier try, but only when reusing delta data.
+        * We do not bother to try a delta that we discarded on an
+        * earlier try, but only when reusing delta data.  Note that
+        * src_entry that is marked as the preferred_base should always
+        * be considered, as even if we produce a suboptimal delta against
+        * it, we will still save the transfer cost, as we already know
+        * the other side has it and we won't send src_entry at all.
         */
        if (reuse_delta && trg_entry->in_pack &&
            trg_entry->in_pack == src_entry->in_pack &&
+           !src_entry->preferred_base &&
            trg_entry->in_pack_type != OBJ_REF_DELTA &&
            trg_entry->in_pack_type != OBJ_OFS_DELTA)
                return 0;
@@@ -2057,10 -1889,10 +2062,10 @@@ static int git_pack_config(const char *
                return 0;
        }
        if (!strcmp(k, "pack.indexversion")) {
 -              pack_idx_default_version = git_config_int(k, v);
 -              if (pack_idx_default_version > 2)
 +              pack_idx_opts.version = git_config_int(k, v);
 +              if (pack_idx_opts.version > 2)
                        die("bad pack.indexversion=%"PRIu32,
 -                              pack_idx_default_version);
 +                          pack_idx_opts.version);
                return 0;
        }
        if (!strcmp(k, "pack.packsizelimit")) {
@@@ -2307,7 -2139,6 +2312,7 @@@ int cmd_pack_objects(int argc, const ch
        rp_av[1] = "--objects"; /* --thin will make it --objects-edge */
        rp_ac = 2;
  
 +      reset_pack_idx_option(&pack_idx_opts);
        git_config(git_pack_config, NULL);
        if (!pack_compression_seen && core_compression_seen)
                pack_compression_level = core_compression_level;
                }
                if (!prefixcmp(arg, "--index-version=")) {
                        char *c;
 -                      pack_idx_default_version = strtoul(arg + 16, &c, 10);
 -                      if (pack_idx_default_version > 2)
 +                      pack_idx_opts.version = strtoul(arg + 16, &c, 10);
 +                      if (pack_idx_opts.version > 2)
                                die("bad %s", arg);
                        if (*c == ',')
 -                              pack_idx_off32_limit = strtoul(c+1, &c, 0);
 -                      if (*c || pack_idx_off32_limit & 0x80000000)
 +                              pack_idx_opts.off32_limit = strtoul(c+1, &c, 0);
 +                      if (*c || pack_idx_opts.off32_limit & 0x80000000)
                                die("bad %s", arg);
                        continue;
                }