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
This commit is contained in:
Junio C Hamano 2023-05-10 10:23:27 -07:00
Родитель 07ac32fff9 10e8a52ef1
Коммит e2abfa7212
2 изменённых файлов: 44 добавлений и 17 удалений

Просмотреть файл

@ -56,30 +56,49 @@ static int clear_marks(const char *refname, const struct object_id *oid,
static void mark_common(struct negotiation_state *ns, struct commit *commit,
int ancestors_only, int dont_parse)
{
if (commit != NULL && !(commit->object.flags & COMMON)) {
struct object *o = (struct object *)commit;
struct prio_queue queue = { NULL };
if (!ancestors_only)
o->flags |= COMMON;
if (!commit || (commit->object.flags & COMMON))
return;
prio_queue_put(&queue, commit);
if (!ancestors_only) {
commit->object.flags |= COMMON;
if ((commit->object.flags & SEEN) && !(commit->object.flags & POPPED))
ns->non_common_revs--;
}
while ((commit = prio_queue_get(&queue))) {
struct object *o = (struct object *)commit;
if (!(o->flags & SEEN))
rev_list_push(ns, commit, SEEN);
else {
struct commit_list *parents;
if (!ancestors_only && !(o->flags & POPPED))
ns->non_common_revs--;
if (!o->parsed && !dont_parse)
if (repo_parse_commit(the_repository, commit))
return;
continue;
for (parents = commit->parents;
parents;
parents = parents->next)
mark_common(ns, parents->item, 0,
dont_parse);
parents = parents->next) {
struct commit *p = parents->item;
if (p->object.flags & COMMON)
continue;
p->object.flags |= COMMON;
if ((p->object.flags & SEEN) && !(p->object.flags & POPPED))
ns->non_common_revs--;
prio_queue_put(&queue, parents->item);
}
}
}
clear_prio_queue(&queue);
}
/*

Просмотреть файл

@ -86,29 +86,37 @@ static int clear_marks(const char *refname, const struct object_id *oid,
}
/*
* Mark this SEEN commit and all its SEEN ancestors as COMMON.
* Mark this SEEN commit and all its parsed SEEN ancestors as COMMON.
*/
static void mark_common(struct data *data, struct commit *seen_commit)
{
struct prio_queue queue = { NULL };
struct commit *c;
if (seen_commit->object.flags & COMMON)
return;
prio_queue_put(&queue, seen_commit);
seen_commit->object.flags |= COMMON;
while ((c = prio_queue_get(&queue))) {
struct commit_list *p;
if (c->object.flags & COMMON)
return;
c->object.flags |= COMMON;
if (!(c->object.flags & POPPED))
data->non_common_revs--;
if (!c->object.parsed)
return;
continue;
for (p = c->parents; p; p = p->next) {
if (p->item->object.flags & SEEN)
prio_queue_put(&queue, p->item);
if (!(p->item->object.flags & SEEN) ||
(p->item->object.flags & COMMON))
continue;
p->item->object.flags |= COMMON;
prio_queue_put(&queue, p->item);
}
}
clear_prio_queue(&queue);
}
/*