* [RFC] multi_ack protocol v2 @ 2005-10-27 0:16 Johannes Schindelin 2005-10-27 7:13 ` Junio C Hamano 2005-10-27 9:11 ` Paul Mackerras 0 siblings, 2 replies; 10+ messages in thread From: Johannes Schindelin @ 2005-10-27 0:16 UTC (permalink / raw) To: git Hi, the fetch-pack/upload-pack protocol as of now goes like this: - server sends the refs it has, then an empty packet - client sends what it wants, then an empty packet - client sends a rev-list via "have" lines in the hope to find a common rev. Interspersed, it sends empty packets. - server answers to those empty packets with a NAK message, until it receives a "have" line for a commit it has (and which is therefore a common commit). This is answered by an ACK message, and no NAK or ACK is sent after that - client sends "done" - server only responds if no common commit was found, with a NAK - server sends pack after thinking about my earlier approach, I think there's a better, less intrusive, and all in all just simpler approach: - client asks for multi_ack protocol by sending " multi_ack" at the end of at least one "want" line - server appends " continue" to the ACK message, but continues sending ACK (but not NAK) messages - after receiving "done", server repeats last ACK message without " continue" appended After much fun with non-working, fragile code which had to be retracted from master, I hope that this approach is less prone to errors. Note that this is incompatible to the multi_ack protocol I described earlier, but given that my patches were buggy anyway, I'd say it does not matter at all. Thoughts, comments, objections? Ciao, Dscho ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] multi_ack protocol v2 2005-10-27 0:16 [RFC] multi_ack protocol v2 Johannes Schindelin @ 2005-10-27 7:13 ` Junio C Hamano 2005-10-27 9:37 ` Johannes Schindelin 2005-10-27 10:16 ` Sergey Vlasov 2005-10-27 9:11 ` Paul Mackerras 1 sibling, 2 replies; 10+ messages in thread From: Junio C Hamano @ 2005-10-27 7:13 UTC (permalink / raw) To: Johannes Schindelin; +Cc: git Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: > after thinking about my earlier approach, I think there's a better, less > intrusive, and all in all just simpler approach: > > - client asks for multi_ack protocol by sending " multi_ack" at the end > of at least one "want" line > - server appends " continue" to the ACK message, but continues sending > ACK (but not NAK) messages > - after receiving "done", server repeats last ACK message without > " continue" appended > > After much fun with non-working, fragile code which had to be retracted > from master, I hope that this approach is less prone to errors. Sorry for a late reply -- real life interrupts ;-). I do not necessarily think the last round (still found in the proposed updates branch) was a failure. One valuable thing you found out was that there is a way to extend the protocol with the appended "multi-ack" trick. Sending "have you found a common yet" every 32 "have" like the original protocol does has a nice batching property (I think we could even tweak pkt-line.c::packet_write() to actually buffer these "have"s and write them out in one-go, to put them in a single network packet) and I do not want to lose it, but other than that, since you have found a good way to extend the initial handshake to find out if both ends can do a v2 protocol without breaking older server nor clients, I have no objection against doing things drastically differently in the v2 protocol. I noticed the sketch in Documentation/pack-protocol.txt is somewhat buggy. Here is my attempt to correct it: upload-pack (S) | fetch/clone-pack (C) protocol (v1): # Tell the puller what commits we have and what their names are S: SHA1 name S: ... S: SHA1 name S: # flush -- it's your turn # Tell the pusher what commits we want, and what we have C: want SHA1 C: .. C: want SHA1 C: # flush -- done with "want" lines. C: have SHA1 C: have SHA1 C: ... C: # flush -- this occasionally asks "had enough?" S: NAK # and the server answers "notyet" C: have SHA1 C: ... C: have SHA1 S: ACK SHA1 C: done S: XXXXXXX -- packfile contents. I wrote as if "want" sends names, but it actually sends SHA1s. Also I missed a place where "flush" was needed. So let's illustrate the v2 the same way as I understand it. upload-pack (S) | fetch/clone-pack (C) protocol (v2): # Tell the puller what commits we have and what their names are S: SHA1 name S: ... S: SHA1 name S: # flush -- it's your turn # Tell the pusher what commits we want, and what we have. # In addition, we tell the other end that we support protocol # extensions, without breaking the old servers. C: want SHA1 extended C: .. C: want SHA1 C: # flush -- done with "want" lines. Notice that until we hear from the server, we cannot tell if our "extended" protocol wish will be granted, and in the original protocol, "NAK" will come in fixed length, and the only thing we could tack arbitrary garbage to was "ACK SHA1". That's why your "ACK SHA1 continue" works nicely, but at the time you could not find out if you are talking with updated server until you get at least one ACK. However, at this point, we *could* force the server to reveal what it supports, by doing an extra flush here, before sending *ANY* "have" lines yet: C: # flush -- this is another one after "I'm done with wants". Upon receiving this, if we were talking with an old upload-pack, we would certanly get an NAK. Note that the server already knows that we support extended protocol at this point, so our updated server can send anything here to say it knows what protocol extensions it supports. Let's say it says something like this: S: proto v2 v3 v5 to tell the puller it understands protocol v2, v3, and v5, to which the puller responds: C: proto v2 After this exchange, both ends know they understand and would want to talk at protocol level v2. This leaves door open for future protocol extension, but more importantly, I think this arrangement would make things safer. Both the server side and the client side code can be modified from the current one by splitting the above handshake part and the current trusty "only one ACK is supported" code, and the exchange after this protocol negotiation part can be implemented in totally separate functions. We could also give command line option and/or .git/config item to limit the protocol level each end supports when we find the v2 protocol implementation of the day was buggy, in order to work problems around without recompilation, reducing the risk of breaking things too much. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] multi_ack protocol v2 2005-10-27 7:13 ` Junio C Hamano @ 2005-10-27 9:37 ` Johannes Schindelin 2005-10-27 10:16 ` Sergey Vlasov 1 sibling, 0 replies; 10+ messages in thread From: Johannes Schindelin @ 2005-10-27 9:37 UTC (permalink / raw) To: Junio C Hamano; +Cc: git Hi, On Thu, 27 Oct 2005, Junio C Hamano wrote: > Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: > > > after thinking about my earlier approach, I think there's a better, less > > intrusive, and all in all just simpler approach: > > > > - client asks for multi_ack protocol by sending " multi_ack" at the end > > of at least one "want" line > > - server appends " continue" to the ACK message, but continues sending > > ACK (but not NAK) messages Here must be a correction: server continues to send NAK messages. Else we must introduce some select() or poll() crud, or the client hangs forever. > > - after receiving "done", server repeats last ACK message without > > " continue" appended In effect, an ACK message with "continue" switches into v2, which just means: "I'll keep sendin'", and an ACK *without* "continue" switches back to v1. This way the patch looks almost trivial. (Will send soon). > > After much fun with non-working, fragile code which had to be retracted > > from master, I hope that this approach is less prone to errors. > > Sorry for a late reply -- real life interrupts ;-). No problem (hope you enjoyed it ;-). I tried to get some Zs anyway. > Sending "have you found a common yet" every 32 "have" like the > original protocol does has a nice batching property (I think we > could even tweak pkt-line.c::packet_write() to actually buffer > these "have"s and write them out in one-go, to put them in a > single network packet) and I do not want to lose it, but other > than that, since you have found a good way to extend the initial > handshake to find out if both ends can do a v2 protocol without > breaking older server nor clients, I have no objection against > doing things drastically differently in the v2 protocol. I think that we don't need to extend packet_write(). Let's leave it like that. > upload-pack (S) | fetch/clone-pack (C) protocol (v1): > > # Tell the puller what commits we have and what their names are > S: SHA1 name > S: ... > S: SHA1 name > S: # flush -- it's your turn > # Tell the pusher what commits we want, and what we have > C: want SHA1 > C: .. > C: want SHA1 > C: # flush -- done with "want" lines. > C: have SHA1 > C: have SHA1 > C: ... > C: # flush -- this occasionally asks "had enough?" > S: NAK > # and the server answers "notyet" > C: have SHA1 > C: ... > C: have SHA1 > S: ACK SHA1 > C: done > S: XXXXXXX -- packfile contents. alternatively, when no "ACK" was sent, the response to "done" is "NAK". > I wrote as if "want" sends names, but it actually sends SHA1s. You also ask if it is sensible in upload-pack.c to accept names. I think not. SHA1s are supposed to be unique, names not (master~10 is likely to denote different commits on server and client). > Also I missed a place where "flush" was needed. Between "want" and "have". It is sent so that the server can handle them in separate functions. > upload-pack (S) | fetch/clone-pack (C) protocol (v2): > > # Tell the puller what commits we have and what their names are > S: SHA1 name > S: ... > S: SHA1 name > S: # flush -- it's your turn > # Tell the pusher what commits we want, and what we have. > # In addition, we tell the other end that we support protocol > # extensions, without breaking the old servers. > C: want SHA1 extended > C: .. > C: want SHA1 > C: # flush -- done with "want" lines. > > Notice that until we hear from the server, we cannot tell if our > "extended" protocol wish will be granted, and in the original > protocol, "NAK" will come in fixed length, and the only thing we > could tack arbitrary garbage to was "ACK SHA1". That's why your > "ACK SHA1 continue" works nicely, but at the time you could not > find out if you are talking with updated server until you get at > least one ACK. > > However, at this point, we *could* force the server to reveal > what it supports, by doing an extra flush here, before sending > *ANY* "have" lines yet: > > C: # flush -- this is another one after "I'm done with wants". We don't need a second flush. The first can do. The client just has to expect either "NAK" or "VER blabla blibli multi_ack". "VER" must be sent by the server only when the client requested an extension the server has, though. > S: proto v2 v3 v5 As written above, I'd prefer something like "VER" in order to stay with the 3 capital letters convention. Also, I like to read what it is about, i.e. "VER multi_ack" instead of "VER v2". > C: proto v2 I'd say that this is not necessary. Client can send that in the "want" lines. > After this exchange, both ends know they understand and would > want to talk at protocol level v2. This leaves door open for > future protocol extension, but more importantly, I think this > arrangement would make things safer. Yes. Nice. I especially like that the client learns early that multi_ack protocol it is. In my tests, non-multi_ack would only be happy when fed with commits sorted by date, while multi_ack is much more efficient when fed commits sorted by distance-to-tip (I cannot yet explain why this is so). Ciao, Dscho ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] multi_ack protocol v2 2005-10-27 7:13 ` Junio C Hamano 2005-10-27 9:37 ` Johannes Schindelin @ 2005-10-27 10:16 ` Sergey Vlasov 2005-10-27 10:47 ` Johannes Schindelin 1 sibling, 1 reply; 10+ messages in thread From: Sergey Vlasov @ 2005-10-27 10:16 UTC (permalink / raw) To: Junio C Hamano; +Cc: Johannes Schindelin, git [-- Attachment #1: Type: text/plain, Size: 2780 bytes --] On Thu, 27 Oct 2005 00:13:17 -0700 Junio C Hamano wrote: [skip] > So let's illustrate the v2 the same way as I understand it. > > upload-pack (S) | fetch/clone-pack (C) protocol (v2): > > # Tell the puller what commits we have and what their names are > S: SHA1 name > S: ... > S: SHA1 name > S: # flush -- it's your turn > # Tell the pusher what commits we want, and what we have. > # In addition, we tell the other end that we support protocol > # extensions, without breaking the old servers. > C: want SHA1 extended > C: .. > C: want SHA1 > C: # flush -- done with "want" lines. > > Notice that until we hear from the server, we cannot tell if our > "extended" protocol wish will be granted, and in the original > protocol, "NAK" will come in fixed length, and the only thing we > could tack arbitrary garbage to was "ACK SHA1". That's why your > "ACK SHA1 continue" works nicely, but at the time you could not > find out if you are talking with updated server until you get at > least one ACK. Actually, there is another way to pass some data from the server which would be ignored by older clients - at the first stage, when upload-pack sends the list of refs to the client: packet_write(1, "%s %s%c%s\n", sha1_to_hex(sha1), refname, '\0', server_capabilities); Old clients will ignore the additional data (functions which work with the received name will happily stop at the added NUL character; just some memory will be wasted), but the new implementation of get_remote_heads() could look for that NUL inside the received packet and find extended server capabilities after it. Then the client could just use new commands at the "want" stage. > However, at this point, we *could* force the server to reveal > what it supports, by doing an extra flush here, before sending > *ANY* "have" lines yet: > > C: # flush -- this is another one after "I'm done with wants". > > Upon receiving this, if we were talking with an old upload-pack, > we would certanly get an NAK. Note that the server already > knows that we support extended protocol at this point, so our > updated server can send anything here to say it knows what > protocol extensions it supports. Let's say it says something > like this: > > S: proto v2 v3 v5 > > to tell the puller it understands protocol v2, v3, and v5, to > which the puller responds: > > C: proto v2 > > After this exchange, both ends know they understand and would > want to talk at protocol level v2. This leaves door open for > future protocol extension, but more importantly, I think this > arrangement would make things safer. This looks cleaner (no NUL bytes in the protocol), but does not allow to replace the "want" stage with something entirely different (if we ever want to do that). [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] multi_ack protocol v2 2005-10-27 10:16 ` Sergey Vlasov @ 2005-10-27 10:47 ` Johannes Schindelin 2005-10-27 17:45 ` Junio C Hamano 0 siblings, 1 reply; 10+ messages in thread From: Johannes Schindelin @ 2005-10-27 10:47 UTC (permalink / raw) To: Sergey Vlasov; +Cc: Junio C Hamano, git Hi, On Thu, 27 Oct 2005, Sergey Vlasov wrote: > Actually, there is another way to pass some data from the server > which would be ignored by older clients - at the first stage, > when upload-pack sends the list of refs to the client: > > packet_write(1, "%s %s%c%s\n", sha1_to_hex(sha1), refname, '\0', > server_capabilities); That exploits that packet_write() uses vnsprintf() to find out the length, not strlen(). Sweet. get_remote_heads() would need to store the server_capabilities, maybe with a function "server_supports(const char *extension_string)" Actually, I like that even more than Junio's proposal. I was thinking hard about how to enhance get_ack() to understand -- and most importantly to return -- the capabilities. I could not think of an elegant way. So, unless people complain, I'll go with that approach. > This looks cleaner (no NUL bytes in the protocol), but does not > allow to replace the "want" stage with something entirely > different (if we ever want to do that). Also it feels wrong that a client should ask for capabilities, where it does not yet know if the server supports them. Ciao, Dscho ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] multi_ack protocol v2 2005-10-27 10:47 ` Johannes Schindelin @ 2005-10-27 17:45 ` Junio C Hamano 2005-10-27 18:04 ` Johannes Schindelin 0 siblings, 1 reply; 10+ messages in thread From: Junio C Hamano @ 2005-10-27 17:45 UTC (permalink / raw) To: Johannes Schindelin; +Cc: Sergey Vlasov, git Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: > On Thu, 27 Oct 2005, Sergey Vlasov wrote: > >> Actually, there is another way to pass some data from the server >> which would be ignored by older clients - at the first stage, >> when upload-pack sends the list of refs to the client: >> >> packet_write(1, "%s %s%c%s\n", sha1_to_hex(sha1), refname, '\0', >> server_capabilities); > > That exploits that packet_write() uses vnsprintf() to find out the length, > not strlen(). Sweet. OK. > get_remote_heads() would need to store the server_capabilities, maybe with > a function "server_supports(const char *extension_string)" Another thing that would probably be helpful is to redo get_remote_heads() slightly differently, so that it can return information on *all* refs the other end has. We need to extend "struct ref" to mark which one was actually matched/ignored by path_match() and ignore_funny. An completely untested patch is attached, based on fetch-pack that still runs rev-list as an external process, to outline the idea. --- diff --git a/cache.h b/cache.h index 2e36cc5..d39a006 100644 --- a/cache.h +++ b/cache.h @@ -329,6 +329,7 @@ struct ref { unsigned char old_sha1[20]; unsigned char new_sha1[20]; unsigned char force; + unsigned char matched; /* when using REPORT_ALL */ struct ref *peer_ref; /* when renaming */ char name[0]; }; @@ -339,7 +340,9 @@ extern int path_match(const char *path, extern int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, int nr_refspec, char **refspec, int all); extern int get_ack(int fd, unsigned char *result_sha1); -extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, int ignore_funny); +#define GET_REMOTE_HEADS_IGNORE_FUNNY 1 +#define GET_REMOTE_HEADS_REPORT_ALL 2 +extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, int match_options); extern struct packed_git *parse_pack_index(unsigned char *sha1); extern struct packed_git *parse_pack_index_file(const unsigned char *sha1, diff --git a/clone-pack.c b/clone-pack.c index 9609219..8b63183 100644 --- a/clone-pack.c +++ b/clone-pack.c @@ -250,7 +250,7 @@ static int clone_pack(int fd[2], int nr_ struct ref *refs; int status; - get_remote_heads(fd[0], &refs, nr_match, match, 1); + get_remote_heads(fd[0], &refs, nr_match, match, GET_REMOTE_HEADS_IGNORE_FUNNY); if (!refs) { packet_flush(fd[1]); die("no matching remote head"); diff --git a/connect.c b/connect.c index b171c5d..f7a3550 100644 --- a/connect.c +++ b/connect.c @@ -12,8 +12,11 @@ * Read all the refs from the other end */ struct ref **get_remote_heads(int in, struct ref **list, - int nr_match, char **match, int ignore_funny) + int nr_match, char **match, int match_options) { + int ignore_funny = match_options & GET_REMOTE_HEADS_IGNORE_FUNNY; + int report_all = match_options & GET_REMOTE_HEADS_REPORT_ALL; + *list = NULL; for (;;) { struct ref *ref; @@ -21,6 +24,7 @@ struct ref **get_remote_heads(int in, st static char buffer[1000]; char *name; int len; + int matched = 1; len = packet_read_line(in, buffer, sizeof(buffer)); if (!len) @@ -28,17 +32,22 @@ struct ref **get_remote_heads(int in, st if (buffer[len-1] == '\n') buffer[--len] = 0; - if (len < 42 || get_sha1_hex(buffer, old_sha1) || buffer[40] != ' ') - die("protocol error: expected sha/ref, got '%s'", buffer); + if (len < 42 || get_sha1_hex(buffer, old_sha1) || + buffer[40] != ' ') + die("protocol error: expected sha/ref, got '%s'", + buffer); name = buffer + 41; - if (ignore_funny && 45 < len && !memcmp(name, "refs/", 5) && - check_ref_format(name + 5)) - continue; + if ((ignore_funny && 45 < len && !memcmp(name, "refs/", 5) && + check_ref_format(name + 5)) || + (nr_match && !path_match(name, nr_match, match))) { + if (!report_all) + continue; + matched = 0; + } - if (nr_match && !path_match(name, nr_match, match)) - continue; ref = xcalloc(1, sizeof(*ref) + len - 40); + ref->matched = matched; memcpy(ref->old_sha1, old_sha1, 20); memcpy(ref->name, buffer + 41, len - 40); *list = ref; diff --git a/fetch-pack.c b/fetch-pack.c index 8566ab1..11fb1c1 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -13,6 +13,7 @@ static const char fetch_pack_usage[] = static const char *exec = "git-upload-pack"; #define COMPLETE (1U << 0) +#define EXCLUDE (1U << 1) static int find_common(int fd[2], unsigned char *result_sha1, struct ref *refs) @@ -52,17 +53,24 @@ static int find_common(int fd[2], unsign p = commit->parents; while (p && rev_command_len + 44 < sizeof(rev_command)) { - snprintf(rev_command + rev_command_len, 44, - " ^%s", - sha1_to_hex(p->item->object.sha1)); - rev_command_len += 43; + struct object *pobj = &(p->item->object); + if (!pobj->flags & EXCLUDE) { + snprintf(rev_command + + rev_command_len, 44, + " ^%s", + sha1_to_hex(pobj->sha1)); + rev_command_len += 43; + } + pobj->flags |= EXCLUDE; p = p->next; } continue; } repair: - packet_write(fd[1], "want %s\n", sha1_to_hex(remote)); - fetching++; + if (refs->matched) { + packet_write(fd[1], "want %s\n", sha1_to_hex(remote)); + fetching = 1; + } } packet_flush(fd[1]); if (!fetching) @@ -183,6 +191,8 @@ static int everything_local(struct ref * unsigned char local[20]; struct object *o; + if (!refs->matched) + continue; o = parse_object(remote); if (!o || !(o->flags & COMPLETE)) { retval = 0; @@ -204,6 +214,16 @@ static int everything_local(struct ref * return retval; } +static int no_matching_remote(struct ref *ref) +{ + while (ref) + if (ref->matched) + return 0; + else + ref = ref->next; + return 1; +} + static int fetch_pack(int fd[2], int nr_match, char **match) { struct ref *ref; @@ -211,8 +231,10 @@ static int fetch_pack(int fd[2], int nr_ int status; pid_t pid; - get_remote_heads(fd[0], &ref, nr_match, match, 1); - if (!ref) { + get_remote_heads(fd[0], &ref, nr_match, match, + GET_REMOTE_HEADS_IGNORE_FUNNY | + GET_REMOTE_HEADS_REPORT_ALL); + if (no_matching_remote(ref)) { packet_flush(fd[1]); die("no matching remote head"); } @@ -245,8 +267,9 @@ static int fetch_pack(int fd[2], int nr_ die("git-unpack-objects died with error code %d", code); all_done: while (ref) { - printf("%s %s\n", - sha1_to_hex(ref->old_sha1), ref->name); + if (ref->matched) + printf("%s %s\n", + sha1_to_hex(ref->old_sha1), ref->name); ref = ref->next; } return 0; diff --git a/send-pack.c b/send-pack.c index 9f9a6e7..d7bb6c1 100644 --- a/send-pack.c +++ b/send-pack.c @@ -181,7 +181,8 @@ static int send_pack(int in, int out, in int new_refs; /* No funny business with the matcher */ - remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, 1); + remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, + GET_REMOTE_HEADS_IGNORE_FUNNY); get_local_heads(); /* match them up */ ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC] multi_ack protocol v2 2005-10-27 17:45 ` Junio C Hamano @ 2005-10-27 18:04 ` Johannes Schindelin 2005-10-27 19:15 ` Junio C Hamano 0 siblings, 1 reply; 10+ messages in thread From: Johannes Schindelin @ 2005-10-27 18:04 UTC (permalink / raw) To: Junio C Hamano; +Cc: Sergey Vlasov, git Hi, On Thu, 27 Oct 2005, Junio C Hamano wrote: > Another thing that would probably be helpful is to redo > get_remote_heads() slightly differently, so that it can return > information on *all* refs the other end has. We need to extend > "struct ref" to mark which one was actually matched/ignored by > path_match() and ignore_funny. An completely untested patch is > attached, based on fetch-pack that still runs rev-list as an > external process, to outline the idea. A completely tested patch (unfortunately in the middle of my work) does not touch get_remote_heads() at all: diff --git a/fetch-pack.c b/fetch-pack.c --- a/fetch-pack.c +++ b/fetch-pack.c @@ -274,7 +290,27 @@ static void mark_recent_complete_commits } } -static int everything_local(struct ref *refs) +static void filter_refs(struct ref **refs, int nr_match, char **match) +{ + struct ref *prev, *current, *next; + + if (!nr_match) + return; + + for (prev = NULL, current = *refs; current; current = next) { + next = current->next; + if (!path_match(current->name, nr_match, match)) { + if (prev == NULL) + *refs = next; + else + prev->next = next; + free(current); + } else + prev = current; + } +} + +static int everything_local(struct ref **refs, int nr_match, char **match) { struct ref *ref; int retval; @@ -283,7 +319,7 @@ static int everything_local(struct ref * track_object_refs = 0; save_commit_buffer = 0; - for (ref = refs; ref; ref = ref->next) { + for (ref = *refs; ref; ref = ref->next) { struct object *o; o = parse_object(ref->old_sha1); @@ -305,8 +341,10 @@ static int everything_local(struct ref * if (cutoff) mark_recent_complete_commits(cutoff); - for (retval = 1; refs ; refs = refs->next) { - const unsigned char *remote = refs->old_sha1; + filter_refs(refs, nr_match, match); + + for (retval = 1, ref = *refs; ref ; ref = ref->next) { + const unsigned char *remote = ref->old_sha1; unsigned char local[20]; struct object *o; @@ -317,16 +355,16 @@ static int everything_local(struct ref * continue; fprintf(stderr, "want %s (%s)\n", sha1_to_hex(remote), - refs->name); + ref->name); continue; } - memcpy(refs->new_sha1, local, 20); + memcpy(ref->new_sha1, local, 20); if (!verbose) continue; fprintf(stderr, "already have %s (%s)\n", sha1_to_hex(remote), - refs->name); + ref->name); } return retval; } @@ -338,12 +376,12 @@ static int fetch_pack(int fd[2], int nr_ int status; pid_t pid; - get_remote_heads(fd[0], &ref, nr_match, match, 1); + get_remote_heads(fd[0], &ref, 0, NULL, 1); if (!ref) { packet_flush(fd[1]); die("no matching remote head"); } - if (everything_local(ref)) { + if (everything_local(&ref, nr_match, match)) { packet_flush(fd[1]); goto all_done; } ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] multi_ack protocol v2 2005-10-27 18:04 ` Johannes Schindelin @ 2005-10-27 19:15 ` Junio C Hamano 0 siblings, 0 replies; 10+ messages in thread From: Junio C Hamano @ 2005-10-27 19:15 UTC (permalink / raw) To: Johannes Schindelin; +Cc: git Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: > A completely tested patch (unfortunately in the middle of my work) does > not touch get_remote_heads() at all: Much nicer. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] multi_ack protocol v2 2005-10-27 0:16 [RFC] multi_ack protocol v2 Johannes Schindelin 2005-10-27 7:13 ` Junio C Hamano @ 2005-10-27 9:11 ` Paul Mackerras 2005-10-27 10:54 ` Johannes Schindelin 1 sibling, 1 reply; 10+ messages in thread From: Paul Mackerras @ 2005-10-27 9:11 UTC (permalink / raw) To: Johannes Schindelin; +Cc: git Johannes Schindelin writes: > after thinking about my earlier approach, I think there's a better, less > intrusive, and all in all just simpler approach: How many round-trips does it take? When you're on the other side of the Pacific from the server you care about round-trips. :) One of the nice things about rsync is that it does everything with only 1.5 round-trips. Paul. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] multi_ack protocol v2 2005-10-27 9:11 ` Paul Mackerras @ 2005-10-27 10:54 ` Johannes Schindelin 0 siblings, 0 replies; 10+ messages in thread From: Johannes Schindelin @ 2005-10-27 10:54 UTC (permalink / raw) To: Paul Mackerras; +Cc: git Hi, On Thu, 27 Oct 2005, Paul Mackerras wrote: > Johannes Schindelin writes: > > > after thinking about my earlier approach, I think there's a better, less > > intrusive, and all in all just simpler approach: > > How many round-trips does it take? When you're on the other side of > the Pacific from the server you care about round-trips. :) One of the > nice things about rsync is that it does everything with only 1.5 > round-trips. The plan is to reuse the existing framework. It sends 32 "have" messages, then a flush, then again 32 "have" messages, flush again, then reads all answers until a "NAK". The last 3 steps are repeated over and over again. That means that there are always at least 32 "have" messages on the wire (which is described in the source code as "one window ahead"), i.e. it is about 32x faster than simple "have" -> "NAK/ACK" handshakes. Ciao, Dscho ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2005-10-27 19:15 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2005-10-27 0:16 [RFC] multi_ack protocol v2 Johannes Schindelin 2005-10-27 7:13 ` Junio C Hamano 2005-10-27 9:37 ` Johannes Schindelin 2005-10-27 10:16 ` Sergey Vlasov 2005-10-27 10:47 ` Johannes Schindelin 2005-10-27 17:45 ` Junio C Hamano 2005-10-27 18:04 ` Johannes Schindelin 2005-10-27 19:15 ` Junio C Hamano 2005-10-27 9:11 ` Paul Mackerras 2005-10-27 10:54 ` Johannes Schindelin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).