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.
--- 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)