Merge branch 'np/pack'
* np/pack: fix repack with --max-pack-size builtin-pack-object: cache small deltas git-pack-objects: cache small deltas between big objects builtin-pack-objects: don't fail, if delta is not possible
This commit is contained in:
@ -568,6 +568,15 @@ pack.compression::
|
|||||||
slowest. If not set, defaults to core.compression. If that is
|
slowest. If not set, defaults to core.compression. If that is
|
||||||
not set, defaults to -1.
|
not set, defaults to -1.
|
||||||
|
|
||||||
|
pack.deltaCacheSize::
|
||||||
|
The maxium memory in bytes used for caching deltas in
|
||||||
|
gitlink:git-pack-objects[1].
|
||||||
|
A value of 0 means no limit. Defaults to 0.
|
||||||
|
|
||||||
|
pack.deltaCacheLimit::
|
||||||
|
The maxium size of a delta, that is cached in
|
||||||
|
gitlink:git-pack-objects[1]. Defaults to 1000.
|
||||||
|
|
||||||
pull.octopus::
|
pull.octopus::
|
||||||
The default merge strategy to use when pulling multiple branches
|
The default merge strategy to use when pulling multiple branches
|
||||||
at once.
|
at once.
|
||||||
|
@ -36,6 +36,7 @@ struct object_entry {
|
|||||||
struct object_entry *delta_sibling; /* other deltified objects who
|
struct object_entry *delta_sibling; /* other deltified objects who
|
||||||
* uses the same base as me
|
* uses the same base as me
|
||||||
*/
|
*/
|
||||||
|
void *delta_data; /* cached delta (uncompressed) */
|
||||||
unsigned long delta_size; /* delta data size (uncompressed) */
|
unsigned long delta_size; /* delta data size (uncompressed) */
|
||||||
enum object_type type;
|
enum object_type type;
|
||||||
enum object_type in_pack_type; /* could be delta */
|
enum object_type in_pack_type; /* could be delta */
|
||||||
@ -76,6 +77,10 @@ static struct progress progress_state;
|
|||||||
static int pack_compression_level = Z_DEFAULT_COMPRESSION;
|
static int pack_compression_level = Z_DEFAULT_COMPRESSION;
|
||||||
static int pack_compression_seen;
|
static int pack_compression_seen;
|
||||||
|
|
||||||
|
static unsigned long delta_cache_size = 0;
|
||||||
|
static unsigned long max_delta_cache_size = 0;
|
||||||
|
static unsigned long cache_max_small_delta_size = 1000;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The object names in objects array are hashed with this hashtable,
|
* The object names in objects array are hashed with this hashtable,
|
||||||
* to help looking up the entry by object name.
|
* to help looking up the entry by object name.
|
||||||
@ -405,24 +410,24 @@ static unsigned long write_object(struct sha1file *f,
|
|||||||
z_stream stream;
|
z_stream stream;
|
||||||
unsigned long maxsize;
|
unsigned long maxsize;
|
||||||
void *out;
|
void *out;
|
||||||
buf = read_sha1_file(entry->sha1, &type, &size);
|
if (!usable_delta) {
|
||||||
if (!buf)
|
buf = read_sha1_file(entry->sha1, &obj_type, &size);
|
||||||
die("unable to read %s", sha1_to_hex(entry->sha1));
|
if (!buf)
|
||||||
if (size != entry->size)
|
die("unable to read %s", sha1_to_hex(entry->sha1));
|
||||||
die("object %s size inconsistency (%lu vs %lu)",
|
} else if (entry->delta_data) {
|
||||||
sha1_to_hex(entry->sha1), size, entry->size);
|
size = entry->delta_size;
|
||||||
if (usable_delta) {
|
buf = entry->delta_data;
|
||||||
|
entry->delta_data = NULL;
|
||||||
|
obj_type = (allow_ofs_delta && entry->delta->offset) ?
|
||||||
|
OBJ_OFS_DELTA : OBJ_REF_DELTA;
|
||||||
|
} else {
|
||||||
|
buf = read_sha1_file(entry->sha1, &type, &size);
|
||||||
|
if (!buf)
|
||||||
|
die("unable to read %s", sha1_to_hex(entry->sha1));
|
||||||
buf = delta_against(buf, size, entry);
|
buf = delta_against(buf, size, entry);
|
||||||
size = entry->delta_size;
|
size = entry->delta_size;
|
||||||
obj_type = (allow_ofs_delta && entry->delta->offset) ?
|
obj_type = (allow_ofs_delta && entry->delta->offset) ?
|
||||||
OBJ_OFS_DELTA : OBJ_REF_DELTA;
|
OBJ_OFS_DELTA : OBJ_REF_DELTA;
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* recover real object type in case
|
|
||||||
* check_object() wanted to re-use a delta,
|
|
||||||
* but we couldn't since base was in previous split pack
|
|
||||||
*/
|
|
||||||
obj_type = type;
|
|
||||||
}
|
}
|
||||||
/* compress the data to store and put compressed length in datalen */
|
/* compress the data to store and put compressed length in datalen */
|
||||||
memset(&stream, 0, sizeof(stream));
|
memset(&stream, 0, sizeof(stream));
|
||||||
@ -1385,6 +1390,23 @@ struct unpacked {
|
|||||||
struct delta_index *index;
|
struct delta_index *index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int delta_cacheable(struct unpacked *trg, struct unpacked *src,
|
||||||
|
unsigned long src_size, unsigned long trg_size,
|
||||||
|
unsigned long delta_size)
|
||||||
|
{
|
||||||
|
if (max_delta_cache_size && delta_cache_size + delta_size > max_delta_cache_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (delta_size < cache_max_small_delta_size)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* cache delta, if objects are large enough compared to delta size */
|
||||||
|
if ((src_size >> 20) + (trg_size >> 21) > (delta_size >> 10))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We search for deltas _backwards_ in a list sorted by type and
|
* We search for deltas _backwards_ in a list sorted by type and
|
||||||
* by size, so that we see progressively smaller and smaller files.
|
* by size, so that we see progressively smaller and smaller files.
|
||||||
@ -1454,18 +1476,32 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
|
|||||||
}
|
}
|
||||||
if (!src->index) {
|
if (!src->index) {
|
||||||
src->index = create_delta_index(src->data, src_size);
|
src->index = create_delta_index(src->data, src_size);
|
||||||
if (!src->index)
|
if (!src->index) {
|
||||||
die("out of memory");
|
static int warned = 0;
|
||||||
|
if (!warned++)
|
||||||
|
warning("suboptimal pack - out of memory");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delta_buf = create_delta(src->index, trg->data, trg_size, &delta_size, max_size);
|
delta_buf = create_delta(src->index, trg->data, trg_size, &delta_size, max_size);
|
||||||
if (!delta_buf)
|
if (!delta_buf)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (trg_entry->delta_data) {
|
||||||
|
delta_cache_size -= trg_entry->delta_size;
|
||||||
|
free(trg_entry->delta_data);
|
||||||
|
}
|
||||||
|
trg_entry->delta_data = 0;
|
||||||
trg_entry->delta = src_entry;
|
trg_entry->delta = src_entry;
|
||||||
trg_entry->delta_size = delta_size;
|
trg_entry->delta_size = delta_size;
|
||||||
trg_entry->depth = src_entry->depth + 1;
|
trg_entry->depth = src_entry->depth + 1;
|
||||||
free(delta_buf);
|
|
||||||
|
if (delta_cacheable(src, trg, src_size, trg_size, delta_size)) {
|
||||||
|
trg_entry->delta_data = xrealloc(delta_buf, delta_size);
|
||||||
|
delta_cache_size += trg_entry->delta_size;
|
||||||
|
} else
|
||||||
|
free(delta_buf);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1611,6 +1647,14 @@ static int git_pack_config(const char *k, const char *v)
|
|||||||
pack_compression_seen = 1;
|
pack_compression_seen = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(k, "pack.deltacachesize")) {
|
||||||
|
max_delta_cache_size = git_config_int(k, v);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!strcmp(k, "pack.deltacachelimit")) {
|
||||||
|
cache_max_small_delta_size = git_config_int(k, v);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return git_default_config(k, v);
|
return git_default_config(k, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user