depthcache: move to a dedicated object and storage
authorPierre-Yves David <pierre-yves.david@octobus.net>
Wed, 22 Nov 2017 15:05:15 +0100
changeset 3240 9361149224a7
parent 3239 0c8c7b5274a5
child 3241 0d2c095aeb2a
depthcache: move to a dedicated object and storage The SQL cache was overkill and fragile. We move to a dedicated storage using the new generic class.
hgext3rd/evolve/depthcache.py
hgext3rd/evolve/stablerange.py
tests/test-discovery-obshashrange.t
--- a/hgext3rd/evolve/depthcache.py	Wed Nov 22 13:44:44 2017 +0100
+++ b/hgext3rd/evolve/depthcache.py	Wed Nov 22 15:05:15 2017 +0100
@@ -1,11 +1,19 @@
 from __future__ import absolute_import
 
+import array
+import weakref
+
 from mercurial import (
+    localrepo,
+    node as nodemod,
+    util,
     scmutil,
 )
 
 from . import (
+    error,
     exthelper,
+    genericcaches,
 )
 
 from mercurial.i18n import _
@@ -20,12 +28,186 @@
     'debugdepth',
     [
         ('r', 'rev', [], 'revs to print depth for'),
+        ('', 'method', 'cached', "one of 'simple', 'cached', 'compare'"),
     ],
     _('REVS'))
 def debugdepth(ui, repo, **opts):
     """display depth of REVS
     """
     revs = scmutil.revrange(repo, opts['rev'])
+    method = opts['method']
+    if method == 'cached':
+        cache = repo.depthcache
+        cache.save(repo)
     for r in revs:
         ctx = repo[r]
