Skip to content

Commit 595296e

Browse files
pks-tgitster
authored andcommitted
streaming: allocate stream inside the backend-specific logic
When creating a new stream we first allocate it and then call into backend-specific logic to populate the stream. This design requires that the stream itself contains a `union` with backend-specific members that then ultimately get populated by the backend-specific logic. This works, but it's awkward in the context of pluggable object databases. Each backend will need its own member in that union, and as the structure itself is completely opaque (it's only defined in "streaming.c") it also has the consequence that we must have the logic that is specific to backends in "streaming.c". Ideally though, the infrastructure would be reversed: we have a generic `struct odb_read_stream` and some helper functions in "streaming.c", whereas the backend-specific logic sits in the backend's subsystem itself. This can be realized by using a design that is similar to how we handle reference databases: instead of having a union of members, we instead have backend-specific structures with a `struct odb_read_stream base` as its first member. The backends would thus hand out the pointer to the base, but internally they know to cast back to the backend-specific type. This means though that we need to allocate different structures depending on the backend. To prepare for this, move allocation of the structure into the backend-specific functions that open a new stream. Subsequent commits will then create those new backend-specific structs. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 3c7722d commit 595296e

1 file changed

Lines changed: 65 additions & 38 deletions

File tree

streaming.c

Lines changed: 65 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -222,47 +222,63 @@ static int close_istream_loose(struct odb_read_stream *st)
222222
return 0;
223223
}
224224

