From: Junio C Hamano Date: Fri, 24 Nov 2006 10:34:27 +0000 (-0800) Subject: Merge branch 'jc/upload-pack' X-Git-Tag: v1.5.0-rc0~235 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/3fbe2d54d7d91378934df7b16d70dc5877586fae?ds=inline;hp=-c Merge branch 'jc/upload-pack' * jc/upload-pack: upload-pack: stop the other side when they have more roots than we do. --- 3fbe2d54d7d91378934df7b16d70dc5877586fae diff --combined upload-pack.c index ddaa72f0a9,e8f4be373c..4572fff07c --- a/upload-pack.c +++ b/upload-pack.c @@@ -4,7 -4,6 +4,7 @@@ #include "cache.h" #include "refs.h" #include "pkt-line.h" +#include "sideband.h" #include "tag.h" #include "object.h" #include "commit.h" @@@ -12,18 -11,21 +12,24 @@@ static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] "; - #define THEY_HAVE (1U << 0) - #define OUR_REF (1U << 1) - #define WANTED (1U << 2) + /* bits #0..7 in revision.h, #8..10 in commit.c */ + #define THEY_HAVE (1u << 11) + #define OUR_REF (1u << 12) + #define WANTED (1u << 13) + #define COMMON_KNOWN (1u << 14) + #define REACHABLE (1u << 15) + -static unsigned long oldest_have = 0; ++static unsigned long oldest_have; + -static int multi_ack = 0, nr_our_refs = 0; -static int use_thin_pack = 0; +static int multi_ack, nr_our_refs; +static int use_thin_pack, use_ofs_delta; static struct object_array have_obj; static struct object_array want_obj; -static unsigned int timeout = 0; -static int use_sideband = 0; +static unsigned int timeout; +/* 0 for no sideband, + * otherwise maximum packet size (up to 65520 bytes). + */ +static int use_sideband; static void reset_timeout(void) { @@@ -37,18 -39,45 +43,18 @@@ static int strip(char *line, int len return len; } -#define PACKET_MAX 1000 static ssize_t send_client_data(int fd, const char *data, ssize_t sz) { - ssize_t ssz; - const char *p; - - if (!data) { - if (!use_sideband) - return 0; - packet_flush(1); - } - - if (!use_sideband) { - if (fd == 3) - /* emergency quit */ - fd = 2; - if (fd == 2) { - xwrite(fd, data, sz); - return sz; - } - return safe_write(fd, data, sz); + if (use_sideband) + return send_sideband(1, fd, data, sz, use_sideband); + if (fd == 3) + /* emergency quit */ + fd = 2; + if (fd == 2) { + xwrite(fd, data, sz); + return sz; } - p = data; - ssz = sz; - while (sz) { - unsigned n; - char hdr[5]; - - n = sz; - if (PACKET_MAX - 5 < n) - n = PACKET_MAX - 5; - sprintf(hdr, "%04x", n + 5); - hdr[4] = fd; - safe_write(1, hdr, 5); - safe_write(1, p, n); - p += n; - sz -= n; - } - return ssz; + return safe_write(fd, data, sz); } static void create_pack_file(void) @@@ -137,9 -166,7 +143,9 @@@ close(pu_pipe[1]); close(pe_pipe[0]); close(pe_pipe[1]); - execl_git_cmd("pack-objects", "--stdout", "--progress", NULL); + execl_git_cmd("pack-objects", "--stdout", "--progress", + use_ofs_delta ? "--delta-base-offset" : NULL, + NULL); kill(pid_rev_list, SIGKILL); die("git-upload-pack: unable to exec git-pack-objects"); } @@@ -287,8 -314,7 +293,8 @@@ goto fail; fprintf(stderr, "flushed.\n"); } - send_client_data(1, NULL, 0); + if (use_sideband) + packet_flush(1); return; } fail: @@@ -303,11 -329,12 +309,12 @@@ static int got_sha1(char *hex, unsigned char *sha1) { struct object *o; + int we_knew_they_have = 0; if (get_sha1_hex(hex, sha1)) die("git-upload-pack: expected SHA1 object, got '%s'", hex); if (!has_sha1_file(sha1)) - return 0; + return -1; o = lookup_object(sha1); if (!(o && o->parsed)) @@@ -316,15 -343,84 +323,84 @@@ die("oops (%s)", sha1_to_hex(sha1)); if (o->type == OBJ_COMMIT) { struct commit_list *parents; + struct commit *commit = (struct commit *)o; if (o->flags & THEY_HAVE) - return 0; - o->flags |= THEY_HAVE; - for (parents = ((struct commit*)o)->parents; + we_knew_they_have = 1; + else + o->flags |= THEY_HAVE; + if (!oldest_have || (commit->date < oldest_have)) + oldest_have = commit->date; + for (parents = commit->parents; parents; parents = parents->next) parents->item->object.flags |= THEY_HAVE; } - add_object_array(o, NULL, &have_obj); + if (!we_knew_they_have) { + add_object_array(o, NULL, &have_obj); + return 1; + } + return 0; + } + + static int reachable(struct commit *want) + { + struct commit_list *work = NULL; + + insert_by_date(want, &work); + while (work) { + struct commit_list *list = work->next; + struct commit *commit = work->item; + free(work); + work = list; + + if (commit->object.flags & THEY_HAVE) { + want->object.flags |= COMMON_KNOWN; + break; + } + if (!commit->object.parsed) + parse_object(commit->object.sha1); + if (commit->object.flags & REACHABLE) + continue; + commit->object.flags |= REACHABLE; + if (commit->date < oldest_have) + continue; + for (list = commit->parents; list; list = list->next) { + struct commit *parent = list->item; + if (!(parent->object.flags & REACHABLE)) + insert_by_date(parent, &work); + } + } + want->object.flags |= REACHABLE; + clear_commit_marks(want, REACHABLE); + free_commit_list(work); + return (want->object.flags & COMMON_KNOWN); + } + + static int ok_to_give_up(void) + { + int i; + + if (!have_obj.nr) + return 0; + + for (i = 0; i < want_obj.nr; i++) { + struct object *want = want_obj.objects[i].item; + + if (want->flags & COMMON_KNOWN) + continue; + want = deref_tag(want, "a want line", 0); + if (!want || want->type != OBJ_COMMIT) { + /* no way to tell if this is reachable by + * looking at the ancestry chain alone, so + * leave a note to ourselves not to worry about + * this object anymore. + */ + want_obj.objects[i].item->flags |= COMMON_KNOWN; + continue; + } + if (!reachable((struct commit *)want)) + return 0; + } return 1; } @@@ -349,7 -445,13 +425,13 @@@ static int get_common_commits(void } len = strip(line, len); if (!strncmp(line, "have ", 5)) { - if (got_sha1(line+5, sha1)) { + switch (got_sha1(line+5, sha1)) { + case -1: /* they have what we do not */ + if (multi_ack && ok_to_give_up()) + packet_write(1, "ACK %s continue\n", + sha1_to_hex(sha1)); + break; + default: memcpy(hex, sha1_to_hex(sha1), 41); if (multi_ack) { const char *msg = "ACK %s continue\n"; @@@ -358,6 -460,7 +440,7 @@@ } else if (have_obj.nr == 1) packet_write(1, "ACK %s\n", hex); + break; } continue; } @@@ -395,12 -498,8 +478,12 @@@ static void receive_needs(void multi_ack = 1; if (strstr(line+45, "thin-pack")) use_thin_pack = 1; - if (strstr(line+45, "side-band")) - use_sideband = 1; + if (strstr(line+45, "ofs-delta")) + use_ofs_delta = 1; + if (strstr(line+45, "side-band-64k")) + use_sideband = LARGE_PACKET_MAX; + else if (strstr(line+45, "side-band")) + use_sideband = DEFAULT_PACKET_MAX; /* We have sent all our refs already, and the other end * should have chosen out of them; otherwise they are @@@ -420,9 -519,9 +503,9 @@@ } } -static int send_ref(const char *refname, const unsigned char *sha1) +static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { - static const char *capabilities = "multi_ack thin-pack side-band"; + static const char *capabilities = "multi_ack thin-pack side-band side-band-64k ofs-delta"; struct object *o = parse_object(sha1); if (!o) @@@ -445,17 -544,18 +528,17 @@@ return 0; } -static int upload_pack(void) +static void upload_pack(void) { reset_timeout(); - head_ref(send_ref); - for_each_ref(send_ref); + head_ref(send_ref, NULL); + for_each_ref(send_ref, NULL); packet_flush(1); receive_needs(); - if (!want_obj.nr) - return 0; - get_common_commits(); - create_pack_file(); - return 0; + if (want_obj.nr) { + get_common_commits(); + create_pack_file(); + } } int main(int argc, char **argv)