[StGit PATCH 2/2] Reuse the same temp index in a transaction

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Instead of making a new temp index every time we need one, just keep
reusing the same one. And keep track of which tree is currently stored
in it -- if we do several consecutive successful pushes, it's always
going to be the "right" tree so that we don't have to call read-tree
before each patch application.

The motivation behind this change is of course that it makes things
faster.

(The same simple test as in the previous patch -- pushing 250 patches
in a 32k-file repository, with one file-level merge necessary per push
-- went from 0.36 to 0.19 seconds per patch with this patch applied.)

Signed-off-by: Karl Hasselström <kha@xxxxxxxxxxx>

---

 stgit/lib/git.py         |   43 +++++++++++++++++++++++++++++--------------
 stgit/lib/transaction.py |   12 +++++++++++-
 2 files changed, 40 insertions(+), 15 deletions(-)


diff --git a/stgit/lib/git.py b/stgit/lib/git.py
index a38eaa5..c98e919 100644
--- a/stgit/lib/git.py
+++ b/stgit/lib/git.py
@@ -459,31 +459,46 @@ class Repository(RunWithEnv):
     def set_head_ref(self, ref, msg):
         self.run(['git', 'symbolic-ref', '-m', msg, 'HEAD', ref]).no_output()
     def simple_merge(self, base, ours, theirs):
+        index = self.temp_index()
+        try:
+            result, index_tree = self.index_merge(base, ours, theirs,
+                                                  index, None)
+        finally:
+            index.delete()
+        return result
+    def index_merge(self, base, ours, theirs, index, current):
         """Given three L{Tree}s, tries to do an in-index merge with a
-        temporary index. Returns the result L{Tree}, or None if the
-        merge failed (due to conflicts)."""
+        temporary index. Returns a pair: the result L{Tree}, or None
+        if the merge failed (due to conflicts); and the L{Tree} now
+        stored in the index.
+
+        C{index} is the L{Index} object to use for the merge.
+        C{current} is the L{Tree} object currently stored in the given
+        index. If this is the same as C{ours}, some work is saved.
+        (C{current} may be C{None}, in which case this optimization is
+        disabled.)"""
         assert isinstance(base, Tree)
         assert isinstance(ours, Tree)
         assert isinstance(theirs, Tree)
+        assert isinstance(index, Index)
+        assert current == None or isinstance(current, Tree)
 
         # Take care of the really trivial cases.
         if base == ours:
-            return theirs
+            return (theirs, current)
         if base == theirs:
-            return ours
+            return (ours, current)
         if ours == theirs:
-            return ours
+            return (ours, current)
 
-        index = self.temp_index()
-        index.read_tree(ours)
+        if current != ours:
+            index.read_tree(ours)
         try:
-            try:
-                index.apply_treediff(base, theirs)
-                return index.write_tree()
-            except MergeException:
-                return None
-        finally:
-            index.delete()
+            index.apply_treediff(base, theirs)
+            result = index.write_tree()
+            return result, result
+        except MergeException:
+            return None, ours
     def apply(self, tree, patch_text):
         """Given a L{Tree} and a patch, will either return the new L{Tree}
         that results when the patch is applied, or None if the patch
diff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py
index e47997e..b4d4b75 100644
--- a/stgit/lib/transaction.py
+++ b/stgit/lib/transaction.py
@@ -1,6 +1,8 @@
 """The L{StackTransaction} class makes it possible to make complex
 updates to an StGit stack in a safe and convenient way."""
 
+import atexit
+
 from stgit import exception, utils
 from stgit.utils import any, all
 from stgit.out import *
@@ -84,6 +86,7 @@ class StackTransaction(object):
             self.__allow_conflicts = lambda trans: allow_conflicts
         else:
             self.__allow_conflicts = allow_conflicts
+        self.__temp_index = self.temp_index_tree = None
     stack = property(lambda self: self.__stack)
     patches = property(lambda self: self.__patches)
     def __set_applied(self, val):
@@ -97,6 +100,12 @@ class StackTransaction(object):
                 or self.patches[self.applied[0]].data.parent == val)
         self.__base = val
     base = property(lambda self: self.__base, __set_base)
+    @property
+    def temp_index(self):
+        if not self.__temp_index:
+            self.__temp_index = self.__stack.repository.temp_index()
+            atexit.register(self.__temp_index.delete)
+        return self.__temp_index
     def __checkout(self, tree, iw):
         if not self.__stack.head_top_equal():
             out.error(
@@ -238,7 +247,8 @@ class StackTransaction(object):
         base = oldparent.data.tree
         ours = cd.parent.data.tree
         theirs = cd.tree
-        tree = self.__stack.repository.simple_merge(base, ours, theirs)
+        tree, self.temp_index_tree = self.__stack.repository.index_merge(
+            base, ours, theirs, self.temp_index, self.temp_index_tree)
         merge_conflict = False
         if not tree:
             if iw == None:

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux