streaming: move zlib stream into backends

While all backend-specific data is now contained in a backend-specific structure, we still share the zlib stream across the loose and packed objects. Refactor the code and move it into the specific structures so that we fully detangle the different backends from one another. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Nov 23, 2025 at 19:59 UTC eb5abbb4e6a8c06f5c6275bbb541bf7d736171c5
1 file changed +52 -52
streaming.c
+52 -52
@@ -25,23 +25,8 @@ struct odb_read_stream {
25
26 enum object_type type;
27 unsigned long size; /* inflated size of full object */
28 - git_zstream z;
29 - enum { z_unused, z_used, z_done, z_error } z_state;
28 };
29
32 -/*****************************************************************
33 - *
34 - * Common helpers
35 - *
36 - *****************************************************************/
37 -
38 -static void close_deflated_stream(struct odb_read_stream *st)
39 -{
40 - if (st->z_state == z_used)
41 - git_inflate_end(&st->z);
42 -}
43 -
44 -
30 /*****************************************************************
31 *
32 * Filtered stream
@@ -150,6 +135,12 @@ static struct odb_read_stream *attach_stream_filter(struct odb_read_stream *st,
135
136 struct odb_loose_read_stream {
137 struct odb_read_stream base;
138 + git_zstream z;
139 + enum {
140 + ODB_LOOSE_READ_STREAM_INUSE,
141 + ODB_LOOSE_READ_STREAM_DONE,
142 + ODB_LOOSE_READ_STREAM_ERROR,
143 + } z_state;
144 void *mapped;
145 unsigned long mapsize;
146 char hdr[32];
@@ -162,10 +153,10 @@ static ssize_t read_istream_loose(struct odb_read_stream *_st, char *buf, size_t
153 struct odb_loose_read_stream *st = (struct odb_loose_read_stream *)_st;
154 size_t total_read = 0;
155
165 - switch (st->base.z_state) {
166 - case z_done:
156 + switch (st->z_state) {
157 + case ODB_LOOSE_READ_STREAM_DONE:
158 return 0;
168 - case z_error:
159 + case ODB_LOOSE_READ_STREAM_ERROR:
160 return -1;
161 default:
162 break;
@@ -183,20 +174,20 @@ static ssize_t read_istream_loose(struct odb_read_stream *_st, char *buf, size_t
174 while (total_read < sz) {
175 int status;
176
186 - st->base.z.next_out = (unsigned char *)buf + total_read;
187 - st->base.z.avail_out = sz - total_read;
188 - status = git_inflate(&st->base.z, Z_FINISH);
177 + st->z.next_out = (unsigned char *)buf + total_read;
178 + st->z.avail_out = sz - total_read;
179 + status = git_inflate(&st->z, Z_FINISH);
180
190 - total_read = st->base.z.next_out - (unsigned char *)buf;
181 + total_read = st->z.next_out - (unsigned char *)buf;
182
183 if (status == Z_STREAM_END) {
193 - git_inflate_end(&st->base.z);
194 - st->base.z_state = z_done;
184 + git_inflate_end(&st->z);
185 + st->z_state = ODB_LOOSE_READ_STREAM_DONE;
186 break;
187 }
188 if (status != Z_OK && (status != Z_BUF_ERROR || total_read < sz)) {
198 - git_inflate_end(&st->base.z);
199 - st->base.z_state = z_error;
189 + git_inflate_end(&st->z);
190 + st->z_state = ODB_LOOSE_READ_STREAM_ERROR;
191 return -1;
192 }
193 }
@@ -206,7 +197,8 @@ static ssize_t read_istream_loose(struct odb_read_stream *_st, char *buf, size_t
197 static int close_istream_loose(struct odb_read_stream *_st)
198 {
199 struct odb_loose_read_stream *st = (struct odb_loose_read_stream *)_st;
209 - close_deflated_stream(&st->base);
200 + if (st->z_state == ODB_LOOSE_READ_STREAM_INUSE)
201 + git_inflate_end(&st->z);
202 munmap(st->mapped, st->mapsize);
203 return 0;
204 }
@@ -238,7 +230,7 @@ static int open_istream_loose(struct odb_read_stream **out,
230 */
231 CALLOC_ARRAY(st, 1);
232
241 - switch (unpack_loose_header(&st->base.z, mapped, mapsize, st->hdr,
233 + switch (unpack_loose_header(&st->z, mapped, mapsize, st->hdr,
234 sizeof(st->hdr))) {
235 case ULHR_OK:
236 break;
@@ -256,8 +248,8 @@ static int open_istream_loose(struct odb_read_stream **out,
248 st->mapped = mapped;
249 st->mapsize = mapsize;
250 st->hdr_used = strlen(st->hdr) + 1;
259 - st->hdr_avail = st->base.z.total_out;
260 - st->base.z_state = z_used;
251 + st->hdr_avail = st->z.total_out;
252 + st->z_state = ODB_LOOSE_READ_STREAM_INUSE;
253 st->base.close = close_istream_loose;
254 st->base.read = read_istream_loose;
255
@@ -265,7 +257,7 @@ static int open_istream_loose(struct odb_read_stream **out,
257
258 return 0;
259 error:
268 - git_inflate_end(&st->base.z);
260 + git_inflate_end(&st->z);
261 munmap(st->mapped, st->mapsize);
262 free(st);
263 return -1;
@@ -281,6 +273,13 @@ error:
273 struct odb_packed_read_stream {
274 struct odb_read_stream base;
275 struct packed_git *pack;
276 + git_zstream z;
277 + enum {
278 + ODB_PACKED_READ_STREAM_UNINITIALIZED,
279 + ODB_PACKED_READ_STREAM_INUSE,
280 + ODB_PACKED_READ_STREAM_DONE,
281 + ODB_PACKED_READ_STREAM_ERROR,
282 + } z_state;
283 off_t pos;
284 };
285
@@ -290,17 +289,17 @@ static ssize_t read_istream_pack_non_delta(struct odb_read_stream *_st, char *bu
289 struct odb_packed_read_stream *st = (struct odb_packed_read_stream *)_st;
290 size_t total_read = 0;
291
293 - switch (st->base.z_state) {
294 - case z_unused:
295 - memset(&st->base.z, 0, sizeof(st->base.z));
296 - git_inflate_init(&st->base.z);
297 - st->base.z_state = z_used;
292 + switch (st->z_state) {
293 + case ODB_PACKED_READ_STREAM_UNINITIALIZED:
294 + memset(&st->z, 0, sizeof(st->z));
295 + git_inflate_init(&st->z);
296 + st->z_state = ODB_PACKED_READ_STREAM_INUSE;
297 break;
299 - case z_done:
298 + case ODB_PACKED_READ_STREAM_DONE:
299 return 0;
301 - case z_error:
300 + case ODB_PACKED_READ_STREAM_ERROR:
301 return -1;
303 - case z_used:
302 + case ODB_PACKED_READ_STREAM_INUSE:
303 break;
304 }
305
@@ -310,20 +309,20 @@ static ssize_t read_istream_pack_non_delta(struct odb_read_stream *_st, char *bu
309 unsigned char *mapped;
310
311 mapped = use_pack(st->pack, &window,
313 - st->pos, &st->base.z.avail_in);
312 + st->pos, &st->z.avail_in);
313
315 - st->base.z.next_out = (unsigned char *)buf + total_read;
316 - st->base.z.avail_out = sz - total_read;
317 - st->base.z.next_in = mapped;
318 - status = git_inflate(&st->base.z, Z_FINISH);
314 + st->z.next_out = (unsigned char *)buf + total_read;
315 + st->z.avail_out = sz - total_read;
316 + st->z.next_in = mapped;
317 + status = git_inflate(&st->z, Z_FINISH);
318
320 - st->pos += st->base.z.next_in - mapped;
321 - total_read = st->base.z.next_out - (unsigned char *)buf;
319 + st->pos += st->z.next_in - mapped;
320 + total_read = st->z.next_out - (unsigned char *)buf;
321 unuse_pack(&window);
322
323 if (status == Z_STREAM_END) {
325 - git_inflate_end(&st->base.z);
326 - st->base.z_state = z_done;
324 + git_inflate_end(&st->z);
325 + st->z_state = ODB_PACKED_READ_STREAM_DONE;
326 break;
327 }
328
@@ -336,8 +335,8 @@ static ssize_t read_istream_pack_non_delta(struct odb_read_stream *_st, char *bu
335 * or truncated), then use_pack() catches that and will die().
336 */
337 if (status != Z_OK && status != Z_BUF_ERROR) {
339 - git_inflate_end(&st->base.z);
340 - st->base.z_state = z_error;
338 + git_inflate_end(&st->z);
339 + st->z_state = ODB_PACKED_READ_STREAM_ERROR;
340 return -1;
341 }
342 }
@@ -347,7 +346,8 @@ static ssize_t read_istream_pack_non_delta(struct odb_read_stream *_st, char *bu
346 static int close_istream_pack_non_delta(struct odb_read_stream *_st)
347 {
348 struct odb_packed_read_stream *st = (struct odb_packed_read_stream *)_st;
350 - close_deflated_stream(&st->base);
349 + if (st->z_state == ODB_PACKED_READ_STREAM_INUSE)
350 + git_inflate_end(&st->z);
351 return 0;
352 }
353
@@ -384,7 +384,7 @@ static int open_istream_pack_non_delta(struct odb_read_stream **out,
384 stream->base.read = read_istream_pack_non_delta;
385 stream->base.type = in_pack_type;
386 stream->base.size = size;
387 - stream->base.z_state = z_unused;
387 + stream->z_state = ODB_PACKED_READ_STREAM_UNINITIALIZED;
388 stream->pack = pack;
389 stream->pos = offset;
390