X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=builtin-pack-objects.c;h=9b3ef94c4cea6eba9d79feb5c6647deb2e149daa;hb=8a1d076e21810f5bc7e9ef10d84f7ca9637b89af;hp=3d396ca37ac1356c7974aaaf34af39bcd0cf6bae;hpb=fe5e7f332c8a95680a869eaca8033213676cbc7b;p=git.git diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 3d396ca37..9b3ef94c4 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -16,8 +16,9 @@ #include "progress.h" static const char pack_usage[] = "\ -git-pack-objects [{ -q | --progress | --all-progress }] [--max-pack-size=N] \n\ - [--local] [--incremental] [--window=N] [--depth=N] \n\ +git-pack-objects [{ -q | --progress | --all-progress }] \n\ + [--max-pack-size=N] [--local] [--incremental] \n\ + [--window=N] [--window-memory=N] [--depth=N] \n\ [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\ [--non-empty] [--revs [--unpacked | --all]*] [--reflog] \n\ [--stdout | base-name] ["); } 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); } @@ -979,6 +979,8 @@ static void add_pbase_object(struct tree_desc *tree, 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) @@ -1270,11 +1272,11 @@ struct unpacked { 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; @@ -1303,6 +1305,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, struct object_entry *trg_entry = trg->entry; struct object_entry *src_entry = src->entry; unsigned long trg_size, src_size, delta_size, sizediff, max_size, sz; + unsigned ref_depth; enum object_type type; void *delta_buf; @@ -1327,34 +1330,49 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, 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. */ trg_size = trg_entry->size; - max_size = trg_size/2 - 20; - max_size = max_size * (max_depth - src_entry->depth) / max_depth; + if (!trg_entry->delta) { + max_size = trg_size/2 - 20; + ref_depth = 1; + } else { + max_size = trg_entry->delta_size; + ref_depth = trg->depth; + } + max_size = max_size * (max_depth - src->depth) / + (max_depth - ref_depth + 1); if (max_size == 0) return 0; - if (trg_entry->delta && trg_entry->delta_size <= max_size) - max_size = trg_entry->delta_size-1; src_size = src_entry->size; sizediff = src_size < trg_size ? trg_size - src_size : 0; if (sizediff >= max_size) return 0; + if (trg_size < src_size / 32) + 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); + window_memory_usage += sz; } 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); + window_memory_usage += sz; } if (!src->index) { src->index = create_delta_index(src->data, src_size); @@ -1364,6 +1382,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, warning("suboptimal pack - out of memory"); return 0; } + window_memory_usage += sizeof_delta_index(src->index); } delta_buf = create_delta(src->index, trg->data, trg_size, &delta_size, max_size); @@ -1371,15 +1390,21 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, return 0; if (trg_entry->delta_data) { + /* Prefer only shallower same-sized deltas. */ + if (delta_size == trg_entry->delta_size && + 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 = NULL; } - 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 (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 @@ -1400,9 +1425,23 @@ static unsigned int check_delta_limit(struct object_entry *me, unsigned int n) return m; } +static void free_unpacked(struct unpacked *n) +{ + window_memory_usage -= sizeof_delta_index(n->index); + free_delta_index(n->index); + n->index = NULL; + if (n->data) { + free(n->data); + n->data = NULL; + window_memory_usage -= n->entry->size; + } + n->entry = NULL; + n->depth = 0; +} + static void find_deltas(struct object_entry **list, int window, int depth) { - uint32_t i = nr_objects, idx = 0, processed = 0; + uint32_t i = nr_objects, idx = 0, count = 0, processed = 0; unsigned int array_size = window * sizeof(struct unpacked); struct unpacked *array; int max_depth; @@ -1437,12 +1476,17 @@ static void find_deltas(struct object_entry **list, int window, int depth) if (entry->no_try_delta) continue; - free_delta_index(n->index); - n->index = NULL; - free(n->data); - n->data = NULL; + free_unpacked(n); n->entry = entry; + while (window_memory_limit && + window_memory_usage > window_memory_limit && + count > 1) { + uint32_t tail = (idx + window - count) % window; + free_unpacked(array + tail); + count--; + } + /* * If the current object is at pack edge, take the depth the * objects that depend on the current object into account @@ -1472,11 +1516,13 @@ static void find_deltas(struct object_entry **list, int window, int depth) * 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; next: idx++; + if (count + 1 < window) + count++; if (idx >= window) idx = 0; } while (i > 0); @@ -1515,7 +1561,11 @@ static int git_pack_config(const char *k, const char *v) window = git_config_int(k, v); return 0; } - if(!strcmp(k, "pack.depth")) { + if (!strcmp(k, "pack.windowmemory")) { + window_memory_limit = git_config_ulong(k, v); + return 0; + } + if (!strcmp(k, "pack.depth")) { depth = git_config_int(k, v); return 0; } @@ -1691,6 +1741,11 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) usage(pack_usage); continue; } + if (!prefixcmp(arg, "--window-memory=")) { + if (!git_parse_ulong(arg+16, &window_memory_limit)) + usage(pack_usage); + continue; + } if (!prefixcmp(arg, "--depth=")) { char *end; depth = strtoul(arg+8, &end, 0);