X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=index-pack.c;h=ac20a46d1594ee1350b11d001f92bf0a8d887890;hb=588c038ac690e012a00dcace34fb318449f5ec7c;hp=8162265a63fca67f6a08bfca1047d3e45350b2fa;hpb=f41aebd46998c8b6df3733196d55aeb7162b3df6;p=git.git diff --git a/index-pack.c b/index-pack.c index 8162265a6..ac20a46d1 100644 --- a/index-pack.c +++ b/index-pack.c @@ -10,7 +10,7 @@ #include "fsck.h" static const char index_pack_usage[] = -"git-index-pack [-v] [-o ] [{ ---keep | --keep= }] [--strict] { | --stdin [--fix-thin] [] }"; +"git index-pack [-v] [-o ] [{ ---keep | --keep= }] [--strict] { | --stdin [--fix-thin] [] }"; struct object_entry { @@ -27,6 +27,9 @@ union delta_base { }; struct base_data { + struct base_data *base; + struct base_data *child; + struct object_entry *obj; void *data; unsigned long size; }; @@ -48,6 +51,8 @@ struct delta_entry static struct object_entry *objects; static struct delta_entry *deltas; +static struct base_data *base_cache; +static size_t base_cache_used; static int nr_objects; static int nr_deltas; static int nr_resolved_deltas; @@ -195,7 +200,8 @@ static void parse_pack_header(void) if (hdr->hdr_signature != htonl(PACK_SIGNATURE)) die("pack signature mismatch"); if (!pack_version_ok(hdr->hdr_version)) - die("pack version %d unsupported", ntohl(hdr->hdr_version)); + die("pack version %"PRIu32" unsupported", + ntohl(hdr->hdr_version)); nr_objects = ntohl(hdr->hdr_entries); use(sizeof(struct pack_header)); @@ -215,6 +221,46 @@ static void bad_object(unsigned long offset, const char *format, ...) die("pack has bad object at offset %lu: %s", offset, buf); } +static void prune_base_data(struct base_data *retain) +{ + struct base_data *b = base_cache; + for (b = base_cache; + base_cache_used > delta_base_cache_limit && b; + b = b->child) { + if (b->data && b != retain) { + free(b->data); + b->data = NULL; + base_cache_used -= b->size; + } + } +} + +static void link_base_data(struct base_data *base, struct base_data *c) +{ + if (base) + base->child = c; + else + base_cache = c; + + c->base = base; + c->child = NULL; + base_cache_used += c->size; + prune_base_data(c); +} + +static void unlink_base_data(struct base_data *c) +{ + struct base_data *base = c->base; + if (base) + base->child = NULL; + else + base_cache = NULL; + if (c->data) { + free(c->data); + base_cache_used -= c->size; + } +} + static void *unpack_entry_data(unsigned long offset, unsigned long size) { z_stream stream; @@ -430,6 +476,30 @@ static void sha1_object(const void *data, unsigned long size, } } +static void *get_base_data(struct base_data *c) +{ + if (!c->data) { + struct object_entry *obj = c->obj; + + if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA) { + void *base = get_base_data(c->base); + void *raw = get_data_from_pack(obj); + c->data = patch_delta( + base, c->base->size, + raw, obj->size, + &c->size); + free(raw); + if (!c->data) + bad_object(obj->idx.offset, "failed to apply delta"); + } else + c->data = get_data_from_pack(obj); + + base_cache_used += c->size; + prune_base_data(c); + } + return c->data; +} + static void resolve_delta(struct object_entry *delta_obj, struct base_data *base_obj, enum object_type type) { @@ -442,7 +512,7 @@ static void resolve_delta(struct object_entry *delta_obj, delta_obj->real_type = type; delta_data = get_data_from_pack(delta_obj); delta_size = delta_obj->size; - result.data = patch_delta(base_obj->data, base_obj->size, + result.data = patch_delta(get_base_data(base_obj), base_obj->size, delta_data, delta_size, &result.size); free(delta_data); @@ -451,6 +521,9 @@ static void resolve_delta(struct object_entry *delta_obj, sha1_object(result.data, result.size, type, delta_obj->idx.sha1); nr_resolved_deltas++; + result.obj = delta_obj; + link_base_data(base_obj, &result); + hashcpy(delta_base.sha1, delta_obj->idx.sha1); if (!find_delta_children(&delta_base, &first, &last)) { for (j = first; j <= last; j++) { @@ -470,7 +543,7 @@ static void resolve_delta(struct object_entry *delta_obj, } } - free(result.data); + unlink_base_data(&result); } static int compare_delta_entry(const void *a, const void *b) @@ -561,6 +634,8 @@ static void parse_pack_objects(unsigned char *sha1) continue; base_obj.data = get_data_from_pack(obj); base_obj.size = obj->size; + base_obj.obj = obj; + link_base_data(NULL, &base_obj); if (ref) for (j = ref_first; j <= ref_last; j++) { @@ -574,7 +649,7 @@ static void parse_pack_objects(unsigned char *sha1) if (child->real_type == OBJ_OFS_DELTA) resolve_delta(child, &base_obj, obj->type); } - free(base_obj.data); + unlink_base_data(&base_obj); display_progress(progress, nr_resolved_deltas); } } @@ -605,7 +680,8 @@ static int write_compressed(int fd, void *in, unsigned int size, uint32_t *obj_c return size; } -static void append_obj_to_pack(const unsigned char *sha1, void *buf, +static struct object_entry *append_obj_to_pack( + const unsigned char *sha1, void *buf, unsigned long size, enum object_type type) { struct object_entry *obj = &objects[nr_objects++]; @@ -626,6 +702,7 @@ static void append_obj_to_pack(const unsigned char *sha1, void *buf, obj[1].idx.offset = obj[0].idx.offset + n; obj[1].idx.offset += write_compressed(output_fd, buf, size, &obj[0].idx.crc32); hashcpy(obj->idx.sha1, sha1); + return obj; } static int delta_pos_compare(const void *_a, const void *_b) @@ -670,6 +747,13 @@ static void fix_unresolved_deltas(int nr_unresolved) if (!base_obj.data) continue; + if (check_sha1_signature(d->base.sha1, base_obj.data, + base_obj.size, typename(type))) + die("local object %s is corrupt", sha1_to_hex(d->base.sha1)); + base_obj.obj = append_obj_to_pack(d->base.sha1, base_obj.data, + base_obj.size, type); + link_base_data(NULL, &base_obj); + find_delta_children(&d->base, &first, &last); for (j = first; j <= last; j++) { struct object_entry *child = objects + deltas[j].obj_no; @@ -677,12 +761,7 @@ static void fix_unresolved_deltas(int nr_unresolved) resolve_delta(child, &base_obj, type); } - if (check_sha1_signature(d->base.sha1, base_obj.data, - base_obj.size, typename(type))) - die("local object %s is corrupt", sha1_to_hex(d->base.sha1)); - append_obj_to_pack(d->base.sha1, base_obj.data, - base_obj.size, type); - free(base_obj.data); + unlink_base_data(&base_obj); display_progress(progress, nr_resolved_deltas); } free(sorted_by_pos); @@ -777,7 +856,8 @@ static int git_index_pack_config(const char *k, const char *v, void *cb) if (!strcmp(k, "pack.indexversion")) { pack_idx_default_version = git_config_int(k, v); if (pack_idx_default_version > 2) - die("bad pack.indexversion=%d", pack_idx_default_version); + die("bad pack.indexversion=%"PRIu32, + pack_idx_default_version); return 0; } return git_default_config(k, v, cb);