pkt-line: introduce struct packet_writer

A future patch will allow the client to request multiplexing of the entire fetch response (and not only during packfile transmission), which in turn allows the server to send progress and keepalive messages at any time during the response. It will be convenient for a future patch if writing options (specifically, whether the written data is to be multiplexed) could be controlled from a single place, so create struct packet_writer to serve as that place, and modify upload-pack to use it. Currently, it only stores the output fd, but a subsequent patch will (as described above) introduce an option to determine if the written data is to be multiplexed. Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jonathan Tan committed Jan 15, 2019 at 11:40 UTC bc2e795cea607e444a9f985b0dbed5a4d25921c8
3 files changed +115 -58
pkt-line.c
+41 -6
@@ -129,12 +129,14 @@ static void set_packet_header(char *buf, const int size)
129 #undef hex
130 }
131
132 -static void format_packet(struct strbuf *out, const char *fmt, va_list args)
132 +static void format_packet(struct strbuf *out, const char *prefix,
133 + const char *fmt, va_list args)
134 {
135 size_t orig_len, n;
136
137 orig_len = out->len;
138 strbuf_addstr(out, "0000");
139 + strbuf_addstr(out, prefix);
140 strbuf_vaddf(out, fmt, args);
141 n = out->len - orig_len;
142
@@ -145,13 +147,13 @@ static void format_packet(struct strbuf *out, const char *fmt, va_list args)
147 packet_trace(out->buf + orig_len + 4, n - 4, 1);
148 }
149
148 -static int packet_write_fmt_1(int fd, int gently,
150 +static int packet_write_fmt_1(int fd, int gently, const char *prefix,
151 const char *fmt, va_list args)
152 {
153 static struct strbuf buf = STRBUF_INIT;
154
155 strbuf_reset(&buf);
154 - format_packet(&buf, fmt, args);
156 + format_packet(&buf, prefix, fmt, args);
157 if (write_in_full(fd, buf.buf, buf.len) < 0) {
158 if (!gently) {
159 check_pipe(errno);
@@ -168,7 +170,7 @@ void packet_write_fmt(int fd, const char *fmt, ...)
170 va_list args;
171
172 va_start(args, fmt);
171 - packet_write_fmt_1(fd, 0, fmt, args);
173 + packet_write_fmt_1(fd, 0, "", fmt, args);
174 va_end(args);
175 }
176
@@ -178,7 +180,7 @@ int packet_write_fmt_gently(int fd, const char *fmt, ...)
180 va_list args;
181
182 va_start(args, fmt);
181 - status = packet_write_fmt_1(fd, 1, fmt, args);
183 + status = packet_write_fmt_1(fd, 1, "", fmt, args);
184 va_end(args);
185 return status;
186 }
@@ -211,7 +213,7 @@ void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
213 va_list args;
214
215 va_start(args, fmt);
214 - format_packet(buf, fmt, args);
216 + format_packet(buf, "", fmt, args);
217 va_end(args);
218 }
219
@@ -486,3 +488,36 @@ enum packet_read_status packet_reader_peek(struct packet_reader *reader)
488 reader->line_peeked = 1;
489 return reader->status;
490 }
491 +
492 +void packet_writer_init(struct packet_writer *writer, int dest_fd)
493 +{
494 + writer->dest_fd = dest_fd;
495 +}
496 +
497 +void packet_writer_write(struct packet_writer *writer, const char *fmt, ...)
498 +{
499 + va_list args;
500 +
501 + va_start(args, fmt);
502 + packet_write_fmt_1(writer->dest_fd, 0, "", fmt, args);
503 + va_end(args);
504 +}
505 +
506 +void packet_writer_error(struct packet_writer *writer, const char *fmt, ...)
507 +{
508 + va_list args;
509 +
510 + va_start(args, fmt);
511 + packet_write_fmt_1(writer->dest_fd, 0, "ERR ", fmt, args);
512 + va_end(args);
513 +}
514 +
515 +void packet_writer_delim(struct packet_writer *writer)
516 +{
517 + packet_delim(writer->dest_fd);
518 +}
519 +
520 +void packet_writer_flush(struct packet_writer *writer)
521 +{
522 + packet_flush(writer->dest_fd);
523 +}
pkt-line.h
+14
@@ -183,4 +183,18 @@ extern enum packet_read_status packet_reader_peek(struct packet_reader *reader);
183 #define LARGE_PACKET_DATA_MAX (LARGE_PACKET_MAX - 4)
184 extern char packet_buffer[LARGE_PACKET_MAX];
185
186 +struct packet_writer {
187 + int dest_fd;
188 +};
189 +
190 +void packet_writer_init(struct packet_writer *writer, int dest_fd);
191 +
192 +/* These functions die upon failure. */
193 +__attribute__((format (printf, 2, 3)))
194 +void packet_writer_write(struct packet_writer *writer, const char *fmt, ...);
195 +__attribute__((format (printf, 2, 3)))
196 +void packet_writer_error(struct packet_writer *writer, const char *fmt, ...);
197 +void packet_writer_delim(struct packet_writer *writer);
198 +void packet_writer_flush(struct packet_writer *writer);
199 +
200 #endif
upload-pack.c
+60 -52
@@ -613,13 +613,14 @@ error:
613 }
614 }
615
616 -static void send_shallow(struct commit_list *result)
616 +static void send_shallow(struct packet_writer *writer,
617 + struct commit_list *result)
618 {
619 while (result) {
620 struct object *object = &result->item->object;
621 if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {
621 - packet_write_fmt(1, "shallow %s",
622 - oid_to_hex(&object->oid));
622 + packet_writer_write(writer, "shallow %s",
623 + oid_to_hex(&object->oid));
624 register_shallow(the_repository, &object->oid);
625 shallow_nr++;
626 }
@@ -627,7 +628,8 @@ static void send_shallow(struct commit_list *result)
628 }
629 }
630
630 -static void send_unshallow(const struct object_array *shallows,
631 +static void send_unshallow(struct packet_writer *writer,
632 + const struct object_array *shallows,
633 struct object_array *want_obj)
634 {
635 int i;
@@ -636,8 +638,8 @@ static void send_unshallow(const struct object_array *shallows,
638 struct object *object = shallows->objects[i].item;
639 if (object->flags & NOT_SHALLOW) {
640 struct commit_list *parents;
639 - packet_write_fmt(1, "unshallow %s",
640 - oid_to_hex(&object->oid));
641 + packet_writer_write(writer, "unshallow %s",
642 + oid_to_hex(&object->oid));
643 object->flags &= ~CLIENT_SHALLOW;
644 /*
645 * We want to _register_ "object" as shallow, but we
@@ -662,7 +664,7 @@ static void send_unshallow(const struct object_array *shallows,
664 }
665 }
666
665 -static void deepen(int depth, int deepen_relative,
667 +static void deepen(struct packet_writer *writer, int depth, int deepen_relative,
668 struct object_array *shallows, struct object_array *want_obj)
669 {
670 if (depth == INFINITE_DEPTH && !is_repository_shallow(the_repository)) {
@@ -680,7 +682,7 @@ static void deepen(int depth, int deepen_relative,
682 result = get_shallow_commits(&reachable_shallows,
683 depth + 1,
684 SHALLOW, NOT_SHALLOW);
683 - send_shallow(result);
685 + send_shallow(writer, result);
686 free_commit_list(result);
687 object_array_clear(&reachable_shallows);
688 } else {
@@ -688,14 +690,15 @@ static void deepen(int depth, int deepen_relative,
690
691 result = get_shallow_commits(want_obj, depth,
692 SHALLOW, NOT_SHALLOW);
691 - send_shallow(result);
693 + send_shallow(writer, result);
694 free_commit_list(result);
695 }
696
695 - send_unshallow(shallows, want_obj);
697 + send_unshallow(writer, shallows, want_obj);
698 }
699
698 -static void deepen_by_rev_list(int ac, const char **av,
700 +static void deepen_by_rev_list(struct packet_writer *writer, int ac,
701 + const char **av,
702 struct object_array *shallows,
703 struct object_array *want_obj)
704 {
@@ -703,13 +706,14 @@ static void deepen_by_rev_list(int ac, const char **av,
706
707 close_commit_graph(the_repository);
708 result = get_shallow_commits_by_rev_list(ac, av, SHALLOW, NOT_SHALLOW);
706 - send_shallow(result);
709 + send_shallow(writer, result);
710 free_commit_list(result);
708 - send_unshallow(shallows, want_obj);
711 + send_unshallow(writer, shallows, want_obj);
712 }
713
714 /* Returns 1 if a shallow list is sent or 0 otherwise */
712 -static int send_shallow_list(int depth, int deepen_rev_list,
715 +static int send_shallow_list(struct packet_writer *writer,
716 + int depth, int deepen_rev_list,
717 timestamp_t deepen_since,
718 struct string_list *deepen_not,
719 struct object_array *shallows,
@@ -720,7 +724,7 @@ static int send_shallow_list(int depth, int deepen_rev_list,
724 if (depth > 0 && deepen_rev_list)
725 die("git upload-pack: deepen and deepen-since (or deepen-not) cannot be used together");
726 if (depth > 0) {
723 - deepen(depth, deepen_relative, shallows, want_obj);
727 + deepen(writer, depth, deepen_relative, shallows, want_obj);
728 ret = 1;
729 } else if (deepen_rev_list) {
730 struct argv_array av = ARGV_ARRAY_INIT;
@@ -741,7 +745,7 @@ static int send_shallow_list(int depth, int deepen_rev_list,
745 struct object *o = want_obj->objects[i].item;
746 argv_array_push(&av, oid_to_hex(&o->oid));
747 }
744 - deepen_by_rev_list(av.argc, av.argv, shallows, want_obj);
748 + deepen_by_rev_list(writer, av.argc, av.argv, shallows, want_obj);
749 argv_array_clear(&av);
750 ret = 1;
751 } else {
@@ -834,8 +838,10 @@ static void receive_needs(struct packet_reader *reader, struct object_array *wan
838 int has_non_tip = 0;
839 timestamp_t deepen_since = 0;
840 int deepen_rev_list = 0;
841 + struct packet_writer writer;
842
843 shallow_nr = 0;
844 + packet_writer_init(&writer, 1);
845 for (;;) {
846 struct object *o;
847 const char *features;
@@ -892,9 +898,9 @@ static void receive_needs(struct packet_reader *reader, struct object_array *wan
898
899 o = parse_object(the_repository, &oid_buf);
900 if (!o) {
895 - packet_write_fmt(1,
896 - "ERR upload-pack: not our ref %s",
897 - oid_to_hex(&oid_buf));
901 + packet_writer_error(&writer,
902 + "upload-pack: not our ref %s",
903 + oid_to_hex(&oid_buf));
904 die("git upload-pack: not our ref %s",
905 oid_to_hex(&oid_buf));
906 }
@@ -923,7 +929,7 @@ static void receive_needs(struct packet_reader *reader, struct object_array *wan
929 if (depth == 0 && !deepen_rev_list && shallows.nr == 0)
930 return;
931
926 - if (send_shallow_list(depth, deepen_rev_list, deepen_since,
932 + if (send_shallow_list(&writer, depth, deepen_rev_list, deepen_since,
933 &deepen_not, &shallows, want_obj))
934 packet_flush(1);
935 object_array_clear(&shallows);
@@ -1102,6 +1108,8 @@ struct upload_pack_data {
1108 int deepen_rev_list;
1109 int deepen_relative;
1110
1111 + struct packet_writer writer;
1112 +
1113 unsigned stateless_rpc : 1;
1114
1115 unsigned use_thin_pack : 1;
@@ -1125,6 +1133,7 @@ static void upload_pack_data_init(struct upload_pack_data *data)
1133 data->haves = haves;
1134 data->shallows = shallows;
1135 data->deepen_not = deepen_not;
1136 + packet_writer_init(&data->writer, 1);
1137 }
1138
1139 static void upload_pack_data_clear(struct upload_pack_data *data)
@@ -1136,7 +1145,8 @@ static void upload_pack_data_clear(struct upload_pack_data *data)
1145 string_list_clear(&data->deepen_not, 0);
1146 }
1147
1139 -static int parse_want(const char *line, struct object_array *want_obj)
1148 +static int parse_want(struct packet_writer *writer, const char *line,
1149 + struct object_array *want_obj)
1150 {
1151 const char *arg;
1152 if (skip_prefix(line, "want ", &arg)) {
@@ -1149,9 +1159,9 @@ static int parse_want(const char *line, struct object_array *want_obj)
1159
1160 o = parse_object(the_repository, &oid);
1161 if (!o) {
1152 - packet_write_fmt(1,
1153 - "ERR upload-pack: not our ref %s",
1154 - oid_to_hex(&oid));
1162 + packet_writer_error(writer,
1163 + "upload-pack: not our ref %s",
1164 + oid_to_hex(&oid));
1165 die("git upload-pack: not our ref %s",
1166 oid_to_hex(&oid));
1167 }
@@ -1167,7 +1177,8 @@ static int parse_want(const char *line, struct object_array *want_obj)
1177 return 0;
1178 }
1179
1170 -static int parse_want_ref(const char *line, struct string_list *wanted_refs,
1180 +static int parse_want_ref(struct packet_writer *writer, const char *line,
1181 + struct string_list *wanted_refs,
1182 struct object_array *want_obj)
1183 {
1184 const char *arg;
@@ -1177,7 +1188,7 @@ static int parse_want_ref(const char *line, struct string_list *wanted_refs,
1188 struct object *o;
1189
1190 if (read_ref(arg, &oid)) {
1180 - packet_write_fmt(1, "ERR unknown ref %s", arg);
1191 + packet_writer_error(writer, "unknown ref %s", arg);
1192 die("unknown ref %s", arg);
1193 }
1194
@@ -1220,10 +1231,11 @@ static void process_args(struct packet_reader *request,
1231 const char *p;
1232
1233 /* process want */
1223 - if (parse_want(arg, want_obj))
1234 + if (parse_want(&data->writer, arg, want_obj))
1235 continue;
1236 if (allow_ref_in_want &&
1226 - parse_want_ref(arg, &data->wanted_refs, want_obj))
1237 + parse_want_ref(&data->writer, arg, &data->wanted_refs,
1238 + want_obj))
1239 continue;
1240 /* process have line */
1241 if (parse_have(arg, &data->haves))
@@ -1317,26 +1329,26 @@ static int process_haves(struct oid_array *haves, struct oid_array *common,
1329 return 0;
1330 }
1331
1320 -static int send_acks(struct oid_array *acks, struct strbuf *response,
1332 +static int send_acks(struct packet_writer *writer, struct oid_array *acks,
1333 const struct object_array *have_obj,
1334 struct object_array *want_obj)
1335 {
1336 int i;
1337
1326 - packet_buf_write(response, "acknowledgments\n");
1338 + packet_writer_write(writer, "acknowledgments\n");
1339
1340 /* Send Acks */
1341 if (!acks->nr)
1330 - packet_buf_write(response, "NAK\n");
1342 + packet_writer_write(writer, "NAK\n");
1343
1344 for (i = 0; i < acks->nr; i++) {
1333 - packet_buf_write(response, "ACK %s\n",
1334 - oid_to_hex(&acks->oid[i]));
1345 + packet_writer_write(writer, "ACK %s\n",
1346 + oid_to_hex(&acks->oid[i]));
1347 }
1348
1349 if (ok_to_give_up(have_obj, want_obj)) {
1350 /* Send Ready */
1339 - packet_buf_write(response, "ready\n");
1351 + packet_writer_write(writer, "ready\n");
1352 return 1;
1353 }
1354
@@ -1348,25 +1360,20 @@ static int process_haves_and_send_acks(struct upload_pack_data *data,
1360 struct object_array *want_obj)
1361 {
1362 struct oid_array common = OID_ARRAY_INIT;
1351 - struct strbuf response = STRBUF_INIT;
1363 int ret = 0;
1364
1365 process_haves(&data->haves, &common, have_obj);
1366 if (data->done) {
1367 ret = 1;
1357 - } else if (send_acks(&common, &response, have_obj, want_obj)) {
1358 - packet_buf_delim(&response);
1368 + } else if (send_acks(&data->writer, &common, have_obj, want_obj)) {
1369 + packet_writer_delim(&data->writer);
1370 ret = 1;
1371 } else {
1372 /* Add Flush */
1362 - packet_buf_flush(&response);
1373 + packet_writer_flush(&data->writer);
1374 ret = 0;
1375 }
1376
1366 - /* Send response */
1367 - write_or_die(1, response.buf, response.len);
1368 - strbuf_release(&response);
1369 -
1377 oid_array_clear(&data->haves);
1378 oid_array_clear(&common);
1379 return ret;
@@ -1379,15 +1386,15 @@ static void send_wanted_ref_info(struct upload_pack_data *data)
1386 if (!data->wanted_refs.nr)
1387 return;
1388
1382 - packet_write_fmt(1, "wanted-refs\n");
1389 + packet_writer_write(&data->writer, "wanted-refs\n");
1390
1391 for_each_string_list_item(item, &data->wanted_refs) {
1385 - packet_write_fmt(1, "%s %s\n",
1386 - oid_to_hex(item->util),
1387 - item->string);
1392 + packet_writer_write(&data->writer, "%s %s\n",
1393 + oid_to_hex(item->util),
1394 + item->string);
1395 }
1396
1390 - packet_delim(1);
1397 + packet_writer_delim(&data->writer);
1398 }
1399
1400 static void send_shallow_info(struct upload_pack_data *data,
@@ -1398,14 +1405,15 @@ static void send_shallow_info(struct upload_pack_data *data,
1405 !is_repository_shallow(the_repository))
1406 return;
1407
1401 - packet_write_fmt(1, "shallow-info\n");
1408 + packet_writer_write(&data->writer, "shallow-info\n");
1409
1403 - if (!send_shallow_list(data->depth, data->deepen_rev_list,
1410 + if (!send_shallow_list(&data->writer, data->depth,
1411 + data->deepen_rev_list,
1412 data->deepen_since, &data->deepen_not,
1413 &data->shallows, want_obj) &&
1414 is_repository_shallow(the_repository))
1407 - deepen(INFINITE_DEPTH, data->deepen_relative, &data->shallows,
1408 - want_obj);
1415 + deepen(&data->writer, INFINITE_DEPTH, data->deepen_relative,
1416 + &data->shallows, want_obj);
1417
1418 packet_delim(1);
1419 }
@@ -1467,7 +1475,7 @@ int upload_pack_v2(struct repository *r, struct argv_array *keys,
1475 send_wanted_ref_info(&data);
1476 send_shallow_info(&data, &want_obj);
1477
1470 - packet_write_fmt(1, "packfile\n");
1478 + packet_writer_write(&data.writer, "packfile\n");
1479 create_pack_file(&have_obj, &want_obj);
1480 state = FETCH_DONE;
1481 break;