summaryrefslogtreecommitdiff
path: root/src/fetch.c
diff options
context:
space:
mode:
authorCarlos Martín Nieto <carlos@cmartin.tk>2012-07-24 17:10:57 +0200
committerCarlos Martín Nieto <carlos@cmartin.tk>2012-07-30 20:28:16 +0200
commit114dc6e14c47ff574b4c97d4519782de3f9d28b2 (patch)
tree85283b30f80129d66017361acf06120bc6379413 /src/fetch.c
parent64d01de8a7802ebec031f921496747bf09426df1 (diff)
downloadlibgit2-114dc6e14c47ff574b4c97d4519782de3f9d28b2.tar.gz
network: implement multi_ack for the git transport
Diffstat (limited to 'src/fetch.c')
-rw-r--r--src/fetch.c78
1 files changed, 58 insertions, 20 deletions
diff --git a/src/fetch.c b/src/fetch.c
index 6a726417c..4880772d5 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -75,13 +75,24 @@ static int filter_wants(git_remote *remote)
}
/* Wait until we get an ack from the */
-static int recv_pkt(gitno_buffer *buf)
+static int recv_pkt(git_pkt **out, gitno_buffer *buf)
{
- const char *ptr = buf->data, *line_end;
+ const char *ptr = buf->data, *line_end = ptr;
git_pkt *pkt;
- int pkt_type, error;
+ int pkt_type, error = 0;
do {
+ if (buf->offset > 0)
+ error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset);
+ else
+ error = GIT_EBUFS;
+
+ if (error == 0)
+ break; /* return the pkt */
+
+ if (error < 0 && error != GIT_EBUFS)
+ return -1;
+
/* Wait for max. 1 second */
if ((error = gitno_select_in(buf, 1, 0)) < 0) {
return -1;
@@ -97,21 +108,41 @@ static int recv_pkt(gitno_buffer *buf)
if ((error = gitno_recv(buf)) < 0)
return -1;
-
- error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset);
- if (error == GIT_EBUFS)
- continue;
- if (error < 0)
- return -1;
} while (error);
gitno_consume(buf, line_end);
pkt_type = pkt->type;
- git__free(pkt);
+ if (out != NULL)
+ *out = pkt;
+ else
+ git__free(pkt);
return pkt_type;
}
+static int store_common(git_transport *t)
+{
+ int done = 0;
+ git_pkt *pkt = NULL;
+ gitno_buffer *buf = &t->buffer;
+
+ do {
+ if (recv_pkt(&pkt, buf) < 0)
+ return -1;
+
+ if (pkt->type == GIT_PKT_ACK) {
+ if (git_vector_insert(&t->common, pkt) < 0)
+ return -1;
+ } else {
+ git__free(pkt);
+ return 0;
+ }
+
+ } while (1);
+
+ return 0;
+}
+
/*
* In this first version, we push all our refs in and start sending
* them out. When we get an ACK we hide that commit and continue
@@ -169,18 +200,25 @@ int git_fetch_negotiate(git_remote *remote)
goto on_error;
git_buf_clear(&data);
- pkt_type = recv_pkt(buf);
-
- if (pkt_type == GIT_PKT_ACK) {
- break;
- } else if (pkt_type == GIT_PKT_NAK) {
- continue;
+ if (t->caps.multi_ack) {
+ if (store_common(t) < 0)
+ goto on_error;
} else {
- giterr_set(GITERR_NET, "Unexpected pkt type");
- goto on_error;
+ pkt_type = recv_pkt(NULL, buf);
+
+ if (pkt_type == GIT_PKT_ACK) {
+ break;
+ } else if (pkt_type == GIT_PKT_NAK) {
+ continue;
+ } else {
+ giterr_set(GITERR_NET, "Unexpected pkt type");
+ goto on_error;
+ }
}
-
}
+
+ if (t->common.length > 0)
+ break;
}
if (error < 0 && error != GIT_REVWALKOVER)
@@ -195,7 +233,7 @@ int git_fetch_negotiate(git_remote *remote)
git_revwalk_free(walk);
/* Now let's eat up whatever the server gives us */
- pkt_type = recv_pkt(buf);
+ pkt_type = recv_pkt(NULL, buf);
if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) {
giterr_set(GITERR_NET, "Unexpected pkt type");
return -1;