From bbc30f996380eacd71ca061675d5d0c5f21c45d2 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 24 Feb 2011 09:30:19 -0500 Subject: add packet tracing debug code This shows a trace of all packets coming in or out of a given program. This can help with debugging object negotiation or other protocol issues. To keep the code changes simple, we operate at the lowest level, meaning we don't necessarily understand what's in the packets. The one exception is a packet starting with "PACK", which causes us to skip that packet and turn off tracing (since the gigantic pack data will not be interesting to read, at least not in the trace format). We show both written and read packets. In the local case, this may mean you will see packets twice (written by the sender and read by the receiver). However, for cases where the other end is remote, this allows you to see the full conversation. Packet tracing can be enabled with GIT_TRACE_PACKET=, where takes the same arguments as GIT_TRACE. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- upload-pack.c | 1 + 1 file changed, 1 insertion(+) (limited to 'upload-pack.c') diff --git a/upload-pack.c b/upload-pack.c index b40a43f27..0c87bc00f 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -682,6 +682,7 @@ int main(int argc, char **argv) int i; int strict = 0; + packet_trace_identity("upload-pack"); git_extract_argv0_path(argv[0]); read_replace_refs = 0; -- cgit v1.2.1 From 49bee717f7080f99d3405682cc43ad525dde0973 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 14 Mar 2011 16:48:39 -0700 Subject: upload-pack: More aggressively send 'ACK %s ready' If a client is merely following the remote (and has not made any new commits itself), all "have %s" lines sent by the client will be common to the server. As all lines are common upload-pack never calls ok_to_give_up() and does not compute if it has a good cut point in the commit graph. Without this computation the following client is going to send all tagged commits, as these were determined to be COMMON_REF during the initial advertisement, but the client does not parse their history to transitively pass the COMMON flag and empty its queue of commits. For git.git with 339 commit tags, it takes clients 11 rounds of negotation to fully send all tagged commits and exhaust its queue of things to send as common. This is pretty slow for a client that has not done any local development activity. Force computing ok_to_give_up() and send "ACK %s ready" at the end of the current round if this round only contained common objects and ok_to_give_up() was therefore not called. This may allow the client to break early, avoiding transmission of the COMMON_REFs. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- upload-pack.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'upload-pack.c') diff --git a/upload-pack.c b/upload-pack.c index b40a43f27..11c3849a7 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -429,6 +429,8 @@ static int get_common_commits(void) static char line[1000]; unsigned char sha1[20]; char last_hex[41]; + int got_common = 0; + int got_other = 0; save_commit_buffer = 0; @@ -437,16 +439,22 @@ static int get_common_commits(void) reset_timeout(); if (!len) { + if (multi_ack == 2 && got_common + && !got_other && ok_to_give_up()) + packet_write(1, "ACK %s ready\n", last_hex); if (have_obj.nr == 0 || multi_ack) packet_write(1, "NAK\n"); if (stateless_rpc) exit(0); + got_common = 0; + got_other = 0; continue; } strip(line, len); if (!prefixcmp(line, "have ")) { switch (got_sha1(line+5, sha1)) { case -1: /* they have what we do not */ + got_other = 1; if (multi_ack && ok_to_give_up()) { const char *hex = sha1_to_hex(sha1); if (multi_ack == 2) @@ -456,6 +464,7 @@ static int get_common_commits(void) } break; default: + got_common = 1; memcpy(last_hex, sha1_to_hex(sha1), 41); if (multi_ack == 2) packet_write(1, "ACK %s common\n", last_hex); -- cgit v1.2.1 From 3e63b21aced116badd30a279c479535449a63560 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 14 Mar 2011 17:59:40 -0700 Subject: upload-pack: Implement no-done capability If the client requests both multi_ack_detailed and no-done then upload-pack is free to immediately send a PACK following its first 'ACK %s ready' message. The upload-pack response actually winds up being: ACK %s common ... (maybe more) ... ACK %s ready NAK ACK %s PACK.... the pack stream .... For smart HTTP connections this saves one HTTP RPC, reducing the overall latency for a trivial fetch. For git:// and ssh:// a no-done option slightly reduces latency by removing one server->client->server round-trip at the end of the common ancestor negotiation. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- upload-pack.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'upload-pack.c') diff --git a/upload-pack.c b/upload-pack.c index 11c3849a7..5924f6f98 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -27,6 +27,7 @@ static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=< static unsigned long oldest_have; static int multi_ack, nr_our_refs; +static int no_done; static int use_thin_pack, use_ofs_delta, use_include_tag; static int no_progress, daemon_mode; static int shallow_nr; @@ -431,6 +432,7 @@ static int get_common_commits(void) char last_hex[41]; int got_common = 0; int got_other = 0; + int sent_ready = 0; save_commit_buffer = 0; @@ -440,10 +442,17 @@ static int get_common_commits(void) if (!len) { if (multi_ack == 2 && got_common - && !got_other && ok_to_give_up()) + && !got_other && ok_to_give_up()) { + sent_ready = 1; packet_write(1, "ACK %s ready\n", last_hex); + } if (have_obj.nr == 0 || multi_ack) packet_write(1, "NAK\n"); + + if (no_done && sent_ready) { + packet_write(1, "ACK %s\n", last_hex); + return 0; + } if (stateless_rpc) exit(0); got_common = 0; @@ -457,9 +466,10 @@ static int get_common_commits(void) got_other = 1; if (multi_ack && ok_to_give_up()) { const char *hex = sha1_to_hex(sha1); - if (multi_ack == 2) + if (multi_ack == 2) { + sent_ready = 1; packet_write(1, "ACK %s ready\n", hex); - else + } else packet_write(1, "ACK %s continue\n", hex); } break; @@ -535,6 +545,8 @@ static void receive_needs(void) multi_ack = 2; else if (strstr(line+45, "multi_ack")) multi_ack = 1; + if (strstr(line+45, "no-done")) + no_done = 1; if (strstr(line+45, "thin-pack")) use_thin_pack = 1; if (strstr(line+45, "ofs-delta")) @@ -628,7 +640,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo { static const char *capabilities = "multi_ack thin-pack side-band" " side-band-64k ofs-delta shallow no-progress" - " include-tag multi_ack_detailed"; + " include-tag multi_ack_detailed no-done"; struct object *o = parse_object(sha1); if (!o) -- cgit v1.2.1 From 4793b7e86d007c492a76a5fae379ded97008e7fb Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 28 Mar 2011 23:33:51 -0700 Subject: Revert "upload-pack: Implement no-done capability" This reverts 3e63b21 (upload-pack: Implement no-done capability, 2011-03-14). Together with 761ecf0 (fetch-pack: Implement no-done capability, 2011-03-14) it seems to make the fetch-pack process out of sync and makes it keep talking long after upload-pack stopped listening to it, terminating the process with SIGPIPE. --- upload-pack.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) (limited to 'upload-pack.c') diff --git a/upload-pack.c b/upload-pack.c index 72aa661f8..eb80dd9aa 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -27,7 +27,6 @@ static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=< static unsigned long oldest_have; static int multi_ack, nr_our_refs; -static int no_done; static int use_thin_pack, use_ofs_delta, use_include_tag; static int no_progress, daemon_mode; static int shallow_nr; @@ -432,7 +431,6 @@ static int get_common_commits(void) char last_hex[41]; int got_common = 0; int got_other = 0; - int sent_ready = 0; save_commit_buffer = 0; @@ -442,17 +440,10 @@ static int get_common_commits(void) if (!len) { if (multi_ack == 2 && got_common - && !got_other && ok_to_give_up()) { - sent_ready = 1; + && !got_other && ok_to_give_up()) packet_write(1, "ACK %s ready\n", last_hex); - } if (have_obj.nr == 0 || multi_ack) packet_write(1, "NAK\n"); - - if (no_done && sent_ready) { - packet_write(1, "ACK %s\n", last_hex); - return 0; - } if (stateless_rpc) exit(0); got_common = 0; @@ -466,10 +457,9 @@ static int get_common_commits(void) got_other = 1; if (multi_ack && ok_to_give_up()) { const char *hex = sha1_to_hex(sha1); - if (multi_ack == 2) { - sent_ready = 1; + if (multi_ack == 2) packet_write(1, "ACK %s ready\n", hex); - } else + else packet_write(1, "ACK %s continue\n", hex); } break; @@ -545,8 +535,6 @@ static void receive_needs(void) multi_ack = 2; else if (strstr(line+45, "multi_ack")) multi_ack = 1; - if (strstr(line+45, "no-done")) - no_done = 1; if (strstr(line+45, "thin-pack")) use_thin_pack = 1; if (strstr(line+45, "ofs-delta")) @@ -640,7 +628,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo { static const char *capabilities = "multi_ack thin-pack side-band" " side-band-64k ofs-delta shallow no-progress" - " include-tag multi_ack_detailed no-done"; + " include-tag multi_ack_detailed"; struct object *o = parse_object(sha1); if (!o) -- cgit v1.2.1 From cf2ad8e64175bcf4b2bb693a9e4c0a89076111dd Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 29 Mar 2011 10:24:59 -0700 Subject: enable "no-done" extension only when serving over smart-http Do not advertise no-done capability when upload-pack is not serving over smart-http, as there is no way for this server to know when it should stop reading in-flight data from the client, even though it is necessary to drain all the in-flight data in order to unblock the client. Signed-off-by: Junio C Hamano Acked-by: Shawn O. Pearce --- upload-pack.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'upload-pack.c') diff --git a/upload-pack.c b/upload-pack.c index 5924f6f98..a247fb9e2 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -640,15 +640,16 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo { static const char *capabilities = "multi_ack thin-pack side-band" " side-band-64k ofs-delta shallow no-progress" - " include-tag multi_ack_detailed no-done"; + " include-tag multi_ack_detailed"; struct object *o = parse_object(sha1); if (!o) die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1)); if (capabilities) - packet_write(1, "%s %s%c%s\n", sha1_to_hex(sha1), refname, - 0, capabilities); + packet_write(1, "%s %s%c%s%s\n", sha1_to_hex(sha1), refname, + 0, capabilities, + stateless_rpc ? " no-done" : ""); else packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname); capabilities = NULL; -- cgit v1.2.1 From 4e10cf9a17467c08754b36683c240fbab69156de Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 29 Mar 2011 12:29:10 -0700 Subject: Revert two "no-done" reverts Last night I had to make these two emergency reverts, but now we have a better understanding of which part of the topic was broken, let's get rid of the revert to fix it correctly. Signed-off-by: Junio C Hamano --- upload-pack.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'upload-pack.c') diff --git a/upload-pack.c b/upload-pack.c index eb80dd9aa..72aa661f8 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -27,6 +27,7 @@ static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=< static unsigned long oldest_have; static int multi_ack, nr_our_refs; +static int no_done; static int use_thin_pack, use_ofs_delta, use_include_tag; static int no_progress, daemon_mode; static int shallow_nr; @@ -431,6 +432,7 @@ static int get_common_commits(void) char last_hex[41]; int got_common = 0; int got_other = 0; + int sent_ready = 0; save_commit_buffer = 0; @@ -440,10 +442,17 @@ static int get_common_commits(void) if (!len) { if (multi_ack == 2 && got_common - && !got_other && ok_to_give_up()) + && !got_other && ok_to_give_up()) { + sent_ready = 1; packet_write(1, "ACK %s ready\n", last_hex); + } if (have_obj.nr == 0 || multi_ack) packet_write(1, "NAK\n"); + + if (no_done && sent_ready) { + packet_write(1, "ACK %s\n", last_hex); + return 0; + } if (stateless_rpc) exit(0); got_common = 0; @@ -457,9 +466,10 @@ static int get_common_commits(void) got_other = 1; if (multi_ack && ok_to_give_up()) { const char *hex = sha1_to_hex(sha1); - if (multi_ack == 2) + if (multi_ack == 2) { + sent_ready = 1; packet_write(1, "ACK %s ready\n", hex); - else + } else packet_write(1, "ACK %s continue\n", hex); } break; @@ -535,6 +545,8 @@ static void receive_needs(void) multi_ack = 2; else if (strstr(line+45, "multi_ack")) multi_ack = 1; + if (strstr(line+45, "no-done")) + no_done = 1; if (strstr(line+45, "thin-pack")) use_thin_pack = 1; if (strstr(line+45, "ofs-delta")) @@ -628,7 +640,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo { static const char *capabilities = "multi_ack thin-pack side-band" " side-band-64k ofs-delta shallow no-progress" - " include-tag multi_ack_detailed"; + " include-tag multi_ack_detailed no-done"; struct object *o = parse_object(sha1); if (!o) -- cgit v1.2.1