perf: adds some cache key helper on the obsstore class
This will be useful to allow validating cache depending on obsstore without
parsing the whole obsstore.
--- a/hgext3rd/evolve/__init__.py Mon May 01 06:06:41 2017 +0200
+++ b/hgext3rd/evolve/__init__.py Mon May 01 08:05:45 2017 +0200
@@ -131,9 +131,10 @@
from . import (
checkheads,
debugcmd,
- obsexchange,
exthelper,
metadata,
+ obscache,
+ obsexchange,
safeguard,
utility,
)
@@ -167,6 +168,7 @@
eh.merge(obsexchange.eh)
eh.merge(checkheads.eh)
eh.merge(safeguard.eh)
+eh.merge(obscache.eh)
uisetup = eh.final_uisetup
extsetup = eh.final_extsetup
reposetup = eh.final_reposetup
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext3rd/evolve/obscache.py Mon May 01 08:05:45 2017 +0200
@@ -0,0 +1,65 @@
+# Code dedicated to an cache around obsolescence property
+#
+# This module content aims at being upstreamed.
+#
+# Copyright 2017 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from . import (
+ exthelper,
+)
+
+eh = exthelper.exthelper()
+
+try:
+ obsstorefilecache = localrepo.localrepository.obsstore
+except AttributeError:
+ # XXX hg-3.8 compat
+ #
+ # mercurial 3.8 has issue with accessing file cache property from their
+ # cache. This is fix by 36fbd72c2f39fef8ad52d7c559906c2bc388760c in core
+ # and shipped in 3.9
+ obsstorefilecache = localrepo.localrepository.__dict__['obsstore']
+
+# obsstore is a filecache so we have do to some spacial dancing
+@eh.wrapfunction(obsstorefilecache, 'func')
+def obsstorewithcache(orig, repo):
+ obsstore = orig(repo)
+
+ class cachekeyobsstore(obsstore.__class__):
+
+ _obskeysize = 200
+
+ def cachekey(self, index=None):
+ """return (current-length, cachekey)
+
+ 'current-length': is the current length of the obsstore storage file,
+ 'cachekey' is the hash of the last 200 bytes ending at 'index'.
+
+ if 'index' is unspecified, current obsstore length is used.
+ Cacheckey will be set to null id if the obstore is empty.
+
+ If the index specified is higher than the current obsstore file
+ length, cachekey will be set to None."""
+ try:
+ with self.svfs('obsstore') as obsfile:
+ obsfile.seek(0, 2)
+ obsstoresize = obsfile.tell()
+ if index is None:
+ index = obsstoresize
+ elif obsstoresize < index:
+ return obsstoresize, None
+ actualsize = min(index, self._obskeysize)
+ obsfile.seek(index - actualsize, 0)
+ keydata = obsfile.read(actualsize)
+ return obsstoresize, hashlib.sha1(keydata).digest()
+ except (OSError, IOError) as e:
+ if e.errno != errno.ENOENT:
+ raise
+ return 0, node.nullid
+
+ obsstore.__class__ = cachekeyobsstore
+
+ return obsstore