D4322: setdiscovery: don't use dagutil for parent resolution

indygreg (Gregory Szorc) phabricator at mercurial-scm.org
Fri Aug 17 21:31:06 UTC 2018


indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  _updatesample()'s one remaining use of revlogdag is for resolving
  the parents of a revision.
  
  In 2 cases, we actually resolve parents. In 1, we operate on the
  inverted DAG and resolve children.
  
  This commit teaches _updatesample() to receive an argument defining
  the function to resolve "parent" revisions. Call sites pass in
  changelog.parentrevs() or a wrapper around changelog.children()
  accordingly.
  
  The use of children() is semantically correct. But it is quadratic,
  since revlog.children() does a range scan over all revisions starting
  at its input and effectively calls parentrevs() to build up the list
  of children. So calling it repeatedly in a loop is a recipe for
  bad performance. I will be implementing something better in a
  subsequent commit. I wanted to get the porting off of dagutil done
  in a way that was simple and correct.
  
  Like other patches in this series, this change is potentially impacted
  but revlogdag's ignorance of filtered revisions. The new code is
  filtering aware, since changelog's revs() (used by children() will
  skip filtered revisions and therefore hidden children won't appear.
  This is potentially backwards incompatible. But no tests fail and
  I think this code should respect visibility.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D4322

AFFECTED FILES
  mercurial/setdiscovery.py

CHANGE DETAILS

diff --git a/mercurial/setdiscovery.py b/mercurial/setdiscovery.py
--- a/mercurial/setdiscovery.py
+++ b/mercurial/setdiscovery.py
@@ -56,7 +56,7 @@
     util,
 )
 
-def _updatesample(dag, revs, heads, sample, quicksamplesize=0):
+def _updatesample(revs, heads, sample, parentfn, quicksamplesize=0):
     """update an existing sample to match the expected size
 
     The sample is updated with revs exponentially distant from each head of the
@@ -66,10 +66,10 @@
     reached. Otherwise sampling will happen until roots of the <revs> set are
     reached.
 
-    :dag: a dag object from dagutil
     :revs:  set of revs we want to discover (if None, assume the whole dag)
     :heads: set of DAG head revs
     :sample: a sample to update
+    :parentfn: a callable to resolve parents for a revision
     :quicksamplesize: optional target size of the sample"""
     dist = {}
     visit = collections.deque(heads)
@@ -87,12 +87,13 @@
             if quicksamplesize and (len(sample) >= quicksamplesize):
                 return
         seen.add(curr)
-        for p in dag.parents(curr):
-            if not revs or p in revs:
+
+        for p in parentfn(curr):
+            if p != nullrev and (not revs or p in revs):
                 dist.setdefault(p, d + 1)
                 visit.append(p)
 
-def _takequicksample(repo, dag, headrevs, revs, size):
+def _takequicksample(repo, headrevs, revs, size):
     """takes a quick sample of size <size>
 
     It is meant for initial sampling and focuses on querying heads and close
@@ -107,18 +108,23 @@
     if len(sample) >= size:
         return _limitsample(sample, size)
 
-    _updatesample(dag, None, headrevs, sample, quicksamplesize=size)
+    _updatesample(None, headrevs, sample, repo.changelog.parentrevs,
+                  quicksamplesize=size)
     return sample
 
-def _takefullsample(repo, dag, headrevs, revs, size):
+def _takefullsample(repo, headrevs, revs, size):
     sample = set(repo.revs('heads(%ld)', revs))
 
     # update from heads
     revsheads = set(repo.revs('heads(%ld)', revs))
-    _updatesample(dag, revs, revsheads, sample)
+    _updatesample(revs, revsheads, sample, repo.changelog.parentrevs)
     # update from roots
     revsroots = set(repo.revs('roots(%ld)', revs))
-    _updatesample(dag.inverse(), revs, revsroots, sample)
+
+    # TODO this is quadratic
+    parentfn = lambda rev: repo.changelog.children(repo.changelog.node(rev))
+
+    _updatesample(revs, revsroots, sample, parentfn)
     assert sample
     sample = _limitsample(sample, size)
     if len(sample) < size:
@@ -244,7 +250,7 @@
         if len(undecided) < targetsize:
             sample = list(undecided)
         else:
-            sample = samplefunc(local, dag, ownheads, undecided, targetsize)
+            sample = samplefunc(local, ownheads, undecided, targetsize)
 
         roundtrips += 1
         progress.update(roundtrips)



To: indygreg, #hg-reviewers
Cc: mercurial-devel


More information about the Mercurial-devel mailing list