{"thread":{"id":"2251","subject":"[PATCH 7/8] git-upload-pack: Support the multi_ack protocol","startedAt":"2005-10-28T02:49:16Z","lastAt":"2005-10-28T02:49:16Z","messageCount":1,"participants":["Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":8},"messages":[{"id":"10738","messageId":"Pine.LNX.4.63.0510280448560.20516@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"2251","inReplyTo":null,"subject":"[PATCH 7/8] git-upload-pack: Support the multi_ack protocol","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2005-10-28T02:49:16Z","receivedAt":"2005-10-28T02:49:16Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThis implements three things (trying very hard to be backwards\ncompatible):\n\nIt sends the \"multi_ack\" capability via the mechanism proposed by\nSergey Vlasov.\n\nWhen the client sends \"multi_ack\" with at least one \"want\", multi_ack\nis enabled.\n\nWhen multi_ack is enabled, \"continue\" is appended to each \"ACK\" until\neither the server can not store more refs, or \"done\" is received.\n\nIn contrast to the original protocol, as long as \"continue\" is sent,\nflushes are answered by a \"NAK\" (not just until an \"ACK\" was sent),\nand if \"continue\" was sent at least once, the last message is an\n\"ACK\" without \"continue\".\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n\n---\n\n upload-pack.c |   47 ++++++++++++++++++++++++-----------------------\n 1 files changed, 24 insertions(+), 23 deletions(-)\n\napplies-to: 4a808fae0b12e633b13bc0e76ec31ee19eecb21b\n42affc8d8fa1ed7e7d95fd7385d118cc57a0c420\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 660d7c4..686445e 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -12,7 +12,7 @@ static const char upload_pack_usage[] = \n #define WANTED (1U << 2)\n #define MAX_HAS 256\n #define MAX_NEEDS 256\n-static int nr_has = 0, nr_needs = 0, nr_our_refs = 0;\n+static int nr_has = 0, nr_needs = 0, multi_ack = 0, nr_our_refs = 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@@ -119,7 +119,7 @@ static int got_sha1(char *hex, unsigned \n static int get_common_commits(void)\n {\n \tstatic char line[1000];\n-\tunsigned char sha1[20];\n+\tunsigned char sha1[20], last_sha1[20];\n \tint len;\n \n \ttrack_object_refs = 0;\n@@ -130,39 +130,36 @@ 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 (nr_has == 0 || multi_ack)\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\tif (got_sha1(line+5, sha1) &&\n+\t\t\t\t\t(multi_ack || nr_has == 1)) {\n+\t\t\t\tif (nr_has >= MAX_HAS)\n+\t\t\t\t\tmulti_ack = 0;\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 ?  \" continue\" : \"\");\n+\t\t\t\tif (multi_ack)\n+\t\t\t\t\tmemcpy(last_sha1, sha1, 20);\n \t\t\t}\n \t\t\tcontinue;\n \t\t}\n \t\tif (!strcmp(line, \"done\")) {\n+\t\t\tif (nr_has > 0) {\n+\t\t\t\tif (multi_ack)\n+\t\t\t\t\tpacket_write(1, \"ACK %s\\n\",\n+\t\t\t\t\t\t\tsha1_to_hex(last_sha1));\n+\t\t\t\treturn 0;\n+\t\t\t}\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@@ -192,6 +189,8 @@ 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+\t\tif (strstr(line+45, \"multi_ack\"))\n+\t\t\tmulti_ack = 1;\n \n \t\t/* We have sent all our refs already, and the other end\n \t\t * should have chosen out of them; otherwise they are\n@@ -213,9 +212,11 @@ static int receive_needs(void)\n \n static int send_ref(const char *refname, const unsigned char *sha1)\n {\n+\tstatic char *capabilities = \"\\0multi_ack\";\n \tstruct object *o = parse_object(sha1);\n \n-\tpacket_write(1, \"%s %s\\n\", sha1_to_hex(sha1), refname);\n+\tpacket_write(1, \"%s %s%s\\n\", sha1_to_hex(sha1), refname, capabilities);\n+\tcapabilities = \"\";\n \tif (!(o->flags & OUR_REF)) {\n \t\to->flags |= OUR_REF;\n \t\tnr_our_refs++;\n---\n0.99.8.GIT\n"}]}