streaming: read loose objects incrementally

Helped-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed May 14, 2011 at 19:17 UTC 93aa7bd595d37aec09b96da7ea9da89d9f659ebd
1 file changed +82 -3
streaming.c
+82 -3
@@ -61,8 +61,11 @@ struct git_istream {
61 } incore;
62
63 struct {
64 - int fd; /* open for reading */
65 - /* NEEDSWORK: what else? */
64 + void *mapped;
65 + unsigned long mapsize;
66 + char hdr[32];
67 + int hdr_avail;
68 + int hdr_used;
69 } loose;
70
71 struct {
@@ -150,9 +153,85 @@ static void close_deflated_stream(struct git_istream *st)
153 *
154 *****************************************************************/
155
156 +static read_method_decl(loose)
157 +{
158 + size_t total_read = 0;
159 +
160 + switch (st->z_state) {
161 + case z_done:
162 + return 0;
163 + case z_error:
164 + return -1;
165 + default:
166 + break;
167 + }
168 +
169 + if (st->u.loose.hdr_used < st->u.loose.hdr_avail) {
170 + size_t to_copy = st->u.loose.hdr_avail - st->u.loose.hdr_used;
171 + if (sz < to_copy)
172 + to_copy = sz;
173 + memcpy(buf, st->u.loose.hdr + st->u.loose.hdr_used, to_copy);
174 + st->u.loose.hdr_used += to_copy;
175 + total_read += to_copy;
176 + }
177 +
178 + while (total_read < sz) {
179 + int status;
180 +
181 + st->z.next_out = (unsigned char *)buf + total_read;
182 + st->z.avail_out = sz - total_read;
183 + status = git_inflate(&st->z, Z_FINISH);
184 +
185 + total_read = st->z.next_out - (unsigned char *)buf;
186 +
187 + if (status == Z_STREAM_END) {
188 + git_inflate_end(&st->z);
189 + st->z_state = z_done;
190 + break;
191 + }
192 + if (status != Z_OK && status != Z_BUF_ERROR) {
193 + git_inflate_end(&st->z);
194 + st->z_state = z_error;
195 + return -1;
196 + }
197 + }
198 + return total_read;
199 +}
200 +
201 +static close_method_decl(loose)
202 +{
203 + close_deflated_stream(st);
204 + munmap(st->u.loose.mapped, st->u.loose.mapsize);
205 + return 0;
206 +}
207 +
208 +static struct stream_vtbl loose_vtbl = {
209 + close_istream_loose,
210 + read_istream_loose,
211 +};
212 +
213 static open_method_decl(loose)
214 {
155 - return -1; /* for now */
215 + st->u.loose.mapped = map_sha1_file(sha1, &st->u.loose.mapsize);
216 + if (!st->u.loose.mapped)
217 + return -1;
218 + if (unpack_sha1_header(&st->z,
219 + st->u.loose.mapped,
220 + st->u.loose.mapsize,
221 + st->u.loose.hdr,
222 + sizeof(st->u.loose.hdr)) < 0) {
223 + git_inflate_end(&st->z);
224 + munmap(st->u.loose.mapped, st->u.loose.mapsize);
225 + return -1;
226 + }
227 +
228 + parse_sha1_header(st->u.loose.hdr, &st->size);
229 + st->u.loose.hdr_used = strlen(st->u.loose.hdr) + 1;
230 + st->u.loose.hdr_avail = st->z.total_out;
231 + st->z_state = z_used;
232 +
233 + st->vtbl = &loose_vtbl;
234 + return 0;
235 }
236
237