-        ui.write('%s %d\n' % (ctx, simpledepth(repo, r)))
+        if method == 'simple':
+            depth = simpledepth(repo, r)
+        elif method == 'cached':
+            depth = cache.get(r)
+        elif method == 'compare':
+            simple = simpledepth(repo, r)
+            cached = cache.get(r)
+            if simple != cached:
+                raise error.Abort('depth differ for revision %s: %d != %d'
+                                  % (ctx, simple, cached))
+        else:
+            raise error.Abort('unknown method "%s"' % method)
+        ui.write('%s %d\n' % (ctx, depth))
+
+@eh.reposetup
+def setupcache(ui, repo):
+
+    class depthcacherepo(repo.__class__):
+
+        @localrepo.unfilteredpropertycache
+        def depthcache(self):
+            cache = depthcache()
+            cache.update(self)
+            return cache
+
+        @localrepo.unfilteredmethod
+        def destroyed(self):
+            if 'obsstore' in vars(self):
+                self.depthcache.clear()
+            super(depthcacherepo, self).destroyed()
+
+        if util.safehasattr(repo, 'updatecaches'):
+            @localrepo.unfilteredmethod
+            def updatecaches(self, tr=None):
+                if (repo.ui.configbool('experimental', 'obshashrange',
+                                       False)
+                        and repo.ui.configbool('experimental',
+                                               'obshashrange.warm-cache',
+                                               True)):
+                    self.depthcache.update(repo)
+                    self.depthcache.save(repo)
+                super(depthcacherepo, self).updatecaches(tr)
+
+        else:
+            def transaction(self, *args, **kwargs):
+                tr = super(depthcacherepo, self).transaction(*args, **kwargs)
+                reporef = weakref.ref(self)
+
+                def _warmcache(tr):
+                    repo = reporef()
+                    if repo is None:
+                        return
+                    repo = repo.unfiltered()
+                    # As pointed in 'obscache.update', we could have the changelog
+                    # and the obsstore in charge of updating the cache when new
+                    # items goes it. The tranaction logic would then only be
+                    # involved for the 'pending' and final writing on disk.
+                    self.obsstore.obscache.update(repo)
+                    self.obsstore.obscache.save(repo)
+
+                if (repo.ui.configbool('experimental', 'obshashrange',
+                                       False)
+                        and repo.ui.configbool('experimental',
+                                               'obshashrange.warm-cache',
+                                               True)):
+                    tr.addpostclose('warmcache-depthcache', _warmcache)
+                return tr
+
+    repo.__class__ = depthcacherepo
+
+class depthcache(genericcaches.changelogsourcebase):
+
+    _filepath = 'evoext-depthcache-00'
+    _cachename = 'evo-ext-depthcache'
+
+    def __init__(self):
+        super(depthcache, self).__init__()
+        self._data = array.array('l')
+
+    def get(self, rev):
+        if len(self._data) <= rev:
+            raise error.ProgrammingError('depthcache must be warmed before use')
+        return self._data[rev]
+
+    def _updatefrom(self, repo, data):
+        """compute the rev of one revision, assert previous revision has an hot cache
+        """
+        cl = repo.unfiltered().changelog
+        for rev in data:
+            assert rev == len(self._data), (rev, len(self._data))
+            self._data.append(self._depth(cl, rev))
+
+    def _depth(self, changelog, rev):
+        cl = changelog
+        p1, p2 = cl.parentrevs(rev)
+        if p1 == nodemod.nullrev:
+            # root case
+            return 1
+        elif p2 == nodemod.nullrev:
+            # linear commit case
+            return self.get(p1) + 1
+        # merge case, must find the amount of exclusive content
+        depth_p1 = self.get(p1)
+        depth_p2 = self.get(p2)
+        # computing depth of a merge
+        ancnodes = cl.commonancestorsheads(cl.node(p1), cl.node(p2))
+        if not ancnodes:
+            # unrelated branch, (no common root)
+            revdepth = depth_p1 + depth_p2 + 1
+        elif len(ancnodes) == 1:
+            # one unique branch point:
+            # we can compute depth without any walk
+            ancrev = cl.rev(ancnodes[0])
+            depth_anc = self.get(ancrev)
+            revdepth = depth_p1 + (depth_p2 - depth_anc) + 1
+        else:
+            # we pick the parent that is that is
+            # * the deepest (less changeset outside of it),
+            # * lowest revs because more chance to have descendant of other "above"
+            parents = [(p1, depth_p1), (p2, depth_p2)]
+            parents.sort(key=lambda x: (x[1], -x[0]))
+            revdepth = parents[1][1]
+            revdepth += len(cl.findmissingrevs(common=[parents[1][0]],
+                                               heads=[parents[0][0]]))
+            revdepth += 1 # the merge revision
+        return revdepth
+
+    # cache internal logic
+
+    def clear(self, reset=False):
+        """invalidate the cache content
+
+        if 'reset' is passed, we detected a strip and the cache will have to be
+        recomputed.
+
+        Subclasses MUST overide this method to actually affect the cache data.
+        """
+        super(depthcache, self).clear()
+        self._data = array.array('l')
+
+    # crude version of a cache, to show the kind of information we have to store
+
+    def load(self, repo):
+        """load data from disk"""
+        assert repo.filtername is None
+
+        data = repo.cachevfs.tryread(self._filepath)
+        self._data = array.array('l')
+        if not data:
+            self._cachekey = self.emptykey
+        else:
+            headerdata = data[:self._cachekeysize]
+            self._cachekey = self._deserializecachekey(headerdata)
+            self._data.fromstring(data[self._cachekeysize:])
+        self._ondiskkey = self._cachekey
+
+    def save(self, repo):
+        """save the data to disk
+
+        Format is pretty simple, we serialise the cache key and then drop the
+        bytearray.
+        """
+        if self._cachekey is None or self._cachekey == self._ondiskkey:
+            return
+
+        cachefile = repo.cachevfs(self._filepath, 'w', atomictemp=True)
+        headerdata = self._serializecachekey()
+        cachefile.write(headerdata)
+        cachefile.write(self._data.tostring())
+        cachefile.close()
--- 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 = []
--- a/tests/test-discovery-obshashrange.t	Wed Nov 22 13:44:44 2017 +0100
+++ b/tests/test-discovery-obshashrange.t	Wed Nov 22 15:05:15 2017 +0100
@@ -35,6 +35,8 @@
   * @0000000000000000000000000000000000000000 (*)> -R server serve --stdio (glob)
   * @0000000000000000000000000000000000000000 (*)> -R server serve --stdio exited 0 after *.?? seconds (glob)
   * @0000000000000000000000000000000000000000 (*)> debugbuilddag .+7 (glob)
+  * @0000000000000000000000000000000000000000 (*)> strip detected, evo-ext-depthcache cache reset (glob)
+  * @0000000000000000000000000000000000000000 (*)> updated evo-ext-depthcache in *.???? seconds (8r) (glob)
   * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obshashrange in *.???? seconds (8r, 0o) (glob)
   * @0000000000000000000000000000000000000000 (*)> updated served branch cache in *.???? seconds (glob)
   * @0000000000000000000000000000000000000000 (*)> wrote served branch cache with 1 labels and 1 nodes (glob)
