graphmod: restore generator nature of dagwalker
9966c95b8c4f introduced the ability to walk the DAG
given arbitrary revisions, but changed the behaviour of
it to return a list of all nodes (and create a changectx
for each one) rather than doing it lazily.
This has a pretty significant impact on performance for large
repositories (tested on CPython repo, with output disabled):
$ time hg glog
real 0m2.642s
user 0m2.560s
sys 0m0.080s
Before 9966c95b8c4f:
$ time hg glog
real 0m0.143s
user 0m0.112s
sys 0m0.032s
And after this fix:
$ time hg glog
real 0m0.213s
user 0m0.184s
sys 0m0.028s
--- a/mercurial/graphmod.py Sat Apr 30 19:42:00 2011 +0200
+++ b/mercurial/graphmod.py Sat Apr 30 15:10:58 2011 +0300
@@ -30,39 +30,27 @@
returned.
"""
if not revs:
- return []
-
- ns = [repo[r].node() for r in revs]
- revdag = list(nodes(repo, ns))
+ return
cl = repo.changelog
lowestrev = min(revs)
gpcache = {}
- leafs = {}
- for i, (id, c, ctx, parents) in enumerate(revdag):
+ for rev in revs:
+ ctx = repo[rev]
+ parents = sorted(set([p.rev() for p in ctx.parents() if p.rev() in revs]))
mpars = [p.rev() for p in ctx.parents() if
p.rev() != nullrev and p.rev() not in parents]
- grandparents = []
for mpar in mpars:
gp = gpcache.get(mpar) or grandparent(cl, lowestrev, revs, mpar)
gpcache[mpar] = gp
if gp is None:
- leafs.setdefault(mpar, []).append((i, ctx))
- else:
- grandparents.append(gp)
+ parents.append(mpar)
+ elif gp not in parents:
+ parents.append(gp)
- if grandparents:
- for gp in grandparents:
- if gp not in revdag[i][3]:
- revdag[i][3].append(gp)
-
- for parent, leafs in leafs.iteritems():
- for i, ctx in leafs:
- revdag[i][3].append(parent)
-
- return revdag
+ yield (ctx.rev(), CHANGESET, ctx, parents)
def nodes(repo, nodes):
"""cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples