perf: adds some cache key helper on the obsstore class
authorPierre-Yves David <pierre-yves.david@ens-lyon.org>
Mon, 01 May 2017 08:05:45 +0200
changeset 2294 75996eafab43
parent 2293 1659b42c28c2
child 2295 017b971ba28f
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.
hgext3rd/evolve/__init__.py
hgext3rd/evolve/obscache.py
--- 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