{"thread":{"id":"2195","subject":"[PATCH 2/4] git-upload-pack: Support sending multiple ACK messages","startedAt":"2005-10-23T01:37:45Z","lastAt":"2005-10-23T01:37:45Z","messageCount":1,"participants":["Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"10475","messageId":"Pine.LNX.4.63.0510230336300.21239@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"2195","inReplyTo":null,"subject":"[PATCH 2/4] git-upload-pack: Support sending multiple ACK messages","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2005-10-23T01:37:45Z","receivedAt":"2005-10-23T01:37:45Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The current fetch/upload protocol works like this:\n\n- client sends revs it wants to have via \"want\" messages\n- client sends a flush message (message with len 0)\n- client sends revs it has via \"have\" messages\n- after one window (32 revs), a flush is sent\n- after each subsequent window, a flush is sent, and an ACK/NAK is received.\n        (NAK means that server does not have any of the transmitted revs;\n         ACK sends also the sha1 of the rev server has)\n - when the first ACK is received, client sends \"done\", and does not expect\n        any further messages\n\nOne special case, though:\n\n- if no ACK is received (only NAK's), and client runs out of revs to send,\n        \"done\" is sent, and server sends just one more \"NAK\"\n\nA smarter scheme, which actually has a chance to detect more than one \ncommon rev, would be to send more than just one ACK. This patch implements \nthe server side of the following extension to the protocol:\n\n- client sends at least one \"want\" message with \"multi_ack\" appended, like\n\n        \"want 1234567890123456789012345678901234567890 multi_ack\"\n\n- if the server understands that extension, it will send ACK messages for all\n        revs it has, not just the first one\n\n- server appends \"continue\" to the ACK messages like\n\n        \"ACK 1234567890123456789012345678901234567890 continue\"\n\n        until it has MAX_HAS-1 revs. In this manner, client knows when to\n        stop sending revs by checking for the substring \"continue\" (and\n        further knows that server understands multi_ack)\n\nIn this manner, the protocol stays backwards compatible, since both client \nmust send \"want ... multi_ack\" and server must answer with \"ACK ... \ncontinue\" to enable the extension.\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n\n---\n\n upload-pack.c |   37 +++++++++++++++----------------------\n 1 files changed, 15 insertions(+), 22 deletions(-)\n\napplies-to: 95634a3973bbc1eb8cc626fd6fd67bb773caf7ab\n89df3fb3bb65e37c33b478b66c76adc46cf22cd7\ndiff --git a/upload-pack.c b/upload-pack.c\nindex ab1981c..c3abf7b 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -10,7 +10,7 @@ static const char upload_pack_usage[] = \n #define THEY_HAVE (1U << 0)\n #define MAX_HAS 256\n #define MAX_NEEDS 256\n-static int nr_has = 0, nr_needs = 0;\n+static int nr_has = 0, nr_needs = 0, multi_ack = 0;\n static unsigned char has_sha1[MAX_HAS][20];\n static unsigned char needs_sha1[MAX_NEEDS][20];\n static unsigned int timeout = 0;\n@@ -124,39 +124,28 @@ static int get_common_commits(void)\n \t\treset_timeout();\n \n \t\tif (!len) {\n-\t\t\tpacket_write(1, \"NAK\\n\");\n+\t\t\tif (multi_ack || nr_has == 0)\n+\t\t\t\tpacket_write(1, \"NAK\\n\");\n \t\t\tcontinue;\n \t\t}\n \t\tlen = strip(line, len);\n \t\tif (!strncmp(line, \"have \", 5)) {\n-\t\t\tif (got_sha1(line+5, sha1)) {\n-\t\t\t\tpacket_write(1, \"ACK %s\\n\", sha1_to_hex(sha1));\n-\t\t\t\tbreak;\n-\t\t\t}\n+\t\t\tif (got_sha1(line+5, sha1) &&\n+\t\t\t\t\t(multi_ack || nr_has == 1))\n+\t\t\t\tpacket_write(1, \"ACK %s%s\\n\",\n+\t\t\t\t\tsha1_to_hex(sha1),\n+\t\t\t\t\tmulti_ack && nr_has < MAX_HAS ?\n+\t\t\t\t\t\" continue\" : \"\");\n \t\t\tcontinue;\n \t\t}\n \t\tif (!strcmp(line, \"done\")) {\n+\t\t\tif (nr_has > 0)\n+\t\t\t\treturn 0;\n \t\t\tpacket_write(1, \"NAK\\n\");\n \t\t\treturn -1;\n \t\t}\n \t\tdie(\"git-upload-pack: expected SHA1 list, got '%s'\", line);\n \t}\n-\n-\tfor (;;) {\n-\t\tlen = packet_read_line(0, line, sizeof(line));\n-\t\treset_timeout();\n-\t\tif (!len)\n-\t\t\tcontinue;\n-\t\tlen = strip(line, len);\n-\t\tif (!strncmp(line, \"have \", 5)) {\n-\t\t\tgot_sha1(line+5, sha1);\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(line, \"done\"))\n-\t\t\tbreak;\n-\t\tdie(\"git-upload-pack: expected SHA1 list, got '%s'\", line);\n-\t}\n-\treturn 0;\n }\n \n static int receive_needs(void)\n@@ -185,6 +174,10 @@ static int receive_needs(void)\n \t\tif (strncmp(\"want \", line, 5) || get_sha1_hex(line+5, sha1_buf))\n \t\t\tdie(\"git-upload-pack: protocol error, \"\n \t\t\t    \"expected to get sha, not '%s'\", line);\n+\n+\t\tif (strstr(line+45, \"multi_ack\"))\n+\t\t\tmulti_ack = 1;\n+\n \t\tneeds++;\n \t}\n }\n---\n0.99.8.GIT\n"}]}