Merge branch 'jc/maint-pack-object-cycle' into maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 14 Dec 2011 06:04:50 +0000 (22:04 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 14 Dec 2011 06:04:50 +0000 (22:04 -0800)
* jc/maint-pack-object-cycle:
  pack-object: tolerate broken packs that have duplicated objects

Conflicts:
builtin/pack-objects.c

1  2 
builtin/pack-objects.c

@@@ -435,173 -461,9 +466,173 @@@ static enum write_one_status write_one(
        if (signed_add_overflows(*offset, size))
                die("pack too large for current definition of off_t");
        *offset += size;
-       return 1;
+       return WRITE_ONE_WRITTEN;
  }
  
 +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;
                offset = sizeof(hdr);
                nr_written = 0;
                for (; i < nr_objects; i++) {
 -                      if (write_one(f, objects + i, &offset) == WRITE_ONE_BREAK)
 +                      struct object_entry *e = write_order[i];
-                       if (!write_one(f, e, &offset))
++                      if (write_one(f, e, &offset) == WRITE_ONE_BREAK)
                                break;
                        display_progress(progress_state, written);
                }