struct object_entry {
struct pack_idx_entry idx;
unsigned long size; /* uncompressed size */
-
- unsigned int hash; /* name hint hash */
- unsigned int depth; /* delta depth */
struct packed_git *in_pack; /* already in pack */
off_t in_pack_offset;
struct object_entry *delta; /* delta base object */
*/
void *delta_data; /* cached delta (uncompressed) */
unsigned long delta_size; /* delta data size (uncompressed) */
+ unsigned int hash; /* name hint hash */
enum object_type type;
enum object_type in_pack_type; /* could be delta */
unsigned char in_pack_header_size;
static int open_object_dir_tmp(const char *path)
{
snprintf(tmpname, sizeof(tmpname), "%s/%s", get_object_directory(), path);
- return mkstemp(tmpname);
+ return xmkstemp(tmpname);
}
/* forward declaration for write_pack_file */
f = sha1fd(1, "<stdout>");
} else {
int fd = open_object_dir_tmp("tmp_pack_XXXXXX");
- if (fd < 0)
- die("unable to create %s: %s\n", tmpname, strerror(errno));
pack_tmp_name = xstrdup(tmpname);
f = sha1fd(fd, pack_tmp_name);
}
int cmp;
while (tree_entry(tree,&entry)) {
+ if (S_ISGITLINK(entry.mode))
+ continue;
cmp = tree_entry_len(entry.path, entry.sha1) != cmplen ? 1 :
memcmp(name, entry.path, cmplen);
if (cmp > 0)
struct object_entry *entry;
void *data;
struct delta_index *index;
+ unsigned depth;
};
-static int delta_cacheable(struct unpacked *trg, struct unpacked *src,
- unsigned long src_size, unsigned long trg_size,
- unsigned long delta_size)
+static int delta_cacheable(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;
return 0;
/* Let's not bust the allowed depth. */
- if (src_entry->depth >= max_depth)
+ if (src->depth >= max_depth)
return 0;
/* Now some size filtering heuristics. */
ref_depth = 1;
} else {
max_size = trg_entry->delta_size;
- ref_depth = trg_entry->depth;
+ ref_depth = trg->depth;
}
- max_size = max_size * (max_depth - src_entry->depth) /
+ max_size = max_size * (max_depth - src->depth) /
(max_depth - ref_depth + 1);
if (max_size == 0)
return 0;
/* Load data if not already done */
if (!trg->data) {
trg->data = read_sha1_file(trg_entry->idx.sha1, &type, &sz);
+ if (!trg->data)
+ die("object %s cannot be read",
+ sha1_to_hex(trg_entry->idx.sha1));
if (sz != trg_size)
die("object %s inconsistent object length (%lu vs %lu)",
sha1_to_hex(trg_entry->idx.sha1), sz, trg_size);
}
if (!src->data) {
src->data = read_sha1_file(src_entry->idx.sha1, &type, &sz);
+ if (!src->data)
+ die("object %s cannot be read",
+ sha1_to_hex(src_entry->idx.sha1));
if (sz != src_size)
die("object %s inconsistent object length (%lu vs %lu)",
sha1_to_hex(src_entry->idx.sha1), sz, src_size);
if (!delta_buf)
return 0;
- if (trg_entry->delta_data) {
+ if (trg_entry->delta) {
/* Prefer only shallower same-sized deltas. */
if (delta_size == trg_entry->delta_size &&
- src_entry->depth + 1 >= trg_entry->depth) {
+ src->depth + 1 >= trg->depth) {
free(delta_buf);
return 0;
}
- 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_size = delta_size;
- trg_entry->depth = src_entry->depth + 1;
+ trg->depth = src->depth + 1;
- if (delta_cacheable(src, trg, src_size, trg_size, delta_size)) {
+ if (trg_entry->delta_data) {
+ delta_cache_size -= trg_entry->delta_size;
+ free(trg_entry->delta_data);
+ trg_entry->delta_data = NULL;
+ }
+
+ if (delta_cacheable(src_size, trg_size, delta_size)) {
trg_entry->delta_data = xrealloc(delta_buf, delta_size);
delta_cache_size += trg_entry->delta_size;
} else
window_memory_usage -= n->entry->size;
}
n->entry = NULL;
+ n->depth = 0;
}
static void find_deltas(struct object_entry **list, int window, int depth)
do {
struct object_entry *entry = list[--i];
struct unpacked *n = array + idx;
- int j;
+ int j, best_base = -1;
if (!entry->preferred_base)
processed++;
j = window;
while (--j > 0) {
+ int ret;
uint32_t other_idx = idx + j;
struct unpacked *m;
if (other_idx >= window)
m = array + other_idx;
if (!m->entry)
break;
- if (try_delta(n, m, max_depth) < 0)
+ ret = try_delta(n, m, max_depth);
+ if (ret < 0)
break;
+ else if (ret > 0)
+ best_base = other_idx;
}
/* if we made n a delta, and if n is already at max
* depth, leaving it in the window is pointless. we
* should evict it first.
*/
- if (entry->delta && depth <= entry->depth)
+ if (entry->delta && depth <= n->depth)
continue;
+ /*
+ * Move the best delta base up in the window, after the
+ * currently deltified object, to keep it longer. It will
+ * be the first base object to be attempted next.
+ */
+ if (entry->delta) {
+ struct unpacked swap = array[best_base];
+ int dist = (window + idx - best_base) % window;
+ int dst = best_base;
+ while (dist--) {
+ int src = (dst + 1) % window;
+ array[dst] = array[src];
+ dst = src;
+ }
+ array[dst] = swap;
+ }
+
next:
idx++;
if (count + 1 < window)