aboutsummaryrefslogtreecommitdiff
path: root/pack-objects.c
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2006-02-17 20:58:45 -0800
committerJunio C Hamano <junkio@cox.net>2006-02-22 13:14:57 -0800
commit15b4d577ae2e0117b7b5a4add2217442a8458812 (patch)
treea848f93d0530f2c4d71ceac2dbea2c1314b4b481 /pack-objects.c
parent4181bda1567fc749623eac1c81c2b07c882d63b3 (diff)
downloadgit-15b4d577ae2e0117b7b5a4add2217442a8458812.tar.gz
git-15b4d577ae2e0117b7b5a4add2217442a8458812.tar.xz
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>
Diffstat (limited to 'pack-objects.c')
-rw-r--r--pack-objects.c43
1 files changed, 35 insertions, 8 deletions
diff --git a/pack-objects.c b/pack-objects.c
index 38e1c9921..0c9f4c9d2 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)