Commit 427ca3d3 by Carlos Martín Nieto Committed by Vicent Marti

Actually implement object negotiation

Only signal that we need a pack if we do need it and don't send a want
just because it's the first. If we don't need to download the pack,
then we can skip all of the negotiation and just return success.

Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk>
parent 946dab73
...@@ -75,6 +75,8 @@ static int filter_wants(git_remote *remote) ...@@ -75,6 +75,8 @@ static int filter_wants(git_remote *remote)
/* If we have the object, mark it so we don't ask for it */ /* If we have the object, mark it so we don't ask for it */
if (git_odb_exists(repo->db, &head->oid)) if (git_odb_exists(repo->db, &head->oid))
head->local = 1; head->local = 1;
else
remote->need_pack = 1;
error = git_vector_insert(&list, head); error = git_vector_insert(&list, head);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
...@@ -108,11 +110,13 @@ int git_fetch_negotiate(git_remote *remote) ...@@ -108,11 +110,13 @@ int git_fetch_negotiate(git_remote *remote)
/* Don't try to negotiate when we don't want anything */ /* Don't try to negotiate when we don't want anything */
if (list->len == 0) if (list->len == 0)
return GIT_SUCCESS; return GIT_SUCCESS;
if (!remote->need_pack)
return GIT_SUCCESS;
/* /*
* Now we have everything set up so we can start tell the server * Now we have everything set up so we can start tell the server
* what we want and what we have. * what we want and what we have.
*/ */
remote->need_pack = 1;
error = git_transport_send_wants(remote->transport, list); error = git_transport_send_wants(remote->transport, list);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to send want list"); return git__rethrow(error, "Failed to send want list");
......
...@@ -55,7 +55,7 @@ int gitno_recv(gitno_buffer *buf) ...@@ -55,7 +55,7 @@ int gitno_recv(gitno_buffer *buf)
ret = recv(buf->fd, buf->data + buf->offset, buf->len - buf->offset, 0); ret = recv(buf->fd, buf->data + buf->offset, buf->len - buf->offset, 0);
if (ret < 0) if (ret < 0)
return git__throw(GIT_EOSERR, "Failed to receive data"); return git__throw(GIT_EOSERR, "Failed to receive data: %s", strerror(errno));
if (ret == 0) /* Orderly shutdown, so exit */ if (ret == 0) /* Orderly shutdown, so exit */
return GIT_SUCCESS; return GIT_SUCCESS;
......
...@@ -299,8 +299,8 @@ static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps, ...@@ -299,8 +299,8 @@ static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps,
int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd) int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd)
{ {
unsigned int i; unsigned int i = 0;
int ret = GIT_SUCCESS; int error = GIT_SUCCESS;
char buf[STRLEN(WANT_PREFIX) + GIT_OID_HEXSZ + 2]; char buf[STRLEN(WANT_PREFIX) + GIT_OID_HEXSZ + 2];
git_remote_head *head; git_remote_head *head;
...@@ -308,26 +308,35 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd) ...@@ -308,26 +308,35 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd)
buf[sizeof(buf) - 2] = '\n'; buf[sizeof(buf) - 2] = '\n';
buf[sizeof(buf) - 1] = '\0'; buf[sizeof(buf) - 1] = '\0';
if (refs->len > 0 && caps->common) { /* If there are common caps, find the first one */
/* Some capabilities are active, so we need to send what we support */ if (caps->common) {
send_want_with_caps(refs->heads[0], caps, fd); for (; i < refs->len; ++i) {
i = 1; head = refs->heads[i];
} else { if (head->local)
i = 0; continue;
else
break;
}
error = send_want_with_caps(refs->heads[i], caps, fd);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to send want pkt with caps");
/* Increase it here so it's correct whether we run this or not */
i++;
} }
/* Continue from where we left off */
for (; i < refs->len; ++i) { for (; i < refs->len; ++i) {
head = refs->heads[i]; head = refs->heads[i];
if (head->local) if (head->local)
continue; continue;
git_oid_fmt(buf + STRLEN(WANT_PREFIX), &head->oid); git_oid_fmt(buf + STRLEN(WANT_PREFIX), &head->oid);
gitno_send(fd, buf, STRLEN(buf), 0); error = gitno_send(fd, buf, STRLEN(buf), 0);
return git__rethrow(error, "Failed to send want pkt");
} }
git_pkt_send_flush(fd); return git_pkt_send_flush(fd);
return ret;
} }
/* /*
......
...@@ -327,7 +327,7 @@ static int git_send_have(git_transport *transport, git_oid *oid) ...@@ -327,7 +327,7 @@ static int git_send_have(git_transport *transport, git_oid *oid)
return git_pkt_send_have(oid, t->socket); return git_pkt_send_have(oid, t->socket);
} }
static int git_negotiate_fetch(git_transport *transport, git_repository *repo, git_headarray *list) static int git_negotiate_fetch(git_transport *transport, git_repository *repo, git_headarray *GIT_UNUSED(list))
{ {
transport_git *t = (transport_git *) transport; transport_git *t = (transport_git *) transport;
git_revwalk *walk; git_revwalk *walk;
...@@ -336,6 +336,11 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g ...@@ -336,6 +336,11 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g
git_oid oid; git_oid oid;
int error; int error;
unsigned int i; unsigned int i;
char buff[128];
gitno_buffer buf;
GIT_UNUSED_ARG(list);
gitno_buffer_setup(&buf, buff, sizeof(buff), t->socket);
error = git_reference_listall(&refs, repo, GIT_REF_LISTALL); error = git_reference_listall(&refs, repo, GIT_REF_LISTALL);
if (error < GIT_ERROR) if (error < GIT_ERROR)
...@@ -349,12 +354,18 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g ...@@ -349,12 +354,18 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g
git_revwalk_sorting(walk, GIT_SORT_TIME); git_revwalk_sorting(walk, GIT_SORT_TIME);
for (i = 0; i < refs.count; ++i) { for (i = 0; i < refs.count; ++i) {
/* No tags */
if (!git__prefixcmp(refs.strings[i], GIT_REFS_TAGS_DIR))
continue;
error = git_reference_lookup(&ref, repo, refs.strings[i]); error = git_reference_lookup(&ref, repo, refs.strings[i]);
if (error < GIT_ERROR) { if (error < GIT_ERROR) {
error = git__rethrow(error, "Failed to lookup %s", refs.strings[i]); error = git__rethrow(error, "Failed to lookup %s", refs.strings[i]);
goto cleanup; goto cleanup;
} }
if (git_reference_type(ref) == GIT_REF_SYMBOLIC)
continue;
error = git_revwalk_push(walk, git_reference_oid(ref)); error = git_revwalk_push(walk, git_reference_oid(ref));
if (error < GIT_ERROR) { if (error < GIT_ERROR) {
error = git__rethrow(error, "Failed to push %s", refs.strings[i]); error = git__rethrow(error, "Failed to push %s", refs.strings[i]);
...@@ -372,17 +383,42 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g ...@@ -372,17 +383,42 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g
while ((error = git_revwalk_next(&oid, walk)) == GIT_SUCCESS) { while ((error = git_revwalk_next(&oid, walk)) == GIT_SUCCESS) {
error = git_pkt_send_have(&oid, t->socket); error = git_pkt_send_have(&oid, t->socket);
i++; i++;
/* if (i % 20 == 0) {
* This is a magic number so we don't flood the server. We const char *ptr = buf.data, *line_end;
* should check every once in a while to see if the server has git_pkt *pkt;
* sent an ACK. git_pkt_send_flush(t->socket);
*/ while (1) {
if (i % 160 == 0) error = gitno_recv(&buf);
break; if (error < GIT_SUCCESS) {
error = git__rethrow(error, "Error receiving data");
goto cleanup;
}
error = git_pkt_parse_line(&pkt, ptr, &line_end, buf.offset);
if (error == GIT_ESHORTBUFFER)
continue;
if (error < GIT_SUCCESS) {
error = git__rethrow(error, "Failed to get answer");
goto cleanup;
}
gitno_consume(&buf, line_end);
if (pkt->type == GIT_PKT_ACK) {
error = GIT_SUCCESS;
goto done;
} else if (pkt->type == GIT_PKT_NAK) {
break;
} else {
error = git__throw(GIT_ERROR, "Got unexpected pkt type");
goto cleanup;
}
}
}
} }
if (error == GIT_EREVWALKOVER) if (error == GIT_EREVWALKOVER)
error = GIT_SUCCESS; error = GIT_SUCCESS;
done:
git_pkt_send_flush(t->socket); git_pkt_send_flush(t->socket);
git_pkt_send_done(t->socket); git_pkt_send_done(t->socket);
...@@ -426,17 +462,17 @@ static int store_pack(char **out, gitno_buffer *buf, git_repository *repo) ...@@ -426,17 +462,17 @@ static int store_pack(char **out, gitno_buffer *buf, git_repository *repo)
goto cleanup; goto cleanup;
while (1) { while (1) {
error = gitno_recv(buf); /* Part of the packfile has been received, don't loose it */
if (error < GIT_SUCCESS)
goto cleanup;
if (error == 0) /* Orderly shutdown */
break;
error = git_filebuf_write(&file, buf->data, buf->offset); error = git_filebuf_write(&file, buf->data, buf->offset);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
gitno_consume_n(buf, buf->offset); gitno_consume_n(buf, buf->offset);
error = gitno_recv(buf);
if (error < GIT_SUCCESS)
goto cleanup;
if (error == 0) /* Orderly shutdown */
break;
} }
*out = git__strdup(file.path_lock); *out = git__strdup(file.path_lock);
...@@ -485,9 +521,9 @@ static int git_download_pack(char **out, git_transport *transport, git_repositor ...@@ -485,9 +521,9 @@ static int git_download_pack(char **out, git_transport *transport, git_repositor
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; return error;
if (pkt->type == GIT_PKT_PACK) { if (pkt->type == GIT_PKT_PACK)
return store_pack(out, &buf, repo); return store_pack(out, &buf, repo);
}
/* For now we don't care about anything */ /* For now we don't care about anything */
free(pkt); free(pkt);
gitno_consume(&buf, line_end); gitno_consume(&buf, line_end);
......
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