diff options
author | Junio C Hamano <junkio@cox.net> | 2006-02-18 07:58:45 +0300 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2006-02-23 00:14:57 +0300 |
commit | 15b4d577ae2e0117b7b5a4add2217442a8458812 (patch) | |
tree | a848f93d0530f2c4d71ceac2dbea2c1314b4b481 | |
parent | 4181bda1567fc749623eac1c81c2b07c882d63b3 (diff) |
pack-objects: avoid delta chains that are too long.
This tries to rework the solution for the excess delta chain
problem. An earlier commit worked it around ``cheaply'', but
repeated repacking risks unbound growth of delta chains.
This version counts the length of delta chain we are reusing
from the existing pack, and makes sure a base object that has
sufficiently long delta chain does not get deltified.
Signed-off-by: Junio C Hamano <junkio@cox.net>
-rw-r--r-- | pack-objects.c | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/pack-objects.c b/pack-objects.c index 38e1c9921b..0c9f4c9d23 100644 --- a/pack-objects.c +++ b/pack-objects.c @@ -10,16 +10,22 @@ static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--no struct object_entry { unsigned char sha1[20]; unsigned long size; /* uncompressed size */ - unsigned long offset; /* offset into the final pack file (nonzero if already written) */ + unsigned long offset; /* offset into the final pack file; + * nonzero if already written. + */ unsigned int depth; /* delta depth */ + unsigned int delta_limit; /* base adjustment for in-pack delta */ unsigned int hash; /* name hint hash */ enum object_type type; - unsigned char edge; /* reused delta chain points at this entry. */ enum object_type in_pack_type; /* could be delta */ unsigned long delta_size; /* delta data size (uncompressed) */ struct object_entry *delta; /* delta base object */ struct packed_git *in_pack; /* already in pack */ unsigned int in_pack_offset; + struct object_entry *delta_child; /* delitified objects who bases me */ + struct object_entry *delta_sibling; /* other deltified objects who + * uses the same base as me + */ }; /* @@ -470,7 +476,8 @@ static void check_object(struct object_entry *entry) entry->delta = base_entry; entry->type = OBJ_DELTA; - base_entry->edge = 1; + entry->delta_sibling = base_entry->delta_child; + base_entry->delta_child = entry; return; } @@ -513,15 +520,32 @@ static void hash_objects(void) } } +static unsigned int check_delta_limit(struct object_entry *me, unsigned int n) +{ + struct object_entry *child = me->delta_child; + unsigned int m = n; + while (child) { + unsigned int c = check_delta_limit(child, n + 1); + if (m < c) + m = c; + child = child->delta_sibling; + } + return m; +} + static void get_object_details(void) { int i; - struct object_entry *entry = objects; + struct object_entry *entry; hash_objects(); prepare_pack_ix(); - for (i = 0; i < nr_objects; i++) - check_object(entry++); + for (i = 0, entry = objects; i < nr_objects; i++, entry++) + check_object(entry); + for (i = 0, entry = objects; i < nr_objects; i++, entry++) + if (!entry->delta && entry->delta_child) + entry->delta_limit = + check_delta_limit(entry, 1); } typedef int (*entry_sort_t)(const struct object_entry *, const struct object_entry *); @@ -598,8 +622,11 @@ static int try_delta(struct unpacked *cur, struct unpacked *old, unsigned max_de * that depend on the current object into account -- otherwise * they would become too deep. */ - if (cur_entry->edge) - max_depth /= 4; + if (cur_entry->delta_child) { + if (max_depth <= cur_entry->delta_limit) + return 0; + max_depth -= cur_entry->delta_limit; + } size = cur_entry->size; if (size < 50) |