manifest: add fastdelta method to manifestdict
authorAugie Fackler <raf@durin42.com>
Wed, 08 Oct 2014 15:20:14 -0400
changeset 22931 48c0b101a9de
parent 22930 1acb81d10eaf
child 22932 d81792872984
manifest: add fastdelta method to manifestdict This is another step closer to alternate manifest implementations that can offer different hashing algorithms.
mercurial/manifest.py
--- a/mercurial/manifest.py	Wed Oct 08 15:21:59 2014 -0400
+++ b/mercurial/manifest.py	Wed Oct 08 15:20:14 2014 -0400
@@ -49,6 +49,49 @@
         # be sure to check the templates/ dir again (especially *-raw.tmpl)
         return ''.join("%s\0%s%s\n" % (f, hex(self[f]), flags(f)) for f in fl)
 
+    def fastdelta(self, base, changes):
+        """Given a base manifest text as an array.array and a list of changes
+        relative to that text, compute a delta that can be used by revlog.
+        """
+        delta = []
+        dstart = None
+        dend = None
+        dline = [""]
+        start = 0
+        # zero copy representation of base as a buffer
+        addbuf = util.buffer(base)
+
+        # start with a readonly loop that finds the offset of
+        # each line and creates the deltas
+        for f, todelete in changes:
+            # bs will either be the index of the item or the insert point
+            start, end = _msearch(addbuf, f, start)
+            if not todelete:
+                l = "%s\0%s%s\n" % (f, revlog.hex(self[f]), self.flags(f))
+            else:
+                if start == end:
+                    # item we want to delete was not found, error out
+                    raise AssertionError(
+                            _("failed to remove %s from manifest") % f)
+                l = ""
+            if dstart is not None and dstart <= start and dend >= start:
+                if dend < end:
+                    dend = end
+                if l:
+                    dline.append(l)
+            else:
+                if dstart is not None:
+                    delta.append([dstart, dend, "".join(dline)])
+                dstart = start
+                dend = end
+                dline = [l]
+
+        if dstart is not None:
+            delta.append([dstart, dend, "".join(dline)])
+        # apply the delta to the base, and get a delta for addrevision
+        deltatext, arraytext = _addlistdelta(base, delta)
+        return arraytext, deltatext
+
 def _msearch(m, s, lo=0, hi=None):
     '''return a tuple (start, end) that says where to find s within m.
 
@@ -173,7 +216,6 @@
             # compute a delta here using properties we know about the
             # manifest up-front, which may save time later for the
             # revlog layer.
-            addlist = self._mancache[p1][1]
 
             _checkforbidden(added)
             # combine the changed lists into one list for sorting
@@ -183,45 +225,8 @@
             # since the lists are already sorted
             work.sort()
 
-            delta = []
-            dstart = None
-            dend = None
-            dline = [""]
-            start = 0
-            # zero copy representation of addlist as a buffer
-            addbuf = util.buffer(addlist)
-
-            # start with a readonly loop that finds the offset of
-            # each line and creates the deltas
-            for f, todelete in work:
-                # bs will either be the index of the item or the insert point
-                start, end = _msearch(addbuf, f, start)
-                if not todelete:
-                    l = "%s\0%s%s\n" % (f, revlog.hex(map[f]), map.flags(f))
-                else:
-                    if start == end:
-                        # item we want to delete was not found, error out
-                        raise AssertionError(
-                                _("failed to remove %s from manifest") % f)
-                    l = ""
-                if dstart is not None and dstart <= start and dend >= start:
-                    if dend < end:
-                        dend = end
-                    if l:
-                        dline.append(l)
-                else:
-                    if dstart is not None:
-                        delta.append([dstart, dend, "".join(dline)])
-                    dstart = start
-                    dend = end
-                    dline = [l]
-
-            if dstart is not None:
-                delta.append([dstart, dend, "".join(dline)])
-            # apply the delta to the addlist, and get a delta for addrevision
-            deltatext, addlist = _addlistdelta(addlist, delta)
-            cachedelta = (self.rev(p1), deltatext)
-            arraytext = addlist
+            arraytext, deltatext = map.fastdelta(self._mancache[p1][1], work)
+            cachedelta = self.rev(p1), deltatext
             text = util.buffer(arraytext)
         else:
             # The first parent manifest isn't already loaded, so we'll