diff --git a/mercurial/setdiscovery.py b/mercurial/setdiscovery.py --- a/mercurial/setdiscovery.py +++ b/mercurial/setdiscovery.py @@ -171,6 +171,32 @@ class partialdiscovery(object): return getrev(r)[5:6] return getparents + def _childrengetter(self, revs): + + # _updatesample() essentially does interaction over revisions to look + # up their children. This lookup is expensive and doing it in a loop is + # quadratic. We precompute the children for all relevant revisions and + # make the lookup in _updatesample() a simple dict lookup. + # + # Because this function can be called multiple times during discovery, + # we may still perform redundant work and there is room to optimize + # this by keeping a persistent cache of children across invocations. + children = {} + + parentrevs = self._parentsgetter() + + for rev in sorted(revs): + # Always ensure revision has an entry so we don't need to worry + # about missing keys. + children[rev] = [] + for prev in parentrevs(rev): + if prev == nullrev: + continue + c = children.get(prev) + if c is not None: + c.append(rev) + return children.__getitem__ + def takequicksample(self, headrevs, size): """takes a quick sample of size @@ -206,28 +232,9 @@ class partialdiscovery(object): # update from roots revsroots = set(repo.revs('roots(%ld)', revs)) - # _updatesample() essentially does interaction over revisions to look - # up their children. This lookup is expensive and doing it in a loop is - # quadratic. We precompute the children for all relevant revisions and - # make the lookup in _updatesample() a simple dict lookup. - # - # Because this function can be called multiple times during discovery, - # we may still perform redundant work and there is room to optimize - # this by keeping a persistent cache of children across invocations. - children = {} + childrenrevs = self._childrengetter(revs) - for rev in sorted(revs): - # Always ensure revision has an entry so we don't need to worry - # about missing keys. - children[rev] = [] - for prev in parentrevs(rev): - if prev == nullrev: - continue - c = children.get(prev) - if c is not None: - c.append(rev) - - _updatesample(revs, revsroots, sample, children.__getitem__) + _updatesample(revs, revsroots, sample, childrenrevs) assert sample sample = _limitsample(sample, size) if len(sample) < size: