Skip to content

Commit

Permalink
upload-pack: stop the other side when they have more roots than we do.
Browse files Browse the repository at this point in the history
When the downloader has more roots than we do, we will see many
"have" that leads to the root we do not have and let the other
side walk all the way to that root.  Tell them to stop sending the
branch'es ancestors by sending a fake "ACK" when we already have
common ancestor for the wanted refs.

Signed-off-by: Junio C Hamano <junkio@cox.net>
  • Loading branch information
Junio C Hamano committed Aug 13, 2006
1 parent c04c4e5 commit 937a515
Showing 1 changed file with 92 additions and 9 deletions.
101 changes: 92 additions & 9 deletions upload-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@

static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] <dir>";

#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 int multi_ack = 0, nr_our_refs = 0;
static int use_thin_pack = 0;
static struct object_array have_obj;
Expand Down Expand Up @@ -323,11 +329,12 @@ static void create_pack_file(void)
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))
Expand All @@ -336,15 +343,84 @@ static int got_sha1(char *hex, unsigned char *sha1)
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;
}

Expand All @@ -369,7 +445,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";
Expand All @@ -378,6 +460,7 @@ static int get_common_commits(void)
}
else if (have_obj.nr == 1)
packet_write(1, "ACK %s\n", hex);
break;
}
continue;
}
Expand Down

0 comments on commit 937a515

Please sign in to comment.