diff mercurial/util.py @ 34358:c41444a39de2

config: use copy-on-write to improve copy performance Previously, chg's `verify` call could take 30+ms loading and checking new config files. With one socket redirection, that adds up to around 70ms, which is a lot for fast commands (ex. `bookmark --hidden`). When investigating closer, A lot of time was spent on actually spent on ui copying, which is mainly about `config.config` and `dict` copying. This patch makes that 20x faster by adopting copy-on-write. The copy-on-write is performed at config section level. Before: In [1]: %timeit ui.copy() 100 loops, best of 3: 2.32 ms per loop After: In [1]: %timeit ui.copy() 10000 loops, best of 3: 128 us per loop 2ms may look not that bad, but it adds up pretty quickly with multiple calls. A typical chg run may call it 4 times, which is about 10ms. Differential Revision: https://phab.mercurial-scm.org/D808
author Jun Wu <quark@fb.com>
date Wed, 27 Sep 2017 18:07:48 -0700
parents 3bb2a9f25fe9
children f435097d13c9
line wrap: on
line diff
--- a/mercurial/util.py	Sat Sep 30 18:19:14 2017 +0530
+++ b/mercurial/util.py	Wed Sep 27 18:07:48 2017 -0700
@@ -588,6 +588,24 @@
 
     return f
 
+class cow(object):
+    """helper class to make copy-on-write easier
+
+    Call preparewrite before doing any writes.
+    """
+
+    def preparewrite(self):
+        """call this before writes, return self or a copied new object"""
+        if getattr(self, '_copied', 0):
+            self._copied -= 1
+            return self.__class__(self)
+        return self
+
+    def copy(self):
+        """always do a cheap copy"""
+        self._copied = getattr(self, '_copied', 0) + 1
+        return self
+
 class sortdict(collections.OrderedDict):
     '''a simple sorted dictionary
 
@@ -613,6 +631,38 @@
             for k, v in src:
                 self[k] = v
 
+class cowdict(cow, dict):
+    """copy-on-write dict
+
+    Be sure to call d = d.preparewrite() before writing to d.
+
+    >>> a = cowdict()
+    >>> a is a.preparewrite()
+    True
+    >>> b = a.copy()
+    >>> b is a
+    True
+    >>> c = b.copy()
+    >>> c is a
+    True
+    >>> a = a.preparewrite()
+    >>> b is a
+    False
+    >>> a is a.preparewrite()
+    True
+    >>> c = c.preparewrite()
+    >>> b is c
+    False
+    >>> b is b.preparewrite()
+    True
+    """
+
+class cowsortdict(cow, sortdict):
+    """copy-on-write sortdict
+
+    Be sure to call d = d.preparewrite() before writing to d.
+    """
+
 class transactional(object):
     """Base class for making a transactional type into a context manager."""
     __metaclass__ = abc.ABCMeta