Skip to content

Commit 3fbe2d5

Browse files
author
Junio C Hamano
committed
Merge branch 'jc/upload-pack'
* jc/upload-pack: upload-pack: stop the other side when they have more roots than we do.
2 parents 30d055a + 937a515 commit 3fbe2d5

File tree

1 file changed

+92
-9
lines changed

1 file changed

+92
-9
lines changed

upload-pack.c

Lines changed: 92 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,15 @@
1212

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

15-
#define THEY_HAVE (1U << 0)
16-
#define OUR_REF (1U << 1)
17-
#define WANTED (1U << 2)
15+
/* bits #0..7 in revision.h, #8..10 in commit.c */
16+
#define THEY_HAVE (1u << 11)
17+
#define OUR_REF (1u << 12)
18+
#define WANTED (1u << 13)
19+
#define COMMON_KNOWN (1u << 14)
20+
#define REACHABLE (1u << 15)
21+
22+
static unsigned long oldest_have;
23+
1824
static int multi_ack, nr_our_refs;
1925
static int use_thin_pack, use_ofs_delta;
2026
static struct object_array have_obj;
@@ -303,11 +309,12 @@ static void create_pack_file(void)
303309
static int got_sha1(char *hex, unsigned char *sha1)
304310
{
305311
struct object *o;
312+
int we_knew_they_have = 0;
306313

307314
if (get_sha1_hex(hex, sha1))
308315
die("git-upload-pack: expected SHA1 object, got '%s'", hex);
309316
if (!has_sha1_file(sha1))
310-
return 0;
317+
return -1;
311318

312319
o = lookup_object(sha1);
313320
if (!(o && o->parsed))
@@ -316,15 +323,84 @@ static int got_sha1(char *hex, unsigned char *sha1)
316323
die("oops (%s)", sha1_to_hex(sha1));
317324
if (o->type == OBJ_COMMIT) {
318325
struct commit_list *parents;
326+
struct commit *commit = (struct commit *)o;
319327
if (o->flags & THEY_HAVE)
320-
return 0;
321-
o->flags |= THEY_HAVE;
322-
for (parents = ((struct commit*)o)->parents;
328+
we_knew_they_have = 1;
329+
else
330+
o->flags |= THEY_HAVE;
331+
if (!oldest_have || (commit->date < oldest_have))
332+
oldest_have = commit->date;
333+
for (parents = commit->parents;
323334
parents;
324335
parents = parents->next)
325336
parents->item->object.flags |= THEY_HAVE;
326337
}
327-
add_object_array(o, NULL, &have_obj);
338+
if (!we_knew_they_have) {
339+
add_object_array(o, NULL, &have_obj);
340+
return 1;
341+
}
342+
return 0;
343+
}
344+
345+
static int reachable(struct commit *want)
346+
{
347+
struct commit_list *work = NULL;
348+
349+
insert_by_date(want, &work);
350+
while (work) {
351+
struct commit_list *list = work->next;
352+
struct commit *commit = work->item;
353+
free(work);
354+
work = list;
355+
356+
if (commit->object.flags & THEY_HAVE) {
357+
want->object.flags |= COMMON_KNOWN;
358+
break;
359+
}
360+
if (!commit->object.parsed)
361+
parse_object(commit->object.sha1);
362+
if (commit->object.flags & REACHABLE)
363+
continue;
364+
commit->object.flags |= REACHABLE;
365+
if (commit->date < oldest_have)
366+
continue;
367+
for (list = commit->parents; list; list = list->next) {
368+
struct commit *parent = list->item;
369+
if (!(parent->object.flags & REACHABLE))
370+
insert_by_date(parent, &work);
371+
}
372+
}
373+
want->object.flags |= REACHABLE;
374+
clear_commit_marks(want, REACHABLE);
375+
free_commit_list(work);
376+
return (want->object.flags & COMMON_KNOWN);
377+
}
378+
379+
static int ok_to_give_up(void)
380+
{
381+
int i;
382+
383+
if (!have_obj.nr)
384+
return 0;
385+
386+
for (i = 0; i < want_obj.nr; i++) {
387+
struct object *want = want_obj.objects[i].item;
388+
389+
if (want->flags & COMMON_KNOWN)
390+
continue;
391+
want = deref_tag(want, "a want line", 0);
392+
if (!want || want->type != OBJ_COMMIT) {
393+
/* no way to tell if this is reachable by
394+
* looking at the ancestry chain alone, so
395+
* leave a note to ourselves not to worry about
396+
* this object anymore.
397+
*/
398+
want_obj.objects[i].item->flags |= COMMON_KNOWN;
399+
continue;
400+
}
401+
if (!reachable((struct commit *)want))
402+
return 0;
403+
}
328404
return 1;
329405
}
330406

@@ -349,7 +425,13 @@ static int get_common_commits(void)
349425
}
350426
len = strip(line, len);
351427
if (!strncmp(line, "have ", 5)) {
352-
if (got_sha1(line+5, sha1)) {
428+
switch (got_sha1(line+5, sha1)) {
429+
case -1: /* they have what we do not */
430+
if (multi_ack && ok_to_give_up())
431+
packet_write(1, "ACK %s continue\n",
432+
sha1_to_hex(sha1));
433+
break;
434+
default:
353435
memcpy(hex, sha1_to_hex(sha1), 41);
354436
if (multi_ack) {
355437
const char *msg = "ACK %s continue\n";
@@ -358,6 +440,7 @@ static int get_common_commits(void)
358440
}
359441
else if (have_obj.nr == 1)
360442
packet_write(1, "ACK %s\n", hex);
443+
break;
361444
}
362445
continue;
363446
}

0 commit comments

Comments
 (0)