diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2012-05-23 21:09:48 +0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2012-05-23 09:08:55 -0700 |
commit | 8a2e163ccd03a12696cbf7518c0b742d313b6f02 (patch) | |
tree | 7c099fe2cefec7422e90e2315a63d44d9c8d5a61 /builtin/index-pack.c | |
parent | index-pack: use streaming interface on large blobs (most of the time) (diff) | |
download | tgif-8a2e163ccd03a12696cbf7518c0b742d313b6f02.tar.xz |
index-pack: factor out unpack core from get_data_from_pack
This allows caller to consume large inflated object with a fixed
amount of memory.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'builtin/index-pack.c')
-rw-r--r-- | builtin/index-pack.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/builtin/index-pack.c b/builtin/index-pack.c index c7c2b88656..9129299cdd 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -504,7 +504,9 @@ static void *unpack_raw_entry(struct object_entry *obj, return data; } -static void *get_data_from_pack(struct object_entry *obj) +static void *unpack_data(struct object_entry *obj, + int (*consume)(const unsigned char *, unsigned long, void *), + void *cb_data) { off_t from = obj[0].idx.offset + obj[0].hdr_size; unsigned long len = obj[1].idx.offset - from; @@ -512,15 +514,16 @@ static void *get_data_from_pack(struct object_entry *obj) git_zstream stream; int status; - data = xmalloc(obj->size); + data = xmalloc(consume ? 64*1024 : obj->size); inbuf = xmalloc((len < 64*1024) ? len : 64*1024); memset(&stream, 0, sizeof(stream)); git_inflate_init(&stream); stream.next_out = data; - stream.avail_out = obj->size; + stream.avail_out = consume ? 64*1024 : obj->size; do { + unsigned char *last_out = stream.next_out; ssize_t n = (len < 64*1024) ? len : 64*1024; n = pread(pack_fd, inbuf, n, from); if (n < 0) @@ -535,6 +538,15 @@ static void *get_data_from_pack(struct object_entry *obj) stream.next_in = inbuf; stream.avail_in = n; status = git_inflate(&stream, 0); + if (consume) { + if (consume(last_out, stream.next_out - last_out, cb_data)) { + free(inbuf); + free(data); + return NULL; + } + stream.next_out = data; + stream.avail_out = 64*1024; + } } while (len && status == Z_OK && !stream.avail_in); /* This has been inflated OK when first encountered, so... */ @@ -543,9 +555,18 @@ static void *get_data_from_pack(struct object_entry *obj) git_inflate_end(&stream); free(inbuf); + if (consume) { + free(data); + data = NULL; + } return data; } +static void *get_data_from_pack(struct object_entry *obj) +{ + return unpack_data(obj, NULL, NULL); +} + static int compare_delta_bases(const union delta_base *base1, const union delta_base *base2, enum object_type type1, |