summaryrefslogtreecommitdiff
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
parent64d01de8a7802ebec031f921496747bf09426df1 (diff)
downloadlibgit2-114dc6e14c47ff574b4c97d4519782de3f9d28b2.tar.gz
network: implement multi_ack for the git transport
-rw-r--r--src/fetch.c78
-rw-r--r--src/pkt.c18
-rw-r--r--src/transport.h5
-rw-r--r--src/transports/git.c10
4 files changed, 85 insertions, 26 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;
diff --git a/src/pkt.c b/src/pkt.c
index e003b97e2..e60e30d5b 100644
--- a/src/pkt.c
+++ b/src/pkt.c
@@ -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);
}
/*
diff --git a/src/transport.h b/src/transport.h
index 09afb0c72..3ef36f49f 100644
--- a/src/transport.h
+++ b/src/transport.h
@@ -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;
diff --git a/src/transports/git.c b/src/transports/git.c
index 4fcde2d37..f5cdfe7a4 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -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;