stablerange: move the range class in the new module
authorPierre-Yves David <pierre-yves.david@ens-lyon.org>
Sun, 19 Mar 2017 03:07:01 +0100
changeset 2130 d784622dd5dc
parent 2129 d07bb7cbae2f
child 2131 86dd39478638
stablerange: move the range class in the new module Our ultimate goal is to remove this class for performance reason. however for now, it contains most of the code we care about so we migrate it as a block first.
hgext3rd/evolve/obsdiscovery.py
hgext3rd/evolve/stablerange.py
--- a/hgext3rd/evolve/obsdiscovery.py	Sun Mar 19 03:06:53 2017 +0100
+++ b/hgext3rd/evolve/obsdiscovery.py	Sun Mar 19 03:07:01 2017 +0100
@@ -24,7 +24,6 @@
 
 import hashlib
 import heapq
-import math
 import struct
 
 from mercurial import (
@@ -260,7 +259,7 @@
         return True
 
     for h in heads:
-        entry = _range(local, h, 0)
+        entry = stablerange.stablerange(local, h, 0)
         addentry(entry)
 
     querycount = 0
@@ -362,7 +361,7 @@
         n = data[:20]
         index = _unpack('>I', data[20:])[0]
         r = op.repo.changelog.rev(n)
-        rhash = _range(op.repo, r, index).obshash
+        rhash = stablerange.stablerange(op.repo, r, index).obshash
         replies.append(data + rhash)
         data = inpart.read(24)
     op.reply.newpart('reply:_donotusemeever_evoext_obshashrange_1', data=iter(replies))
@@ -395,7 +394,7 @@
     # prewarm depth cache
     for r in repo.revs("::%ld", revs):
         repo.stablerange.depthrev(repo, r)
-    toproceed = [_range(repo, r, 0, ) for r in revs]
+    toproceed = [stablerange.stablerange(repo, r, 0, ) for r in revs]
     ranges = set(toproceed)
     while toproceed:
         entry = toproceed.pop()
@@ -410,147 +409,6 @@
         d = (r.head, s(r.node), r.index, len(r), r.depth, node.short(r.obshash))
         ui.status('%3d %s %5d %4d %5d %s\n' % d)
 
-def _hlp2(i):
-    """return highest power of two lower than 'i'"""
-    return 2 ** int(math.log(i - 1, 2))
-
-class _range(object):
-
-    def __init__(self, repo, head, index, revs=None):
-        self._repo = repo.unfiltered()
-        self.head = head
-        self.index = index
-        if revs is not None:
-            assert len(revs) == len(self)
-            self._revs = revs
-        assert index < self.depth, (head, index, self.depth, revs)
-
-    def __repr__(self):
-        return '%s %d %d %s' % (node.short(self.node), self.depth, self.index, node.short(self.obshash))
-
-    def __hash__(self):
-        return self._id
-
-    def __eq__(self, other):
-        if type(self) != type(other):
-            raise NotImplementedError()
-        return self.stablekey == other.stablekey
-
-    @util.propertycache
-    def _id(self):
-        return hash(self.stablekey)
-
-    @util.propertycache
-    def stablekey(self):
-        return (self.node, self.index)
-
-    @util.propertycache
-    def node(self):
-        return self._repo.changelog.node(self.head)
-
-    def __len__(self):
-        return self.depth - self.index
-
-    @util.propertycache
-    def depth(self):
-        return self._repo.stablerange.depthrev(self._repo, self.head)
-
-    @util.propertycache
-    def _revs(self):
-        r = stablerange.stablesort(self._repo, [self.head])[self.index:]
-        assert len(r) == len(self), (self.head, self.index, len(r), len(self))
-        return r
-
-    def _slicesat(self, globalindex):
-        localindex = globalindex - self.index
-
-        cl = self._repo.changelog
-
-        result = []
-        bottom = self._revs[:localindex]
-        top = _range(self._repo, self.head, globalindex, self._revs[localindex:])
-        #
-        toprootdepth = self._repo.stablerange.depthrev(self._repo, top._revs[0])
-        if toprootdepth + len(top) == self.depth + 1:
-            bheads = [bottom[-1]]
-        else:
-            bheads = set(bottom)
-            parentrevs = cl.parentrevs
-            du = bheads.difference_update
-            for r in bottom:
-                du(parentrevs(r))
-            # if len(bheads) == 1:
-            #     assert 1 == len(self._repo.revs('roots(%ld)', top._revs))
-        if len(bheads) == 1:
-            newhead = bottom[-1]
-            bottomdepth = self._repo.stablerange.depthrev(self._repo, newhead)
-            newstart = bottomdepth - len(bottom)
-            result.append(_range(self._repo, newhead, newstart, bottom))
-        else:
-            # assert 1 < len(bheads), (toprootdepth, len(top), len(self))
-            cl = self._repo.changelog
-            for h in bheads:
-                subset = cl.ancestors([h], inclusive=True)
-                hrevs = [r for r in bottom if r in subset]
-                start = self._repo.stablerange.depthrev(self._repo, h) - len(hrevs)
-                entry = _range(self._repo, h, start, [r for r in bottom if r in subset])
-                result.append(entry)
-        result.append(top)
-        return result
-
-    def subranges(self):
-        cached = self._repo.stablerange.subranges(self._repo, self)
-        if cached is not None:
-            return cached
-        step = _hlp2(self.depth)
-        standard_start = 0
-        while standard_start < self.index and 0 < step:
-            if standard_start + step < self.depth:
-                standard_start += step
-            step //= 2
-        if self.index == standard_start:
-            slicesize = _hlp2(len(self))
-            slicepoint = self.index + slicesize
-        else:
-            assert standard_start < self.depth
-            slicepoint = standard_start
-        result = self._slicesat(slicepoint)
-        self._repo.stablerange.setsubranges(self, result)
-        return result
-
-    @util.propertycache
-    def obshash(self):
-        cache = self._repo.obsstore.rangeobshashcache
-        obshash = cache.get(self)
-        if obshash is not None:
-            return obshash
-        pieces = []
-        nullid = node.nullid
-        if len(self) == 1:
-            tmarkers = self._repo.obsstore.relevantmarkers([self.node])
-            pieces = []
-            for m in tmarkers:
-                mbin = obsolete._fm1encodeonemarker(m)
-                pieces.append(mbin)
-            pieces.sort()
-        else:
-            for subrange in self.subranges():
-                obshash = subrange.obshash
-                if obshash != nullid:
-                    pieces.append(obshash)
-
-        sha = hashlib.sha1()
-        # note: if there is only one subrange with actual data, we'll just
-        # reuse the same hash.
-        if not pieces:
-            obshash = node.nullid
-        elif len(pieces) != 1 or obshash is None:
-            sha = hashlib.sha1()
-            for p in pieces:
-                sha.update(p)
-            obshash = cache[self] = sha.digest()
-        return obshash
-
 @eh.wrapfunction(obsolete.obsstore, '_addmarkers')
 def _addmarkers(orig, obsstore, *args, **kwargs):
     obsstore.rangeobshashcache.clear()
--- a/hgext3rd/evolve/stablerange.py	Sun Mar 19 03:06:53 2017 +0100
+++ b/hgext3rd/evolve/stablerange.py	Sun Mar 19 03:07:01 2017 +0100
@@ -8,18 +8,23 @@
 # GNU General Public License version 2 or any later version.
 
 import collections
+import math
+import hashlib
+
 from mercurial import (
     commands,
     cmdutil,
     localrepo,
     node as nodemod,
     scmutil,
+    util,
 )
 
 from mercurial.i18n import _
 
 from . import (
     exthelper,
+    obsolete,
 )
 
 eh = exthelper.exthelper()
@@ -123,6 +128,10 @@
     assert len(result) == len(set(result))
     return result
 
+#################################
+### Stable Range computation  ###
+#################################
+
 class stablerangecache(dict):
 
     def __init__(self):
@@ -227,6 +236,147 @@
         # this class reach.
         return self._subrangescache.get(rangeid)
 
+def _hlp2(i):
+    """return highest power of two lower than 'i'"""
+    return 2 ** int(math.log(i - 1, 2))
+
+class stablerange(object):
+
+    def __init__(self, repo, head, index, revs=None):
+        self._repo = repo.unfiltered()
+        self.head = head
+        self.index = index
+        if revs is not None:
+            assert len(revs) == len(self)
+            self._revs = revs
+        assert index < self.depth, (head, index, self.depth, revs)
+
+    def __repr__(self):
+        return '%s %d %d %s' % (nodemod.short(self.node), self.depth, self.index, nodemod.short(self.obshash))
+
+    def __hash__(self):
+        return self._id
+
+    def __eq__(self, other):
+        if type(self) != type(other):
+            raise NotImplementedError()
+        return self.stablekey == other.stablekey
+
+    @util.propertycache
+    def _id(self):
+        return hash(self.stablekey)
+
+    @util.propertycache
+    def stablekey(self):
+        return (self.node, self.index)
+
+    @util.propertycache
+    def node(self):
+        return self._repo.changelog.node(self.head)
+
+    def __len__(self):
+        return self.depth - self.index
+
+    @util.propertycache
+    def depth(self):
+        return self._repo.stablerange.depthrev(self._repo, self.head)
+
+    @util.propertycache
+    def _revs(self):
+        r = stablesort(self._repo, [self.head])[self.index:]
+        assert len(r) == len(self), (self.head, self.index, len(r), len(self))
+        return r
+
+    def _slicesat(self, globalindex):
+        localindex = globalindex - self.index
+
+        cl = self._repo.changelog
+
+        result = []
+        bottom = self._revs[:localindex]
+        top = stablerange(self._repo, self.head, globalindex, self._revs[localindex:])
+        #
+        toprootdepth = self._repo.stablerange.depthrev(self._repo, top._revs[0])
+        if toprootdepth + len(top) == self.depth + 1:
+            bheads = [bottom[-1]]
+        else:
+            bheads = set(bottom)
+            parentrevs = cl.parentrevs
+            du = bheads.difference_update
+            for r in bottom:
+                du(parentrevs(r))
+            # if len(bheads) == 1:
+            #     assert 1 == len(self._repo.revs('roots(%ld)', top._revs))
+        if len(bheads) == 1:
+            newhead = bottom[-1]
+            bottomdepth = self._repo.stablerange.depthrev(self._repo, newhead)
+            newstart = bottomdepth - len(bottom)
+            result.append(stablerange(self._repo, newhead, newstart, bottom))
+        else:
+            # assert 1 < len(bheads), (toprootdepth, len(top), len(self))
+            cl = self._repo.changelog
+            for h in bheads:
+                subset = cl.ancestors([h], inclusive=True)
+                hrevs = [r for r in bottom if r in subset]
+                start = self._repo.stablerange.depthrev(self._repo, h) - len(hrevs)
+                entry = stablerange(self._repo, h, start, [r for r in bottom if r in subset])
+                result.append(entry)
+        result.append(top)
+        return result
+
+    def subranges(self):
+        cached = self._repo.stablerange.subranges(self._repo, self)
+        if cached is not None:
+            return cached
+        step = _hlp2(self.depth)
+        standard_start = 0
+        while standard_start < self.index and 0 < step:
+            if standard_start + step < self.depth:
+                standard_start += step
+            step //= 2
+        if self.index == standard_start:
+            slicesize = _hlp2(len(self))
+            slicepoint = self.index + slicesize
+        else:
+            assert standard_start < self.depth
+            slicepoint = standard_start
+        result = self._slicesat(slicepoint)
+        self._repo.stablerange.setsubranges(self, result)
+        return result
+
+    @util.propertycache
+    def obshash(self):
+        cache = self._repo.obsstore.rangeobshashcache
+        obshash = cache.get(self)
+        if obshash is not None:
+            return obshash
+        pieces = []
+        nullid = nodemod.nullid
+        if len(self) == 1:
+            tmarkers = self._repo.obsstore.relevantmarkers([self.node])
+            pieces = []
+            for m in tmarkers:
+                mbin = obsolete._fm1encodeonemarker(m)
+                pieces.append(mbin)
+            pieces.sort()
+        else:
+            for subrange in self.subranges():
+                obshash = subrange.obshash
+                if obshash != nullid:
+                    pieces.append(obshash)
+
+        sha = hashlib.sha1()
+        # note: if there is only one subrange with actual data, we'll just
+        # reuse the same hash.
+        if not pieces:
+            obshash = nodemod.nullid
+        elif len(pieces) != 1 or obshash is None:
+            sha = hashlib.sha1()
+            for p in pieces:
+                sha.update(p)
+            obshash = cache[self] = sha.digest()
+        return obshash
+
 @eh.reposetup
 def setupcache(ui, repo):