@@ -155,6 +157,8 @@
   $ hg blackbox
   * @0000000000000000000000000000000000000000 (*)> clone 'ssh://user@dummy/server' client exited 0 after *.?? seconds (glob)
   * @0000000000000000000000000000000000000000 (*)> pull --rev 4 (glob)
+  * @0000000000000000000000000000000000000000 (*)> strip detected, evo-ext-depthcache cache reset (glob)
+  * @0000000000000000000000000000000000000000 (*)> updated evo-ext-depthcache in *.???? seconds (5r) (glob)
   * @0000000000000000000000000000000000000000 (*)> updated stablerange cache in *.???? seconds (glob)
   * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obshashrange in *.???? seconds (5r, 3o) (glob)
   * @0000000000000000000000000000000000000000 (*)> updated base branch cache in *.???? seconds (glob)
@@ -236,6 +240,7 @@
   received listkey for "phases": 58 bytes
   $ hg -R ../server blackbox
   * @0000000000000000000000000000000000000000 (*)> -R server serve --stdio (glob)
+  * @0000000000000000000000000000000000000000 (*)> updated evo-ext-depthcache in *.???? seconds (1r) (glob)
   * @0000000000000000000000000000000000000000 (*)> updated stablerange cache in *.???? seconds (glob)
   * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obshashrange in *.???? seconds (1r, 1o) (glob)
   * @0000000000000000000000000000000000000000 (*)> obscache is out of date, falling back to slower obsstore version (glob)
@@ -298,6 +303,7 @@
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> add foo (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> add foo exited 0 after *.?? seconds (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> commit -m foo (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-depthcache in *.???? seconds (1r) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obshashrange in *.???? seconds (1r, 0o) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obscache is out of date, falling back to slower obsstore version (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated served branch cache in *.???? seconds (glob)
@@ -412,6 +418,7 @@
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> log -G exited 0 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> pull -r 6 (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obsdiscovery, 2/6 mismatch - 1 obshashrange queries in *.???? seconds (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-depthcache in *.???? seconds (2r) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated stablerange cache in *.???? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obshashcache reset - new markers affect cached ranges (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obshashrange in *.???? seconds (2r, 3o) (glob)
@@ -558,6 +565,7 @@
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobshashrange --subranges --rev 'heads(all())' exited 0 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> pull (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obsdiscovery, 0/8 mismatch - 1 obshashrange queries in *.???? seconds (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-depthcache in *.???? seconds (1r) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated stablerange cache in *.???? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obshashrange in *.???? seconds (1r, 1o) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated served branch cache in *.???? seconds (glob)
@@ -566,6 +574,8 @@
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> 1 incoming changes - new heads: 4de32a90b66c (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> pull exited 0 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> rollback (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> strip detected, evo-ext-depthcache cache reset (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-depthcache in *.???? seconds (8r) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated base branch cache in *.???? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> wrote base branch cache with 1 labels and 2 nodes (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> strip detected, evo-ext-obscache cache reset (glob)
@@ -610,6 +620,7 @@
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobshashrange --subranges --rev 'heads(all())' exited 0 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> pull (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obsdiscovery, 0/8 mismatch - 1 obshashrange queries in *.???? seconds (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-depthcache in *.???? seconds (1r) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated stablerange cache in *.???? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obshashrange in *.???? seconds (1r, 1o) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (1r, 1o) (glob)
@@ -722,9 +733,12 @@
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> --config 'extensions.strip=' strip -r 'desc("foo")' (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> saved backup bundle to $TESTTMP/client/.hg/strip-backup/45f8b879de92-94c82517-backup.hg (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> strip detected, evo-ext-obshashrange cache reset (glob)
+  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> strip detected, evo-ext-depthcache cache reset (glob)
+  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-depthcache in *.???? seconds (5r) (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obshashrange in *.???? seconds (5r, 11o) (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> strip detected, evo-ext-obscache cache reset (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obscache in *.???? seconds (5r, 11o) (glob)
+  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-depthcache in *.???? seconds (3r) (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated stablerange cache in *.???? seconds (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obshashrange in *.???? seconds (3r, 0o) (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obscache in *.???? seconds (3r, 0o) (glob)
@@ -737,6 +751,7 @@
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> log -G exited 0 after *.?? seconds (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> pull (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> obsdiscovery, 1/8 mismatch - 1 obshashrange queries in *.???? seconds (glob)
+  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-depthcache in *.???? seconds (1r) (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated stablerange cache in *.???? seconds (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> obshashcache reset - new markers affect cached ranges (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obshashrange in *.???? seconds (1r, 2o) (glob)