Commits

Patrick Mézard committed bd9c292

editor: add a small changectx cache

Reverts including a lot of files create many actions like:

R bar (from trunk/bar:4343)

For each of these files, an open_file() call is made and the parent
mercurial revision is loaded to detect copies in issamefile(). This
results in a big slowdown, easily reduced by caching the changectx.

Comments (0)

Files changed (2)

hgsubversion/editor.py

         self.path = path
         self.copypath = copypath
 
-    def resolve(self, repo, ctx=None):
+    def resolve(self, getctxfn, ctx=None):
         if ctx is None:
-            ctx = repo[self.node]
+            ctx = getctxfn(self.node)
         fctx = ctx[self.path]
         data = fctx.data()
         flags = fctx.flags()
         # A mapping of file paths to batons
         self._openpaths = {}
         self._deleted = set()
+        self._getctx = util.lrucachefunc(self.repo.changectx, 3)
 
     def _openfile(self, path, data, isexec, islink, copypath, create=False):
         if path in self._openpaths:
             ha = self.meta.get_parent_revision(self.current.rev.revnum, branch)
             if ha == revlog.nullid:
                 return
-            ctx = self.repo.changectx(ha)
+            ctx = self._getctx(ha)
             if br_path not in ctx:
                 br_path2 = ''
                 if br_path != '':
 
         if path in self._svncopies:
             copy = self._svncopies.pop(path)
-            base, isexec, islink, copypath = copy.resolve(self.repo)
+            base, isexec, islink, copypath = copy.resolve(self._getctx)
             return self._openfile(path, base, isexec, islink, copypath)
 
         if not self.meta.is_path_valid(path):
         # replacing branch as parent, but svn delta editor provides delta
         # agains replaced branch.
         parent = self.meta.get_parent_revision(baserev + 1, branch, True)
-        ctx = self.repo[parent]
+        ctx = self._getctx(parent)
         if fpath not in ctx:
             self.current.addmissing(path)
             return None
         # agains replaced branch.
         ha = self.meta.get_parent_revision(copyfrom_revision + 1,
                                            from_branch, True)
-        ctx = self.repo.changectx(ha)
+        ctx = self._getctx(ha)
         if from_file not in ctx:
             self.current.addmissing(path)
             return None
             parentid = self.meta.get_parent_revision(
                 self.current.rev.revnum, branch)
             if parentid != revlog.nullid:
-                parentctx = self.repo.changectx(parentid)
+                parentctx = self._getctx(parentid)
                 if util.issamefile(parentctx, ctx, from_file):
                     copypath = from_file
         return self._openfile(path, fctx.data(), 'x' in flags, 'l' in flags,
         if new_hash == node.nullid:
             self.current.addmissing('%s/' % path)
             return path
-        fromctx = self.repo.changectx(new_hash)
+        fromctx = self._getctx(new_hash)
         if frompath != '/' and frompath != '':
             frompath = '%s/' % frompath
         else:
             parentid = self.meta.get_parent_revision(
                     self.current.rev.revnum, branch)
             if parentid != revlog.nullid:
-                parentctx = self.repo.changectx(parentid)
+                parentctx = self._getctx(parentid)
                 for k, v in copies.iteritems():
                     if util.issamefile(parentctx, fromctx, v):
                         svncopies[k].copypath = v
         for path, copy in self._svncopies.iteritems():
             nodes.setdefault(copy.node, []).append((path, copy))
         for node, copies in nodes.iteritems():
-            ctx = self.repo[node]
             for path, copy in copies:
-                data, isexec, islink, copied = copy.resolve(self.repo, ctx)
+                data, isexec, islink, copied = copy.resolve(self._getctx)
                 self.current.set(path, data, isexec, islink, copied)
         self._svncopies.clear()
 

hgsubversion/util.py

 import re
 import os
 import urllib
+from collections import deque
 
 from mercurial import cmdutil
 from mercurial import error
     else:
         size = -1
     return size
+
+# Copy-paste from mercurial.util to avoid having to deal with backward
+# compatibility, plus the cache size is configurable.
+def lrucachefunc(func, size):
+    '''cache most recent results of function calls'''
+    cache = {}
+    order = deque()
+    if func.func_code.co_argcount == 1:
+        def f(arg):
+            if arg not in cache:
+                if len(cache) > size:
+                    del cache[order.popleft()]
+                cache[arg] = func(arg)
+            else:
+                order.remove(arg)
+            order.append(arg)
+            return cache[arg]
+    else:
+        def f(*args):
+            if args not in cache:
+                if len(cache) > size:
+                    del cache[order.popleft()]
+                cache[args] = func(*args)
+            else:
+                order.remove(args)
+            order.append(args)
+            return cache[args]
+
+    return f