hgext3rd/evolve/stablerange.py
changeset 3240 9361149224a7
parent 3236 7c78b0c482a1
child 3243 556316fe4b4f
--- a/hgext3rd/evolve/stablerange.py	Wed Nov 22 13:44:44 2017 +0100
+++ b/hgext3rd/evolve/stablerange.py	Wed Nov 22 15:05:15 2017 +0100
@@ -249,8 +249,6 @@
         # The point up to which we have data in cache
         self._tiprev = None
         self._tipnode = None
-        # cache the 'depth' of a changeset, the size of '::rev'
-        self._depthcache = {}
         # cache the standard stable subranges or a range
         self._subrangescache = {}
         # To slices merge, we need to walk their descendant in reverse stable
@@ -273,6 +271,7 @@
     def warmup(self, repo, upto=None):
         """warm the cache up"""
         repo = repo.unfiltered()
+        repo.depthcache.update(repo)
         cl = repo.changelog
         # subrange should be warmed from head to range to be able to benefit
         # from revsfromrange cache. otherwise each merge will trigger its own
@@ -340,38 +339,7 @@
                     duration)
 
     def depthrev(self, repo, rev):
-        repo = repo.unfiltered()
-        cl = repo.changelog
-        depth = self._getdepth
-        nullrev = nodemod.nullrev
-        stack = [rev]
-        while stack:
-            revdepth = None
-            current = stack[-1]
-            revdepth = depth(current)
-            if revdepth is not None:
-                stack.pop()
-                continue
-            p1, p2 = self._parents(current, cl.parentrevs)
-            if p1 == nullrev:
-                # root case
-                revdepth = 1
-            elif p2 == nullrev:
-                # linear commit case
-                parentdepth = depth(p1)
-                if parentdepth is None:
-                    stack.append(p1)
-                else:
-                    revdepth = parentdepth + 1
-            else:
-                # merge case
-                revdepth = self._depthmerge(cl, current, p1, p2, stack)
-            if revdepth is not None:
-                self._setdepth(current, revdepth)
-                stack.pop()
-        # actual_depth = len(list(cl.ancestors([rev], inclusive=True)))
-        # assert revdepth == actual_depth, (rev, revdepth, actual_depth)
-        return revdepth
+        return repo.depthcache.get(rev)
 
     def rangelength(self, repo, rangeid):
         headrev, index = rangeid[0], rangeid[1]
@@ -417,18 +385,6 @@
             self._parentscache[rev] = parents
         return parents
 
-    def _getdepth(self, rev):
-        """utility function used to access the depth cache
-
-        This mostly exist to help the on disk persistence."""
-        return self._depthcache.get(rev)
-
-    def _setdepth(self, rev, value):
-        """utility function used to set the depth cache
-
-        This mostly exist to help the on disk persistence."""
-        self._depthcache[rev] = value
-
     def _getsub(self, rev):
         """utility function used to access the subranges cache
 
@@ -491,63 +447,18 @@
             expected = len(revs) - 1
             # Since we do warmup properly, we can expect the cache to be hot
             # for everythin under the merge we investigate
-            cache = self._depthcache
+            cache = repo.depthcache
             # note: we cannot do a binary search because element under the
             # inherited point might have mismatching depth because of inner
             # branching.
             for rev in i:
-                if cache[rev] == expected:
+                if cache.get(rev) == expected:
                     break
                 expected -= 1
             value = (expected - 1, rev)
             self._inheritancecache[merge] = value
         return value
 
-    def _depthmerge(self, cl, rev, p1, p2, stack):
-        # sub method to simplify the main 'depthrev' one
-        revdepth = None
-        depth = self._getdepth
-        depth_p1 = depth(p1)
-        depth_p2 = depth(p2)
-        missingparent = False
-        if depth_p1 is None:
-            stack.append(p1)
-            missingparent = True
-        if depth_p2 is None:
-            stack.append(p2)
-            missingparent = True
-        if missingparent:
-            return None
-        # computin depth of a merge
-        # XXX the common ancestors heads could be cached
-        ancnodes = cl.commonancestorsheads(cl.node(p1), cl.node(p2))
-        ancrevs = [cl.rev(a) for a in ancnodes]
-        anyunkown = False
-        ancdepth = []
-        for r in ancrevs:
-            d = depth(r)
-            if d is None:
-                anyunkown = True
-                stack.append(r)
-            ancdepth.append((r, d))
-        if anyunkown:
-            return None
-        if not ancrevs:
-            # unrelated branch, (no common root)
-            revdepth = depth_p1 + depth_p2 + 1
-        elif len(ancrevs) == 1:
-            # one unique branch point:
-            # we can compute depth without any walk
-            depth_anc = ancdepth[0][1]
-            revdepth = depth_p1 + (depth_p2 - depth_anc) + 1
-        else:
-            # multiple ancestors, we pick one that is
-            # * the deepest (less changeset outside of it),
-            # * lowest revs because more chance to have descendant of other "above"
-            anc, revdepth = max(ancdepth, key=lambda x: (x[1], -x[0]))
-            revdepth += len(cl.findmissingrevs(common=[anc], heads=[rev]))
-        return revdepth
-
     def _subranges(self, repo, rangeid):
         if self.rangelength(repo, rangeid) == 1:
             return []
@@ -706,7 +617,6 @@
                          tiprev        INTEGER NOT NULL,
                          tipnode       BLOB    NOT NULL
                         );""",
