index-pack: smarter memory usage when resolving deltas

In the same spirit as commit 9892bebafe, let's avoid allocating the full
buffer for the deflated data in get_data_from_pack() in order to inflate
it.  Let's read and inflate the data in chunks instead to reduce memory
usage.

Signed-off-by: Nicolas Pitre <nico@fluxnic.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Nicolas Pitre 2010-04-12 12:11:07 -04:00 committed by Junio C Hamano
parent 748af44c63
commit 776ea3707a
1 changed files with 25 additions and 21 deletions

View File

@ -359,34 +359,38 @@ static void *get_data_from_pack(struct object_entry *obj)
{ {
off_t from = obj[0].idx.offset + obj[0].hdr_size; off_t from = obj[0].idx.offset + obj[0].hdr_size;
unsigned long len = obj[1].idx.offset - from; unsigned long len = obj[1].idx.offset - from;
unsigned long rdy = 0; unsigned char *data, *inbuf;
unsigned char *src, *data;
z_stream stream; z_stream stream;
int st; int status;

data = xmalloc(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;


src = xmalloc(len);
data = src;
do { do {
ssize_t n = pread(pack_fd, data + rdy, len - rdy, from + rdy); ssize_t n = (len < 64*1024) ? len : 64*1024;
n = pread(pack_fd, inbuf, n, from);
if (n < 0) if (n < 0)
die_errno("cannot pread pack file"); die_errno("cannot pread pack file");
if (!n) if (!n)
die("premature end of pack file, %lu bytes missing", die("premature end of pack file, %lu bytes missing", len);
len - rdy); from += n;
rdy += n; len -= n;
} while (rdy < len); stream.next_in = inbuf;
data = xmalloc(obj->size); stream.avail_in = n;
memset(&stream, 0, sizeof(stream)); status = git_inflate(&stream, 0);
stream.next_out = data; } while (len && status == Z_OK && !stream.avail_in);
stream.avail_out = obj->size;
stream.next_in = src; /* This has been inflated OK when first encountered, so... */
stream.avail_in = len; if (status != Z_STREAM_END || stream.total_out != obj->size)
git_inflate_init(&stream);
while ((st = git_inflate(&stream, Z_FINISH)) == Z_OK);
git_inflate_end(&stream);
if (st != Z_STREAM_END || stream.total_out != obj->size)
die("serious inflate inconsistency"); die("serious inflate inconsistency");
free(src);
git_inflate_end(&stream);
free(inbuf);
return data; return data;
} }