@matheusbsbs / matheus-bagliano / commits / 78affc49de
Fork 0

Add multi_ack_detailed capability to fetch-pack/upload-pack

When multi_ack_detailed is enabled the ACK continue messages returned by the remote upload-pack are broken out to describe the different states within the peer. This permits the client to better understand the server's in-memory state. The fetch-pack/upload-pack protocol now looks like: NAK --------------------------------- Always sent in response to "done" if there was no common base selected from the "have" lines (or no have lines were sent). * no multi_ack or multi_ack_detailed: Sent when the client has sent a pkt-line flush ("0000") and the server has not yet found a common base object. * either multi_ack or multi_ack_detailed: Always sent in response to a pkt-line flush. ACK %s ----------------------------------- * no multi_ack or multi_ack_detailed: Sent in response to "have" when the object exists on the remote side and is therefore an object in common between the peers. The argument is the SHA-1 of the common object. * either multi_ack or multi_ack_detailed: Sent in response to "done" if there are common objects. The argument is the last SHA-1 determined to be common. ACK %s continue ----------------------------------- * multi_ack only: Sent in response to "have". The remote side wants the client to consider this object as common, and immediately stop transmitting additional "have" lines for objects that are reachable from it. The reason the client should stop is not given, but is one of the two cases below available under multi_ack_detailed. ACK %s common ----------------------------------- * multi_ack_detailed only: Sent in response to "have". Both sides have this object. Like with "ACK %s continue" above the client should stop sending have lines reachable for objects from the argument. ACK %s ready ----------------------------------- * multi_ack_detailed only: Sent in response to "have". The client should stop transmitting objects which are reachable from the argument, and send "done" soon to get the objects. If the remote side has the specified object, it should first send an "ACK %s common" message prior to sending "ACK %s ready". Clients may still submit additional "have" lines if there are more side branches for the client to explore that might be added to the common set and reduce the number of objects to transfer. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Shawn O. Pearce committed Oct 30, 2009 at 17:47 UTC 78affc49ded26700450d25168534af02b29a6c61
2 files changed +50 -22
builtin-fetch-pack.c
+32 -9
@@ -157,7 +157,15 @@ static const unsigned char *get_rev(void)
157 return commit->object.sha1;
158 }
159
160 -static int get_ack(int fd, unsigned char *result_sha1)
160 +enum ack_type {
161 + NAK = 0,
162 + ACK,
163 + ACK_continue,
164 + ACK_common,
165 + ACK_ready
166 +};
167 +
168 +static enum ack_type get_ack(int fd, unsigned char *result_sha1)
169 {
170 static char line[1000];
171 int len = packet_read_line(fd, line, sizeof(line));
@@ -167,12 +175,16 @@ static int get_ack(int fd, unsigned char *result_sha1)
175 if (line[len-1] == '\n')
176 line[--len] = 0;
177 if (!strcmp(line, "NAK"))
170 - return 0;
178 + return NAK;
179 if (!prefixcmp(line, "ACK ")) {
180 if (!get_sha1_hex(line+4, result_sha1)) {
181 if (strstr(line+45, "continue"))
174 - return 2;
175 - return 1;
182 + return ACK_continue;
183 + if (strstr(line+45, "common"))
184 + return ACK_common;
185 + if (strstr(line+45, "ready"))
186 + return ACK_ready;
187 + return ACK;
188 }
189 }
190 die("git fetch_pack: expected ACK/NAK, got '%s'", line);
@@ -218,7 +230,8 @@ static int find_common(int fd[2], unsigned char *result_sha1,
230 remote_hex = sha1_to_hex(remote);
231 if (!fetching) {
232 struct strbuf c = STRBUF_INIT;
221 - if (multi_ack) strbuf_addstr(&c, " multi_ack");
233 + if (multi_ack == 2) strbuf_addstr(&c, " multi_ack_detailed");
234 + if (multi_ack == 1) strbuf_addstr(&c, " multi_ack");
235 if (use_sideband == 2) strbuf_addstr(&c, " side-band-64k");
236 if (use_sideband == 1) strbuf_addstr(&c, " side-band");
237 if (args.use_thin_pack) strbuf_addstr(&c, " thin-pack");
@@ -298,18 +311,23 @@ static int find_common(int fd[2], unsigned char *result_sha1,
311 if (args.verbose && ack)
312 fprintf(stderr, "got ack %d %s\n", ack,
313 sha1_to_hex(result_sha1));
301 - if (ack == 1) {
314 + switch (ack) {
315 + case ACK:
316 flushes = 0;
317 multi_ack = 0;
318 retval = 0;
319 goto done;
306 - } else if (ack == 2) {
320 + case ACK_common:
321 + case ACK_ready:
322 + case ACK_continue: {
323 struct commit *commit =
324 lookup_commit(result_sha1);
325 mark_common(commit, 0, 1);
326 retval = 0;
327 in_vain = 0;
328 got_continue = 1;
329 + break;
330 + }
331 }
332 } while (ack);
333 flushes--;
@@ -336,7 +354,7 @@ done:
354 if (args.verbose)
355 fprintf(stderr, "got ack (%d) %s\n", ack,
356 sha1_to_hex(result_sha1));
339 - if (ack == 1)
357 + if (ack == ACK)
358 return 0;
359 multi_ack = 1;
360 continue;
@@ -618,7 +636,12 @@ static struct ref *do_fetch_pack(int fd[2],
636
637 if (is_repository_shallow() && !server_supports("shallow"))
638 die("Server does not support shallow clients");
621 - if (server_supports("multi_ack")) {
639 + if (server_supports("multi_ack_detailed")) {
640 + if (args.verbose)
641 + fprintf(stderr, "Server supports multi_ack_detailed\n");
642 + multi_ack = 2;
643 + }
644 + else if (server_supports("multi_ack")) {
645 if (args.verbose)
646 fprintf(stderr, "Server supports multi_ack\n");
647 multi_ack = 1;
upload-pack.c
+18 -13
@@ -498,7 +498,7 @@ static int get_common_commits(void)
498 {
499 static char line[1000];
500 unsigned char sha1[20];
501 - char hex[41], last_hex[41];
501 + char last_hex[41];
502
503 save_commit_buffer = 0;
504
@@ -515,19 +515,22 @@ static int get_common_commits(void)
515 if (!prefixcmp(line, "have ")) {
516 switch (got_sha1(line+5, sha1)) {
517 case -1: /* they have what we do not */
518 - if (multi_ack && ok_to_give_up())
519 - packet_write(1, "ACK %s continue\n",
520 - sha1_to_hex(sha1));
518 + if (multi_ack && ok_to_give_up()) {
519 + const char *hex = sha1_to_hex(sha1);
520 + if (multi_ack == 2)
521 + packet_write(1, "ACK %s ready\n", hex);
522 + else
523 + packet_write(1, "ACK %s continue\n", hex);
524 + }
525 break;
526 default:
523 - memcpy(hex, sha1_to_hex(sha1), 41);
524 - if (multi_ack) {
525 - const char *msg = "ACK %s continue\n";
526 - packet_write(1, msg, hex);
527 - memcpy(last_hex, hex, 41);
528 - }
527 + memcpy(last_hex, sha1_to_hex(sha1), 41);
528 + if (multi_ack == 2)
529 + packet_write(1, "ACK %s common\n", last_hex);
530 + else if (multi_ack)
531 + packet_write(1, "ACK %s continue\n", last_hex);
532 else if (have_obj.nr == 1)
530 - packet_write(1, "ACK %s\n", hex);
533 + packet_write(1, "ACK %s\n", last_hex);
534 break;
535 }
536 continue;
@@ -587,7 +590,9 @@ static void receive_needs(void)
590 get_sha1_hex(line+5, sha1_buf))
591 die("git upload-pack: protocol error, "
592 "expected to get sha, not '%s'", line);
590 - if (strstr(line+45, "multi_ack"))
593 + if (strstr(line+45, "multi_ack_detailed"))
594 + multi_ack = 2;
595 + else if (strstr(line+45, "multi_ack"))
596 multi_ack = 1;
597 if (strstr(line+45, "thin-pack"))
598 use_thin_pack = 1;
@@ -681,7 +686,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
686 {
687 static const char *capabilities = "multi_ack thin-pack side-band"
688 " side-band-64k ofs-delta shallow no-progress"
684 - " include-tag";
689 + " include-tag multi_ack_detailed";
690 struct object *o = parse_object(sha1);
691
692 if (!o)