-    "CREATE TABLE depth(rev INTEGER NOT NULL PRIMARY KEY, depth INTEGER NOT NULL);",
     """CREATE TABLE range(rev INTEGER  NOT NULL,
                           idx INTEGER NOT NULL,
                           PRIMARY KEY(rev, idx));""",
@@ -721,19 +631,15 @@
     );""",
     "CREATE INDEX subranges_index ON subranges (suprev, supidx);",
     "CREATE INDEX range_index ON range (rev, idx);",
-    "CREATE INDEX depth_index ON depth (rev);"
 ]
 _newmeta = "INSERT INTO meta (schemaversion, tiprev, tipnode) VALUES (?,?,?);"
 _updatemeta = "UPDATE meta SET tiprev = ?, tipnode = ?;"
-_updatedepth = "INSERT INTO depth(rev, depth) VALUES (?,?);"
 _updaterange = "INSERT INTO range(rev, idx) VALUES (?,?);"
 _updatesubranges = """INSERT
                        INTO subranges(listidx, suprev, supidx, subrev, subidx)
                        VALUES (?,?,?,?,?);"""
 _queryexist = "SELECT name FROM sqlite_master WHERE type='table' AND name='meta';"
 _querymeta = "SELECT schemaversion, tiprev, tipnode FROM meta;"
-_querydepth = "SELECT depth FROM depth WHERE rev = ?;"
-_batchdepth = "SELECT rev, depth FROM depth;"
 _queryrange = "SELECT * FROM range WHERE (rev = ? AND idx = ?);"
 _querysubranges = """SELECT subrev, subidx
                      FROM subranges
@@ -742,7 +648,7 @@
 
 class sqlstablerange(stablerange):
 
-    _schemaversion = 0
+    _schemaversion = 1
 
     def __init__(self, repo):
         lrusize = repo.ui.configint('experimental', 'obshashrange.lru-size',
@@ -753,9 +659,7 @@
         self._cl = repo.unfiltered().changelog # (okay to keep an old one)
         self._ondisktiprev = None
         self._ondisktipnode = None
-        self._unsaveddepth = {}
         self._unsavedsubranges = {}
-        self._fulldepth = False
 
     def warmup(self, repo, upto=None):
         self._con # make sure the data base is loaded
@@ -776,22 +680,6 @@
             repo.ui.warn('(cache will not be saved)\n')
             super(sqlstablerange, self).warmup(repo, upto)
 
-    def _getdepth(self, rev):
-        cache = self._depthcache
-        if rev not in cache and rev <= self._ondisktiprev and self._con is not None:
-            value = None
-            result = self._con.execute(_querydepth, (rev,)).fetchone()
-            if result is not None:
-                value = result[0]
-            # in memory caching of the value
-            cache[rev] = value
-        return cache.get(rev)
-
-    def _setdepth(self, rev, depth):
-        assert rev not in self._unsaveddepth
-        self._unsaveddepth[rev] = depth
-        super(sqlstablerange, self)._setdepth(rev, depth)
-
     def _getsub(self, rangeid):
         cache = self._subrangescache
         if rangeid not in cache and rangeid[0] <= self._ondisktiprev and self._con is not None:
@@ -808,10 +696,6 @@
         self._unsavedsubranges[rangeid] = value
         super(sqlstablerange, self)._setsub(rangeid, value)
 
-    def _inheritancepoint(self, *args, **kwargs):
-        self._loaddepth()
-        return super(sqlstablerange, self)._inheritancepoint(*args, **kwargs)
-
     def _db(self):
         try:
             util.makedirs(self._vfs.dirname(self._path))
@@ -847,7 +731,8 @@
 
     def _save(self, repo):
         repo = repo.unfiltered()
-        if not (self._unsavedsubranges or self._unsaveddepth):
+        repo.depthcache.save(repo)
+        if not self._unsavedsubranges:
             return # no new data
 
         if self._con is None:
@@ -886,26 +771,12 @@
             ]
             con.execute(_updatemeta, meta)
 
-        self._savedepth(con, repo)
         self._saverange(con, repo)
         con.commit()
         self._ondisktiprev = self._tiprev
         self._ondisktipnode = self._tipnode
-        self._unsaveddepth.clear()
         self._unsavedsubranges.clear()
 
-    def _savedepth(self, con, repo):
-        repo = repo.unfiltered()
-        data = self._unsaveddepth.items()
-        con.executemany(_updatedepth, data)
-
-    def _loaddepth(self):
-        """batch load all data about depth"""
-        if not (self._fulldepth or self._con is None):
-            result = self._con.execute(_batchdepth)
-            self._depthcache.update(result.fetchall())
-            self._fulldepth = True
-
     def _saverange(self, con, repo):
         repo = repo.unfiltered()
         data = []