mirror of
https://github.com/git/git
synced 2024-08-24 18:26:02 +00:00
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>
This commit is contained in:
parent
4181bda156
commit
15b4d577ae
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue