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)
}
/* 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;
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,7 +200,11 @@ int git_fetch_negotiate(git_remote *remote)
goto on_error;
git_buf_clear(&data);
pkt_type = recv_pkt(buf);
if (t->caps.multi_ack) {
if (store_common(t) < 0)
goto on_error;
} else {
pkt_type = recv_pkt(NULL, buf);
if (pkt_type == GIT_PKT_ACK) {
break;
......@@ -179,10 +214,13 @@ int git_fetch_negotiate(git_remote *remote)
giterr_set(GITERR_NET, "Unexpected pkt type");
goto on_error;
}
}
}
if (t->common.length > 0)
break;
}
if (error < 0 && error != GIT_REVWALKOVER)
goto on_error;
......@@ -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;
......
......@@ -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)
{
char capstr[20];
git_buf str = GIT_BUF_INIT;
char oid[GIT_OID_HEXSZ +1] = {0};
unsigned int len;
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)
(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_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 @@
#define GIT_CAP_OFS_DELTA "ofs-delta"
#define GIT_CAP_MULTI_ACK "multi_ack"
typedef struct git_transport_caps {
int common:1,
ofs_delta:1;
ofs_delta:1,
multi_ack: 1;
} git_transport_caps;
#ifdef GIT_SSL
......@@ -76,6 +78,7 @@ struct git_transport {
#ifdef GIT_SSL
struct gitno_ssl ssl;
#endif
git_vector common;
gitno_buffer buffer;
GIT_SOCKET socket;
git_transport_caps caps;
......
......@@ -179,6 +179,12 @@ static int detect_caps(transport_git *t)
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 */
ptr = strchr(ptr, ' ');
}
......@@ -303,6 +309,10 @@ int git_transport_git(git_transport **out)
GITERR_CHECK_ALLOC(t);
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.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