Skip to content

Commit 78affc4

Browse files
spearcegitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 28754ab commit 78affc4

File tree

2 files changed

+50
-22
lines changed

2 files changed

+50
-22
lines changed

builtin-fetch-pack.c

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,15 @@ static const unsigned char *get_rev(void)
157157
return commit->object.sha1;
158158
}
159159

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)
161169
{
162170
static char line[1000];
163171
int len = packet_read_line(fd, line, sizeof(line));
@@ -167,12 +175,16 @@ static int get_ack(int fd, unsigned char *result_sha1)
167175
if (line[len-1] == '\n')
168176
line[--len] = 0;
169177
if (!strcmp(line, "NAK"))
170-
return 0;
178+
return NAK;
171179
if (!prefixcmp(line, "ACK ")) {
172180
if (!get_sha1_hex(line+4, result_sha1)) {
173181
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;
176188
}
177189
}
178190
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,
218230
remote_hex = sha1_to_hex(remote);
219231
if (!fetching) {
220232
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");
222235
if (use_sideband == 2) strbuf_addstr(&c, " side-band-64k");
223236
if (use_sideband == 1) strbuf_addstr(&c, " side-band");
224237
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,
298311
if (args.verbose && ack)
299312
fprintf(stderr, "got ack %d %s\n", ack,
300313
sha1_to_hex(result_sha1));
301-
if (ack == 1) {
314+
switch (ack) {
315+
case ACK:
302316
flushes = 0;
303317
multi_ack = 0;
304318
retval = 0;
305319
goto done;
306-
} else if (ack == 2) {
320+
case ACK_common:
321+
case ACK_ready:
322+
case ACK_continue: {
307323
struct commit *commit =
308324
lookup_commit(result_sha1);
309325
mark_common(commit, 0, 1);
310326
retval = 0;
311327
in_vain = 0;
312328
got_continue = 1;
329+
break;
330+
}
313331
}
314332
} while (ack);
315333
flushes--;
@@ -336,7 +354,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
336354
if (args.verbose)
337355
fprintf(stderr, "got ack (%d) %s\n", ack,
338356
sha1_to_hex(result_sha1));
339-
if (ack == 1)
357+
if (ack == ACK)
340358
return 0;
341359
multi_ack = 1;
342360
continue;
@@ -618,7 +636,12 @@ static struct ref *do_fetch_pack(int fd[2],
618636

619637
if (is_repository_shallow() && !server_supports("shallow"))
620638
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")) {
622645
if (args.verbose)
623646
fprintf(stderr, "Server supports multi_ack\n");
624647
multi_ack = 1;

upload-pack.c

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ static int get_common_commits(void)
498498
{
499499
static char line[1000];
500500
unsigned char sha1[20];
501-
char hex[41], last_hex[41];
501+
char last_hex[41];
502502

503503
save_commit_buffer = 0;
504504

@@ -515,19 +515,22 @@ static int get_common_commits(void)
515515
if (!prefixcmp(line, "have ")) {
516516
switch (got_sha1(line+5, sha1)) {
517517
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+
}
521525
break;
522526
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);
529532
else if (have_obj.nr == 1)
530-
packet_write(1, "ACK %s\n", hex);
533+
packet_write(1, "ACK %s\n", last_hex);
531534
break;
532535
}
533536
continue;
@@ -587,7 +590,9 @@ static void receive_needs(void)
587590
get_sha1_hex(line+5, sha1_buf))
588591
die("git upload-pack: protocol error, "
589592
"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"))
591596
multi_ack = 1;
592597
if (strstr(line+45, "thin-pack"))
593598
use_thin_pack = 1;
@@ -681,7 +686,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
681686
{
682687
static const char *capabilities = "multi_ack thin-pack side-band"
683688
" side-band-64k ofs-delta shallow no-progress"
684-
" include-tag";
689+
" include-tag multi_ack_detailed";
685690
struct object *o = parse_object(sha1);
686691

687692
if (!o)

0 commit comments

Comments
 (0)