# HG changeset patch # User Pierre-Yves David # Date 1513799170 -3600 # Node ID 7d4c157b65190b1f1565b8a8594156a34302efde # Parent 846bdf081871baa3a7a7d92047773f1e608ba6c1 stablerange: add a new 'firstmerge' cache This cache store the first merge ancestors of a changesets. This is useful to avoid iteration over the changelog when building stablerange. diff -r 846bdf081871 -r 7d4c157b6519 hgext3rd/evolve/depthcache.py --- a/hgext3rd/evolve/depthcache.py Wed Dec 20 20:17:11 2017 +0100 +++ b/hgext3rd/evolve/depthcache.py Wed Dec 20 20:46:10 2017 +0100 @@ -71,7 +71,7 @@ @localrepo.unfilteredmethod def destroyed(self): - if 'obsstore' in vars(self): + if 'depthcache' in vars(self): self.depthcache.clear() super(depthcacherepo, self).destroyed() @@ -97,19 +97,13 @@ 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) + tr.addpostclose('warmcache-00depthcache', _warmcache) return tr repo.__class__ = depthcacherepo diff -r 846bdf081871 -r 7d4c157b6519 hgext3rd/evolve/firstmergecache.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext3rd/evolve/firstmergecache.py Wed Dec 20 20:46:10 2017 +0100 @@ -0,0 +1,165 @@ +from __future__ import absolute_import + +import array +import weakref + +from mercurial import ( + localrepo, + node as nodemod, + util, +) + +from . import ( + error, + exthelper, + genericcaches, + utility, +) + +filterparents = utility.filterparents + +eh = exthelper.exthelper() + +@eh.reposetup +def setupcache(ui, repo): + + class firstmergecacherepo(repo.__class__): + + @localrepo.unfilteredpropertycache + def firstmergecache(self): + cache = firstmergecache() + cache.update(self) + return cache + + @localrepo.unfilteredmethod + def destroyed(self): + if 'firstmergecach' in vars(self): + self.firstmergecache.clear() + super(firstmergecacherepo, 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.firstmergecache.update(repo) + self.firstmergecache.save(repo) + super(firstmergecacherepo, self).updatecaches(tr) + + else: + def transaction(self, *args, **kwargs): + tr = super(firstmergecacherepo, self).transaction(*args, **kwargs) + reporef = weakref.ref(self) + + def _warmcache(tr): + repo = reporef() + if repo is None: + return + repo = repo.unfiltered() + self.firstmergecache.update(repo) + self.firstmergecache.save(repo) + + if (repo.ui.configbool('experimental', 'obshashrange', + False) + and repo.ui.configbool('experimental', + 'obshashrange.warm-cache', + True)): + tr.addpostclose('warmcache-01-firstparentcache', _warmcache) + return tr + + repo.__class__ = firstmergecacherepo + +class firstmergecache(genericcaches.changelogsourcebase): + + _filepath = 'evoext-firstmerge-00' + _cachename = 'evo-ext-firstmerge' + + def __init__(self): + super(firstmergecache, self).__init__() + self._data = array.array('l') + + def get(self, rev): + if len(self._data) <= rev: + raise error.ProgrammingError('firstmergecache 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 + total = len(data) + + def progress(pos, rev): + repo.ui.progress('updating firstmerge cache', + pos, 'rev %s' % rev, unit='revision', total=total) + progress(0, '') + for idx, rev in enumerate(data, 1): + assert rev == len(self._data), (rev, len(self._data)) + self._data.append(self._firstmerge(cl, rev)) + if not (idx % 10000): # progress as a too high performance impact + progress(idx, rev) + progress(None, '') + + def _firstmerge(self, changelog, rev): + cl = changelog + ps = filterparents(cl.parentrevs(rev)) + if not ps: + return nodemod.nullrev + elif len(ps) == 1: + # linear commit case + return self.get(ps[0]) + else: + return rev + + # 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(firstmergecache, 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 + + if util.safehasattr(repo, 'cachevfs'): + data = repo.cachevfs.tryread(self._filepath) + else: + data = repo.vfs.tryread('cache/' + 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 + + if util.safehasattr(repo, 'cachevfs'): + cachefile = repo.cachevfs(self._filepath, 'w', atomictemp=True) + else: + cachefile = repo.vfs('cache/' + self._filepath, 'w', atomictemp=True) + headerdata = self._serializecachekey() + cachefile.write(headerdata) + cachefile.write(self._data.tostring()) + cachefile.close() diff -r 846bdf081871 -r 7d4c157b6519 hgext3rd/evolve/stablerange.py --- a/hgext3rd/evolve/stablerange.py Wed Dec 20 20:17:11 2017 +0100 +++ b/hgext3rd/evolve/stablerange.py Wed Dec 20 20:46:10 2017 +0100 @@ -25,8 +25,9 @@ from mercurial.i18n import _ from . import ( + exthelper, + firstmergecache, stablesort, - exthelper, utility, ) @@ -34,6 +35,7 @@ eh = exthelper.exthelper() eh.merge(stablesort.eh) +eh.merge(firstmergecache.eh) # prior to hg-4.2 there are not util.timer if util.safehasattr(util, 'timer'): diff -r 846bdf081871 -r 7d4c157b6519 tests/test-discovery-obshashrange.t --- a/tests/test-discovery-obshashrange.t Wed Dec 20 20:17:11 2017 +0100 +++ b/tests/test-discovery-obshashrange.t Wed Dec 20 20:46:10 2017 +0100 @@ -38,6 +38,8 @@ * @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 (*)> strip detected, evo-ext-firstmerge cache reset (glob) + * @0000000000000000000000000000000000000000 (*)> updated evo-ext-firstmerge in *.???? seconds (8r) (glob) * @0000000000000000000000000000000000000000 (*)> updated served branch cache in *.???? seconds (glob) * @0000000000000000000000000000000000000000 (*)> wrote served branch cache with 1 labels and 1 nodes (glob) * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obscache in *.???? seconds (8r, 0o) (glob) @@ -161,6 +163,8 @@ * @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 (*)> strip detected, evo-ext-firstmerge cache reset (glob) + * @0000000000000000000000000000000000000000 (*)> updated evo-ext-firstmerge in *.???? seconds (5r) (glob) * @0000000000000000000000000000000000000000 (*)> updated base branch cache in *.???? seconds (glob) * @0000000000000000000000000000000000000000 (*)> wrote base branch cache with 1 labels and 1 nodes (glob) * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obscache in *.???? seconds (5r, 3o) (glob) @@ -243,6 +247,7 @@ * @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 (*)> updated evo-ext-firstmerge in *.???? seconds (1r) (glob) * @0000000000000000000000000000000000000000 (*)> obscache is out of date, falling back to slower obsstore version (glob) * @0000000000000000000000000000000000000000 (*)> updated served branch cache in *.???? seconds (glob) * @0000000000000000000000000000000000000000 (*)> wrote served branch cache with 1 labels and 2 nodes (glob) @@ -305,6 +310,7 @@ * @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 (*)> updated evo-ext-firstmerge in *.???? seconds (1r) (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obscache is out of date, falling back to slower obsstore version (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated served branch cache in *.???? seconds (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> wrote served branch cache with 1 labels and 1 nodes (glob) @@ -422,6 +428,7 @@ * @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) + * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-firstmerge in *.???? seconds (2r) (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated served branch cache in *.???? seconds (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> wrote served branch cache with 1 labels and 2 nodes (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (2r, 3o) (glob) @@ -568,12 +575,15 @@ * @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-firstmerge in *.???? seconds (1r) (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated served branch cache in *.???? seconds (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> wrote served branch cache with 1 labels and 2 nodes (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (1r, 1o) (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> 1 incoming changes - new heads: 4de32a90b66c (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> pull exited 0 after *.?? seconds (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> rollback (glob) + * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> strip detected, evo-ext-firstmerge cache reset (glob) + * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-firstmerge in *.???? seconds (8r) (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) @@ -623,6 +633,7 @@ * @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-firstmerge in *.???? seconds (1r) (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (1r, 1o) (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> 1 incoming changes - new heads: 4de32a90b66c (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> pull exited 0 after *.?? seconds (glob) @@ -736,11 +747,14 @@ * @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-firstmerge cache reset (glob) + * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-firstmerge in *.???? seconds (5r) (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-firstmerge in *.???? seconds (3r) (glob) * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obscache in *.???? seconds (3r, 0o) (glob) * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated base branch cache in *.???? seconds (glob) * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> wrote base branch cache with 1 labels and 1 nodes (glob) @@ -755,6 +769,7 @@ * @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) + * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-firstmerge in *.???? seconds (1r) (glob) * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated base branch cache in *.???? seconds (glob) * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> wrote base branch cache with 1 labels and 2 nodes (glob) * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obscache in *.???? seconds (1r, 2o) (glob)