Commit 114dc6e1 by Carlos Martín Nieto

network: implement multi_ack for the git transport

parent 64d01de8
...@@ -75,13 +75,24 @@ static int filter_wants(git_remote *remote) ...@@ -75,13 +75,24 @@ static int filter_wants(git_remote *remote)
} }
/* Wait until we get an ack from the */ /* 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; git_pkt *pkt;
int pkt_type, error; int pkt_type, error = 0;
do { 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 */ /* Wait for max. 1 second */
if ((error = gitno_select_in(buf, 1, 0)) < 0) { if ((error = gitno_select_in(buf, 1, 0)) < 0) {
return -1; return -1;
...@@ -97,21 +108,41 @@ static int recv_pkt(gitno_buffer *buf) ...@@ -97,21 +108,41 @@ static int recv_pkt(gitno_buffer *buf)
if ((error = gitno_recv(buf)) < 0) if ((error = gitno_recv(buf)) < 0)
return -1; 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); } while (error);
gitno_consume(buf, line_end); gitno_consume(buf, line_end);
pkt_type = pkt->type; pkt_type = pkt->type;
git__free(pkt); if (out != NULL)
*out = pkt;
else
git__free(pkt);
return pkt_type; 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 * 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 * them out. When we get an ACK we hide that commit and continue
...@@ -169,18 +200,25 @@ int git_fetch_negotiate(git_remote *remote) ...@@ -169,18 +200,25 @@ int git_fetch_negotiate(git_remote *remote)
goto on_error; goto on_error;
git_buf_clear(&data); git_buf_clear(&data);
pkt_type = recv_pkt(buf); if (t->caps.multi_ack) {
if (store_common(t) < 0)
if (pkt_type == GIT_PKT_ACK) { goto on_error;
break;
} else if (pkt_type == GIT_PKT_NAK) {
continue;
} else { } else {
giterr_set(GITERR_NET, "Unexpected pkt type"); pkt_type = recv_pkt(NULL, buf);
goto on_error;
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) if (error < 0 && error != GIT_REVWALKOVER)
...@@ -195,7 +233,7 @@ int git_fetch_negotiate(git_remote *remote) ...@@ -195,7 +233,7 @@ int git_fetch_negotiate(git_remote *remote)
git_revwalk_free(walk); git_revwalk_free(walk);
/* Now let's eat up whatever the server gives us */ /* 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) { if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) {
giterr_set(GITERR_NET, "Unexpected pkt type"); giterr_set(GITERR_NET, "Unexpected pkt type");
return -1; return -1;
......
...@@ -283,20 +283,28 @@ int git_pkt_buffer_flush(git_buf *buf) ...@@ -283,20 +283,28 @@ int git_pkt_buffer_flush(git_buf *buf)
static int buffer_want_with_caps(git_remote_head *head, git_transport_caps *caps, git_buf *buf) static int buffer_want_with_caps(git_remote_head *head, git_transport_caps *caps, git_buf *buf)
{ {
char capstr[20]; git_buf str = GIT_BUF_INIT;
char oid[GIT_OID_HEXSZ +1] = {0}; char oid[GIT_OID_HEXSZ +1] = {0};
unsigned int len; unsigned int len;
if (caps->ofs_delta) if (caps->ofs_delta)
strncpy(capstr, GIT_CAP_OFS_DELTA, sizeof(capstr)); git_buf_puts(&str, GIT_CAP_OFS_DELTA " ");
if (caps->multi_ack)
git_buf_puts(&str, GIT_CAP_MULTI_ACK " ");
if (git_buf_oom(&str))
return -1;
len = (unsigned int) len = (unsigned int)
(strlen("XXXXwant ") + GIT_OID_HEXSZ + 1 /* NUL */ + (strlen("XXXXwant ") + GIT_OID_HEXSZ + 1 /* NUL */ +
strlen(capstr) + 1 /* LF */); git_buf_len(&str) + 1 /* LF */);
git_buf_grow(buf, git_buf_len(buf) + len); git_buf_grow(buf, git_buf_len(buf) + len);
git_oid_fmt(oid, &head->oid); git_oid_fmt(oid, &head->oid);
return git_buf_printf(buf, "%04xwant %s %s\n", len, oid, capstr); git_buf_printf(buf, "%04xwant %s %s\n", len, oid, git_buf_cstr(&str));
git_buf_free(&str);
return git_buf_oom(buf);
} }
/* /*
......
...@@ -20,10 +20,12 @@ ...@@ -20,10 +20,12 @@
#define GIT_CAP_OFS_DELTA "ofs-delta" #define GIT_CAP_OFS_DELTA "ofs-delta"
#define GIT_CAP_MULTI_ACK "multi_ack"
typedef struct git_transport_caps { typedef struct git_transport_caps {
int common:1, int common:1,
ofs_delta:1; ofs_delta:1,
multi_ack: 1;
} git_transport_caps; } git_transport_caps;
#ifdef GIT_SSL #ifdef GIT_SSL
...@@ -76,6 +78,7 @@ struct git_transport { ...@@ -76,6 +78,7 @@ struct git_transport {
#ifdef GIT_SSL #ifdef GIT_SSL
struct gitno_ssl ssl; struct gitno_ssl ssl;
#endif #endif
git_vector common;
gitno_buffer buffer; gitno_buffer buffer;
GIT_SOCKET socket; GIT_SOCKET socket;
git_transport_caps caps; git_transport_caps caps;
......
...@@ -179,6 +179,12 @@ static int detect_caps(transport_git *t) ...@@ -179,6 +179,12 @@ static int detect_caps(transport_git *t)
continue; continue;
} }
if(!git__prefixcmp(ptr, GIT_CAP_MULTI_ACK)) {
caps->common = caps->multi_ack = 1;
ptr += strlen(GIT_CAP_MULTI_ACK);
continue;
}
/* We don't know this capability, so skip it */ /* We don't know this capability, so skip it */
ptr = strchr(ptr, ' '); ptr = strchr(ptr, ' ');
} }
...@@ -303,6 +309,10 @@ int git_transport_git(git_transport **out) ...@@ -303,6 +309,10 @@ int git_transport_git(git_transport **out)
GITERR_CHECK_ALLOC(t); GITERR_CHECK_ALLOC(t);
memset(t, 0x0, sizeof(transport_git)); memset(t, 0x0, sizeof(transport_git));
if (git_vector_init(&t->parent.common, 8, NULL)) {
git__free(t);
return -1;
}
t->parent.connect = git_connect; t->parent.connect = git_connect;
t->parent.negotiation_step = git_negotiation_step; t->parent.negotiation_step = git_negotiation_step;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment