summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVicent Martí <vicent@github.com>2013-10-30 09:27:36 -0700
committerVicent Martí <vicent@github.com>2013-10-30 09:27:36 -0700
commitcc7453417f6ab4783d1211a0562fa3ea438649b2 (patch)
treee48976288f6edd9368ba5b1ad68615e86cbeadb6 /src
parent1d37da3392276c16d49a3680e9bd6c22f2c3abd0 (diff)
parent2f8c481cc08ee00fa9c298f80eae0616e99faef1 (diff)
downloadlibgit2-cc7453417f6ab4783d1211a0562fa3ea438649b2.tar.gz
Merge pull request #1919 from libgit2/cmn/multi-ack-detailed
protocol: basic support for multi_ack_detailed
Diffstat (limited to 'src')
-rw-r--r--src/transports/smart.h4
-rw-r--r--src/transports/smart_pkt.c30
-rw-r--r--src/transports/smart_protocol.c53
3 files changed, 58 insertions, 29 deletions
diff --git a/src/transports/smart.h b/src/transports/smart.h
index 7fda27d4e..5232e54de 100644
--- a/src/transports/smart.h
+++ b/src/transports/smart.h
@@ -16,6 +16,7 @@
#define GIT_CAP_OFS_DELTA "ofs-delta"
#define GIT_CAP_MULTI_ACK "multi_ack"
+#define GIT_CAP_MULTI_ACK_DETAILED "multi_ack_detailed"
#define GIT_CAP_SIDE_BAND "side-band"
#define GIT_CAP_SIDE_BAND_64K "side-band-64k"
#define GIT_CAP_INCLUDE_TAG "include-tag"
@@ -40,7 +41,7 @@ enum git_pkt_type {
GIT_PKT_UNPACK,
};
-/* Used for multi-ack */
+/* Used for multi_ack and mutli_ack_detailed */
enum git_ack_status {
GIT_ACK_NONE,
GIT_ACK_CONTINUE,
@@ -113,6 +114,7 @@ typedef struct transport_smart_caps {
int common:1,
ofs_delta:1,
multi_ack: 1,
+ multi_ack_detailed: 1,
side_band:1,
side_band_64k:1,
include_tag:1,
diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c
index a1f623c78..2bb09c750 100644
--- a/src/transports/smart_pkt.c
+++ b/src/transports/smart_pkt.c
@@ -39,7 +39,7 @@ static int flush_pkt(git_pkt **out)
return 0;
}
-/* the rest of the line will be useful for multi_ack */
+/* the rest of the line will be useful for multi_ack and multi_ack_detailed */
static int ack_pkt(git_pkt **out, const char *line, size_t len)
{
git_pkt_ack *pkt;
@@ -62,6 +62,10 @@ static int ack_pkt(git_pkt **out, const char *line, size_t len)
if (len >= 7) {
if (!git__prefixcmp(line + 1, "continue"))
pkt->status = GIT_ACK_CONTINUE;
+ if (!git__prefixcmp(line + 1, "common"))
+ pkt->status = GIT_ACK_COMMON;
+ if (!git__prefixcmp(line + 1, "ready"))
+ pkt->status = GIT_ACK_READY;
}
*out = (git_pkt *) pkt;
@@ -456,25 +460,27 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
char oid[GIT_OID_HEXSZ +1] = {0};
unsigned int len;
- /* Prefer side-band-64k if the server supports both */
- if (caps->side_band) {
- if (caps->side_band_64k)
- git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND_64K);
- else
- git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND);
- }
- if (caps->ofs_delta)
- git_buf_puts(&str, GIT_CAP_OFS_DELTA " ");
-
- if (caps->multi_ack)
+ /* Prefer multi_ack_detailed */
+ if (caps->multi_ack_detailed)
+ git_buf_puts(&str, GIT_CAP_MULTI_ACK_DETAILED " ");
+ else if (caps->multi_ack)
git_buf_puts(&str, GIT_CAP_MULTI_ACK " ");
+ /* Prefer side-band-64k if the server supports both */
+ if (caps->side_band_64k)
+ git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND_64K);
+ else if (caps->side_band)
+ git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND);
+
if (caps->include_tag)
git_buf_puts(&str, GIT_CAP_INCLUDE_TAG " ");
if (caps->thin_pack)
git_buf_puts(&str, GIT_CAP_THIN_PACK " ");
+ if (caps->ofs_delta)
+ git_buf_puts(&str, GIT_CAP_OFS_DELTA " ");
+
if (git_buf_oom(&str))
return -1;
diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c
index af6e35fa1..a12921269 100644
--- a/src/transports/smart_protocol.c
+++ b/src/transports/smart_protocol.c
@@ -97,6 +97,13 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps)
continue;
}
+ /* Keep multi_ack_detailed before multi_ack */
+ if (!git__prefixcmp(ptr, GIT_CAP_MULTI_ACK_DETAILED)) {
+ caps->common = caps->multi_ack_detailed = 1;
+ ptr += strlen(GIT_CAP_MULTI_ACK_DETAILED);
+ continue;
+ }
+
if (!git__prefixcmp(ptr, GIT_CAP_MULTI_ACK)) {
caps->common = caps->multi_ack = 1;
ptr += strlen(GIT_CAP_MULTI_ACK);
@@ -236,6 +243,32 @@ on_error:
return -1;
}
+static int wait_while_ack(gitno_buffer *buf)
+{
+ int error;
+ git_pkt_ack *pkt = NULL;
+
+ while (1) {
+ git__free(pkt);
+
+ if ((error = recv_pkt((git_pkt **)&pkt, buf)) < 0)
+ return error;
+
+ if (pkt->type == GIT_PKT_NAK)
+ break;
+
+ if (pkt->type == GIT_PKT_ACK &&
+ (pkt->status != GIT_ACK_CONTINUE ||
+ pkt->status != GIT_ACK_COMMON)) {
+ git__free(pkt);
+ break;
+ }
+ }
+
+ git__free(pkt);
+ return 0;
+}
+
int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_remote_head * const *refs, size_t count)
{
transport_smart *t = (transport_smart *)transport;
@@ -287,7 +320,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
goto on_error;
git_buf_clear(&data);
- if (t->caps.multi_ack) {
+ if (t->caps.multi_ack || t->caps.multi_ack_detailed) {
if ((error = store_common(t)) < 0)
goto on_error;
} else {
@@ -365,7 +398,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
git_revwalk_free(walk);
/* Now let's eat up whatever the server gives us */
- if (!t->caps.multi_ack) {
+ if (!t->caps.multi_ack && !t->caps.multi_ack_detailed) {
pkt_type = recv_pkt(NULL, buf);
if (pkt_type < 0) {
@@ -375,22 +408,10 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
return -1;
}
} else {
- git_pkt_ack *pkt;
- do {
- if ((error = recv_pkt((git_pkt **)&pkt, buf)) < 0)
- return error;
-
- if (pkt->type == GIT_PKT_NAK ||
- (pkt->type == GIT_PKT_ACK && pkt->status != GIT_ACK_CONTINUE)) {
- git__free(pkt);
- break;
- }
-
- git__free(pkt);
- } while (1);
+ error = wait_while_ack(buf);
}
- return 0;
+ return error;
on_error:
git_revwalk_free(walk);