Browse Source

send-pack: use buffered I/O to talk to pack-objects

We start a pack-objects process and then write all of the
positive and negative sha1s to it over a pipe. We do so by
formatting each item into a fixed-size buffer and then
writing each individually. This has two drawbacks:

  1. There's some manual computation of the buffer size,
     which is not immediately obvious is correct (though it
     is).

  2. We write() once per sha1, which means a lot more system
     calls than are necessary.

We can solve both by wrapping the pipe descriptor in a stdio
handle; this is the same technique used by upload-pack when
serving fetches.

Note that we can also simplify and improve the error
handling here. The original detected a single write error
and broke out of the loop (presumably to avoid writing the
error message over and over), but never actually acted on
seeing an error; we just fed truncated input and took
whatever pack-objects returned.

In practice, this probably didn't matter, as the likely
errors would be caused by pack-objects dying (and we'd
probably just die with SIGPIPE anyway). But we can easily
make this simpler and more robust; the stdio handle keeps an
error flag, which we can check at the end.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Jeff King 9 years ago committed by Junio C Hamano
parent
commit
f0bca72dc7
  1. 33
      send-pack.c

33
send-pack.c

@ -36,18 +36,15 @@ int option_parse_push_signed(const struct option *opt,
die("bad %s argument: %s", opt->long_name, arg); die("bad %s argument: %s", opt->long_name, arg);
} }


static int feed_object(const unsigned char *sha1, int fd, int negative) static void feed_object(const unsigned char *sha1, FILE *fh, int negative)
{ {
char buf[42];

if (negative && !has_sha1_file(sha1)) if (negative && !has_sha1_file(sha1))
return 1; return;


memcpy(buf + negative, sha1_to_hex(sha1), 40);
if (negative) if (negative)
buf[0] = '^'; putc('^', fh);
buf[40 + negative] = '\n'; fputs(sha1_to_hex(sha1), fh);
return write_or_whine(fd, buf, 41 + negative, "send-pack: send refs"); putc('\n', fh);
} }


/* /*
@ -73,6 +70,7 @@ static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, stru
NULL, NULL,
}; };
struct child_process po = CHILD_PROCESS_INIT; struct child_process po = CHILD_PROCESS_INIT;
FILE *po_in;
int i; int i;


i = 4; i = 4;
@ -97,21 +95,22 @@ static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, stru
* We feed the pack-objects we just spawned with revision * We feed the pack-objects we just spawned with revision
* parameters by writing to the pipe. * parameters by writing to the pipe.
*/ */
po_in = xfdopen(po.in, "w");
for (i = 0; i < extra->nr; i++) for (i = 0; i < extra->nr; i++)
if (!feed_object(extra->sha1[i], po.in, 1)) feed_object(extra->sha1[i], po_in, 1);
break;


while (refs) { while (refs) {
if (!is_null_oid(&refs->old_oid) && if (!is_null_oid(&refs->old_oid))
!feed_object(refs->old_oid.hash, po.in, 1)) feed_object(refs->old_oid.hash, po_in, 1);
break; if (!is_null_oid(&refs->new_oid))
if (!is_null_oid(&refs->new_oid) && feed_object(refs->new_oid.hash, po_in, 0);
!feed_object(refs->new_oid.hash, po.in, 0))
break;
refs = refs->next; refs = refs->next;
} }


close(po.in); fflush(po_in);
if (ferror(po_in))
die_errno("error writing to pack-objects");
fclose(po_in);


if (args->stateless_rpc) { if (args->stateless_rpc) {
char *buf = xmalloc(LARGE_PACKET_MAX); char *buf = xmalloc(LARGE_PACKET_MAX);

Loading…
Cancel
Save