Commit 2f8c481c by Carlos Martín Nieto

protocol: basic support for multi_ack_detailed

This tells the server that we speak it, but we don't make use of its
extra information to determine if there's a better place to stop
negotiating.

In a somewhat-related change, reorder the capabilities so we ask for
them in the same order as git does.

Also take this opportunity to factor out a fairly-indented portion of
the negotiation logic.
parent 97d32abb
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define GIT_CAP_OFS_DELTA "ofs-delta" #define GIT_CAP_OFS_DELTA "ofs-delta"
#define GIT_CAP_MULTI_ACK "multi_ack" #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 "side-band"
#define GIT_CAP_SIDE_BAND_64K "side-band-64k" #define GIT_CAP_SIDE_BAND_64K "side-band-64k"
#define GIT_CAP_INCLUDE_TAG "include-tag" #define GIT_CAP_INCLUDE_TAG "include-tag"
...@@ -40,7 +41,7 @@ enum git_pkt_type { ...@@ -40,7 +41,7 @@ enum git_pkt_type {
GIT_PKT_UNPACK, GIT_PKT_UNPACK,
}; };
/* Used for multi-ack */ /* Used for multi_ack and mutli_ack_detailed */
enum git_ack_status { enum git_ack_status {
GIT_ACK_NONE, GIT_ACK_NONE,
GIT_ACK_CONTINUE, GIT_ACK_CONTINUE,
...@@ -113,6 +114,7 @@ typedef struct transport_smart_caps { ...@@ -113,6 +114,7 @@ typedef struct transport_smart_caps {
int common:1, int common:1,
ofs_delta:1, ofs_delta:1,
multi_ack: 1, multi_ack: 1,
multi_ack_detailed: 1,
side_band:1, side_band:1,
side_band_64k:1, side_band_64k:1,
include_tag:1, include_tag:1,
......
...@@ -39,7 +39,7 @@ static int flush_pkt(git_pkt **out) ...@@ -39,7 +39,7 @@ static int flush_pkt(git_pkt **out)
return 0; 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) static int ack_pkt(git_pkt **out, const char *line, size_t len)
{ {
git_pkt_ack *pkt; git_pkt_ack *pkt;
...@@ -62,6 +62,10 @@ static int ack_pkt(git_pkt **out, const char *line, size_t len) ...@@ -62,6 +62,10 @@ static int ack_pkt(git_pkt **out, const char *line, size_t len)
if (len >= 7) { if (len >= 7) {
if (!git__prefixcmp(line + 1, "continue")) if (!git__prefixcmp(line + 1, "continue"))
pkt->status = GIT_ACK_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; *out = (git_pkt *) pkt;
...@@ -456,18 +460,17 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca ...@@ -456,18 +460,17 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
char oid[GIT_OID_HEXSZ +1] = {0}; char oid[GIT_OID_HEXSZ +1] = {0};
unsigned int len; unsigned int len;
/* 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 */ /* Prefer side-band-64k if the server supports both */
if (caps->side_band) {
if (caps->side_band_64k) if (caps->side_band_64k)
git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND_64K); git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND_64K);
else else if (caps->side_band)
git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND); 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)
git_buf_puts(&str, GIT_CAP_MULTI_ACK " ");
if (caps->include_tag) if (caps->include_tag)
git_buf_puts(&str, GIT_CAP_INCLUDE_TAG " "); git_buf_puts(&str, GIT_CAP_INCLUDE_TAG " ");
...@@ -475,6 +478,9 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca ...@@ -475,6 +478,9 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
if (caps->thin_pack) if (caps->thin_pack)
git_buf_puts(&str, GIT_CAP_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)) if (git_buf_oom(&str))
return -1; return -1;
......
...@@ -97,6 +97,13 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps) ...@@ -97,6 +97,13 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps)
continue; 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)) { if (!git__prefixcmp(ptr, GIT_CAP_MULTI_ACK)) {
caps->common = caps->multi_ack = 1; caps->common = caps->multi_ack = 1;
ptr += strlen(GIT_CAP_MULTI_ACK); ptr += strlen(GIT_CAP_MULTI_ACK);
...@@ -236,6 +243,32 @@ on_error: ...@@ -236,6 +243,32 @@ on_error:
return -1; 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) 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; transport_smart *t = (transport_smart *)transport;
...@@ -287,7 +320,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c ...@@ -287,7 +320,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
goto on_error; goto on_error;
git_buf_clear(&data); 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) if ((error = store_common(t)) < 0)
goto on_error; goto on_error;
} else { } else {
...@@ -365,7 +398,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c ...@@ -365,7 +398,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
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 */
if (!t->caps.multi_ack) { if (!t->caps.multi_ack && !t->caps.multi_ack_detailed) {
pkt_type = recv_pkt(NULL, buf); pkt_type = recv_pkt(NULL, buf);
if (pkt_type < 0) { if (pkt_type < 0) {
...@@ -375,22 +408,10 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c ...@@ -375,22 +408,10 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
return -1; return -1;
} }
} else { } else {
git_pkt_ack *pkt; error = wait_while_ack(buf);
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);
} }
return 0; return error;
on_error: on_error:
git_revwalk_free(walk); git_revwalk_free(walk);
......
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