streaming: read non-delta incrementally from a pack
Helped-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
May 13, 2011 at 15:34 UTC
7ef2d9a2604b0cd554e59f948f2c879b3708dfa5
1 file changed
+102
-3
streaming.c
+102
-3
@@ -51,6 +51,8 @@ static open_istream_fn open_istream_tbl[] = {
51
struct git_istream {
52
const struct stream_vtbl *vtbl;
53
unsigned long size; /* inflated size of full object */
54
+ z_stream z;
55
+ enum { z_unused, z_used, z_done, z_error } z_state;
56
57
union {
58
struct {
@@ -64,8 +66,8 @@ struct git_istream {
66
} loose;
67
68
struct {
67
- int fd; /* open for reading */
68
- /* NEEDSWORK: what else? */
69
+ struct packed_git *pack;
70
+ off_t pos;
71
} in_pack;
72
} u;
73
};
@@ -128,6 +130,20 @@ struct git_istream *open_istream(const unsigned char *sha1,
130
return st;
131
}
132
133
+
134
+/*****************************************************************
135
+ *
136
+ * Common helpers
137
+ *
138
+ *****************************************************************/
139
+
140
+static void close_deflated_stream(struct git_istream *st)
141
+{
142
+ if (st->z_state == z_used)
143
+ git_inflate_end(&st->z);
144
+}
145
+
146
+
147
/*****************************************************************
148
*
149
* Loose object stream
@@ -146,9 +162,92 @@ static open_method_decl(loose)
162
*
163
*****************************************************************/
164
165
+static read_method_decl(pack_non_delta)
166
+{
167
+ size_t total_read = 0;
168
+
169
+ switch (st->z_state) {
170
+ case z_unused:
171
+ memset(&st->z, 0, sizeof(st->z));
172
+ git_inflate_init(&st->z);
173
+ st->z_state = z_used;
174
+ break;
175
+ case z_done:
176
+ return 0;
177
+ case z_error:
178
+ return -1;
179
+ case z_used:
180
+ break;
181
+ }
182
+
183
+ while (total_read < sz) {
184
+ int status;
185
+ struct pack_window *window = NULL;
186
+ unsigned char *mapped;
187
+
188
+ mapped = use_pack(st->u.in_pack.pack, &window,
189
+ st->u.in_pack.pos, &st->z.avail_in);
190
+
191
+ st->z.next_out = (unsigned char *)buf + total_read;
192
+ st->z.avail_out = sz - total_read;
193
+ st->z.next_in = mapped;
194
+ status = git_inflate(&st->z, Z_FINISH);
195
+
196
+ st->u.in_pack.pos += st->z.next_in - mapped;
197
+ total_read = st->z.next_out - (unsigned char *)buf;
198
+ unuse_pack(&window);
199
+
200
+ if (status == Z_STREAM_END) {
201
+ git_inflate_end(&st->z);
202
+ st->z_state = z_done;
203
+ break;
204
+ }
205
+ if (status != Z_OK && status != Z_BUF_ERROR) {
206
+ git_inflate_end(&st->z);
207
+ st->z_state = z_error;
208
+ return -1;
209
+ }
210
+ }
211
+ return total_read;
212
+}
213
+
214
+static close_method_decl(pack_non_delta)
215
+{
216
+ close_deflated_stream(st);
217
+ return 0;
218
+}
219
+
220
+static struct stream_vtbl pack_non_delta_vtbl = {
221
+ close_istream_pack_non_delta,
222
+ read_istream_pack_non_delta,
223
+};
224
+
225
static open_method_decl(pack_non_delta)
226
{
151
- return -1; /* for now */
227
+ struct pack_window *window;
228
+ enum object_type in_pack_type;
229
+
230
+ st->u.in_pack.pack = oi->u.packed.pack;
231
+ st->u.in_pack.pos = oi->u.packed.offset;
232
+ window = NULL;
233
+
234
+ in_pack_type = unpack_object_header(st->u.in_pack.pack,
235
+ &window,
236
+ &st->u.in_pack.pos,
237
+ &st->size);
238
+ unuse_pack(&window);
239
+ switch (in_pack_type) {
240
+ default:
241
+ return -1; /* we do not do deltas for now */
242
+ case OBJ_COMMIT:
243
+ case OBJ_TREE:
244
+ case OBJ_BLOB:
245
+ case OBJ_TAG:
246
+ break;
247
+ }
248
+ st->z_state = z_unused;
249
+ st->vtbl = &pack_non_delta_vtbl;
250
+ return 0;
251
}
252
253