225-
static int open_istream_loose(struct odb_read_stream *st, struct repository *r,
225+
static int open_istream_loose(struct odb_read_stream **out,
226+
struct repository *r,
226227
const struct object_id *oid)
227228
{
228229
struct object_info oi = OBJECT_INFO_INIT;
230+
struct odb_read_stream *st;
229231
struct odb_source *source;
230-
231-
oi.sizep = &st->size;
232-
oi.typep = &st->type;
232+
unsigned long mapsize;
233+
void *mapped;
233234

234235
odb_prepare_alternates(r->objects);
235236
for (source = r->objects->sources; source; source = source->next) {
236-
st->u.loose.mapped = odb_source_loose_map_object(source, oid,
237-
&st->u.loose.mapsize);
238-
if (st->u.loose.mapped)
237+
mapped = odb_source_loose_map_object(source, oid, &mapsize);
238+
if (mapped)
239239
break;
240240
}
241-
if (!st->u.loose.mapped)
241+
if (!mapped)
242242
return -1;
243243

244-
switch (unpack_loose_header(&st->z, st->u.loose.mapped,
245-
st->u.loose.mapsize, st->u.loose.hdr,
244+
/*
245+
* Note: we must allocate this structure early even though we may still
246+
* fail. This is because we need to initialize the zlib stream, and it
247+
* is not possible to copy the stream around after the fact because it
248+
* has self-referencing pointers.
249+
*/
250+
CALLOC_ARRAY(st, 1);
251+
252+
switch (unpack_loose_header(&st->z, mapped, mapsize, st->u.loose.hdr,
246253
sizeof(st->u.loose.hdr))) {
247254
case ULHR_OK:
248255
break;
249256
case ULHR_BAD:
250257
case ULHR_TOO_LONG:
251258
goto error;
252259
}
260+
261+
oi.sizep = &st->size;
262+
oi.typep = &st->type;
263+
253264
if (parse_loose_header(st->u.loose.hdr, &oi) < 0 || st->type < 0)
254265
goto error;
255266

267+
st->u.loose.mapped = mapped;
268+
st->u.loose.mapsize = mapsize;
256269
st->u.loose.hdr_used = strlen(st->u.loose.hdr) + 1;
257270
st->u.loose.hdr_avail = st->z.total_out;
258271
st->z_state = z_used;
259272
st->close = close_istream_loose;
260273
st->read = read_istream_loose;
261274

275+
*out = st;
276+
262277
return 0;
263278
error:
264279
git_inflate_end(&st->z);
265280
munmap(st->u.loose.mapped, st->u.loose.mapsize);
281+
free(st);
266282
return -1;
267283
}
268284

@@ -338,12 +354,16 @@ static int close_istream_pack_non_delta(struct odb_read_stream *st)
338354
return 0;
339355
}
340356

341-
static int open_istream_pack_non_delta(struct odb_read_stream *st,
357+
static int open_istream_pack_non_delta(struct odb_read_stream **out,
342358
struct repository *r UNUSED,
343359
const struct object_id *oid UNUSED,
344360
struct packed_git *pack,
345361
off_t offset)
346362
{
363+
struct odb_read_stream stream = {
364+
.close = close_istream_pack_non_delta,
365+
.read = read_istream_pack_non_delta,
366+
};
347367
struct pack_window *window;
348368
enum object_type in_pack_type;
349369

@@ -352,7 +372,7 @@ static int open_istream_pack_non_delta(struct odb_read_stream *st,
352372
in_pack_type = unpack_object_header(pack,
353373
&window,
354374
&offset,
355-
&st->size);
375+
&stream.size);
356376
unuse_pack(&window);
357377
switch (in_pack_type) {
358378
default:
@@ -363,12 +383,13 @@ static int open_istream_pack_non_delta(struct odb_read_stream *st,
363383
case OBJ_TAG:
364384
break;
365385
}
366-
st->type = in_pack_type;
367-
st->z_state = z_unused;
368-
st->close = close_istream_pack_non_delta;
369-
st->read = read_istream_pack_non_delta;
370-
st->u.in_pack.pack = pack;
371-
st->u.in_pack.pos = offset;
386+
stream.type = in_pack_type;
387+
stream.z_state = z_unused;
388+
stream.u.in_pack.pack = pack;
389+
stream.u.in_pack.pos = offset;
390+
391+
CALLOC_ARRAY(*out, 1);
392+
**out = stream;
372393

373394
return 0;
374395
}
@@ -400,27 +421,35 @@ static ssize_t read_istream_incore(struct odb_read_stream *st, char *buf, size_t
400421
return read_size;
401422
}
402423

403-
static int open_istream_incore(struct odb_read_stream *st, struct repository *r,
424+
static int open_istream_incore(struct odb_read_stream **out,
425+
struct repository *r,
404426
const struct object_id *oid)
405427
{
406428
struct object_info oi = OBJECT_INFO_INIT;
407-
408-
st->u.incore.read_ptr = 0;
409-
st->close = close_istream_incore;
410-
st->read = read_istream_incore;
411-
412-
oi.typep = &st->type;
413-
oi.sizep = &st->size;
414-
oi.contentp = (void **)&st->u.incore.buf;
415-
return odb_read_object_info_extended(r->objects, oid, &oi,
416-
OBJECT_INFO_DIE_IF_CORRUPT);
429+
struct odb_read_stream stream = {
430+
.close = close_istream_incore,
431+
.read = read_istream_incore,
432+
};
433+
int ret;
434+
435+
oi.typep = &stream.type;
436+
oi.sizep = &stream.size;
437+
oi.contentp = (void **)&stream.u.incore.buf;
438+
ret = odb_read_object_info_extended(r->objects, oid, &oi,
439+
OBJECT_INFO_DIE_IF_CORRUPT);
440+
if (ret)
441+
return ret;
442+
443+
CALLOC_ARRAY(*out, 1);
444+
**out = stream;
445+
return 0;
417446
}
418447

419448
/*****************************************************************************
420449
* static helpers variables and functions for users of streaming interface
421450
*****************************************************************************/
422451

423-
static int istream_source(struct odb_read_stream *st,
452+
static int istream_source(struct odb_read_stream **out,
424453
struct repository *r,
425454
const struct object_id *oid)
426455
{
@@ -435,21 +464,21 @@ static int istream_source(struct odb_read_stream *st,
435464

436465
switch (oi.whence) {
437466
case OI_LOOSE:
438-
if (open_istream_loose(st, r, oid) < 0)
467+
if (open_istream_loose(out, r, oid) < 0)
439468
break;
440469
return 0;
441470
case OI_PACKED:
442471
if (oi.u.packed.is_delta ||
443472
repo_settings_get_big_file_threshold(the_repository) >= size ||
444-
open_istream_pack_non_delta(st, r, oid, oi.u.packed.pack,
473+
open_istream_pack_non_delta(out, r, oid, oi.u.packed.pack,
445474
oi.u.packed.offset) < 0)
446475
break;
447476
return 0;
448477
default:
449478
break;
450479
}
451480

452-
return open_istream_incore(st, r, oid);
481+
return open_istream_incore(out, r, oid);
453482
}
454483

455484
/****************************************************************
@@ -474,14 +503,12 @@ struct odb_read_stream *open_istream(struct repository *r,
474503
unsigned long *size,
475504
struct stream_filter *filter)
476505
{
477-
struct odb_read_stream *st = xmalloc(sizeof(*st));
506+
struct odb_read_stream *st;
478507
const struct object_id *real = lookup_replace_object(r, oid);
479-
int ret = istream_source(st, r, real);
508+
int ret = istream_source(&st, r, real);
480509

481-
if (ret) {
482-
free(st);
510+
if (ret)
483511
return NULL;
484-
}
485512

486513
if (filter) {
487514
/* Add "&& !is_null_stream_filter(filter)" for performance */

0 commit comments

Comments
 (0)