Skip to content

Commit e2abfa7

Browse files
committed
Merge branch 'hx/negotiator-non-recursive'
The implementation of the default "negotiator", used to find common ancestor over the network for object tranfer, used to be recursive; it was updated to be iterative to conserve stackspace usage. * hx/negotiator-non-recursive: negotiator/skipping: fix some problems in mark_common() negotiator/default: avoid stack overflow
2 parents 07ac32f + 10e8a52 commit e2abfa7

File tree

2 files changed

+44
-17
lines changed

2 files changed

+44
-17
lines changed

negotiator/default.c

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,30 +56,49 @@ static int clear_marks(const char *refname, const struct object_id *oid,
5656
static void mark_common(struct negotiation_state *ns, struct commit *commit,
5757
int ancestors_only, int dont_parse)
5858
{
59-
if (commit != NULL && !(commit->object.flags & COMMON)) {
60-
struct object *o = (struct object *)commit;
59+
struct prio_queue queue = { NULL };
60+
61+
if (!commit || (commit->object.flags & COMMON))
62+
return;
63+
64+
prio_queue_put(&queue, commit);
65+
if (!ancestors_only) {
66+
commit->object.flags |= COMMON;
6167

62-
if (!ancestors_only)
63-
o->flags |= COMMON;
68+
if ((commit->object.flags & SEEN) && !(commit->object.flags & POPPED))
69+
ns->non_common_revs--;
70+
}
71+
while ((commit = prio_queue_get(&queue))) {
72+
struct object *o = (struct object *)commit;
6473

6574
if (!(o->flags & SEEN))
6675
rev_list_push(ns, commit, SEEN);
6776
else {
6877
struct commit_list *parents;
6978

70-
if (!ancestors_only && !(o->flags & POPPED))
71-
ns->non_common_revs--;
7279
if (!o->parsed && !dont_parse)
7380
if (repo_parse_commit(the_repository, commit))
74-
return;
81+
continue;
7582

7683
for (parents = commit->parents;
7784
parents;
78-
parents = parents->next)
79-
mark_common(ns, parents->item, 0,
80-
dont_parse);
85+
parents = parents->next) {
86+
struct commit *p = parents->item;
87+
88+
if (p->object.flags & COMMON)
89+
continue;
90+
91+
p->object.flags |= COMMON;
92+
93+
if ((p->object.flags & SEEN) && !(p->object.flags & POPPED))
94+
ns->non_common_revs--;
95+
96+
prio_queue_put(&queue, parents->item);
97+
}
8198
}
8299
}
100+
101+
clear_prio_queue(&queue);
83102
}
84103

85104
/*

negotiator/skipping.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,29 +86,37 @@ static int clear_marks(const char *refname, const struct object_id *oid,
8686
}
8787

8888
/*
89-
* Mark this SEEN commit and all its SEEN ancestors as COMMON.
89+
* Mark this SEEN commit and all its parsed SEEN ancestors as COMMON.
9090
*/
9191
static void mark_common(struct data *data, struct commit *seen_commit)
9292
{
9393
struct prio_queue queue = { NULL };
9494
struct commit *c;
9595

96+
if (seen_commit->object.flags & COMMON)
97+
return;
98+
9699
prio_queue_put(&queue, seen_commit);
100+
seen_commit->object.flags |= COMMON;
97101
while ((c = prio_queue_get(&queue))) {
98102
struct commit_list *p;
99-
if (c->object.flags & COMMON)
100-
return;
101-
c->object.flags |= COMMON;
103+
102104
if (!(c->object.flags & POPPED))
103105
data->non_common_revs--;
104106

105107
if (!c->object.parsed)
106-
return;
108+
continue;
107109
for (p = c->parents; p; p = p->next) {
108-
if (p->item->object.flags & SEEN)
109-
prio_queue_put(&queue, p->item);
110+
if (!(p->item->object.flags & SEEN) ||
111+
(p->item->object.flags & COMMON))
112+
continue;
113+
114+
p->item->object.flags |= COMMON;
115+
prio_queue_put(&queue, p->item);
110116
}
111117
}
118+
119+
clear_prio_queue(&queue);
112120
}
113121

114122
/*

0 commit comments

Comments
 (0)