revlog: introduce 'deltainfo' to distinguish from 'delta'
authorPaul Morelle <paul.morelle@octobus.net>
Fri, 12 Jan 2018 18:58:44 +0100
changeset 35638 edc9330acac1
parent 35637 a7d39f08bc66
child 35639 30f5f33250c8
revlog: introduce 'deltainfo' to distinguish from 'delta' A 'delta' is a binary diff between two revisions, as returned by revdiff. A 'deltainfo' is an object storing information about a delta, including the 'delta' itself. Formerly, it was stored in a 7-position tuple, which was less readable.
mercurial/revlog.py
tests/test-revlog-raw.py
--- a/mercurial/revlog.py	Fri Jan 12 18:10:03 2018 +0100
+++ b/mercurial/revlog.py	Fri Jan 12 18:58:44 2018 +0100
@@ -33,6 +33,9 @@
     wdirrev,
 )
 from .i18n import _
+from .thirdparty import (
+    attr,
+)
 from . import (
     ancestor,
     error,
@@ -251,6 +254,16 @@
     if chunk:
         yield chunk
 
+@attr.s(slots=True, frozen=True)
+class _deltainfo(object):
+    distance = attr.ib()
+    deltalen = attr.ib()
+    data = attr.ib()
+    base = attr.ib()
+    chainbase = attr.ib()
+    chainlen = attr.ib()
+    compresseddeltalen = attr.ib()
+
 # index v0:
 #  4 bytes: offset
 #  4 bytes: compressed length
@@ -1819,27 +1832,26 @@
 
         return compressor.decompress(data)
 
-    def _isgooddelta(self, d, textlen):
+    def _isgooddeltainfo(self, d, textlen):
         """Returns True if the given delta is good. Good means that it is within
         the disk span, disk size, and chain length bounds that we know to be
         performant."""
         if d is None:
             return False
 
-        # - 'dist' is the distance from the base revision -- bounding it limits
-        #   the amount of I/O we need to do.
-        # - 'compresseddeltalen' is the sum of the total size of deltas we need
-        #   to apply -- bounding it limits the amount of CPU we consume.
-        dist, l, data, base, chainbase, chainlen, compresseddeltalen = d
+        # - 'd.distance' is the distance from the base revision -- bounding it
+        #   limits the amount of I/O we need to do.
+        # - 'd.compresseddeltalen' is the sum of the total size of deltas we
+        #   need to apply -- bounding it limits the amount of CPU we consume.
 
         defaultmax = textlen * 4
         maxdist = self._maxdeltachainspan
         if not maxdist:
-            maxdist = dist # ensure the conditional pass
+            maxdist = d.distance # ensure the conditional pass
         maxdist = max(maxdist, defaultmax)
-        if (dist > maxdist or l > textlen or
-            compresseddeltalen > textlen * 2 or
-            (self._maxchainlen and chainlen > self._maxchainlen)):
+        if (d.distance > maxdist or d.deltalen > textlen or
+            d.compresseddeltalen > textlen * 2 or
+            (self._maxchainlen and d.chainlen > self._maxchainlen)):
             return False
 
         return True
@@ -1923,7 +1935,7 @@
                 raise
         return btext[0]
 
-    def _builddelta(self, node, rev, p1, p2, btext, cachedelta, fh, flags):
+    def _builddeltainfo(self, node, rev, p1, p2, btext, cachedelta, fh, flags):
         # can we use the cached delta?
         if cachedelta and cachedelta[0] == rev:
             delta = cachedelta[1]
@@ -1949,8 +1961,8 @@
         chainlen, compresseddeltalen = self._chaininfo(rev)
         chainlen += 1
         compresseddeltalen += deltalen
-        return (dist, deltalen, (header, data), base,
-                chainbase, chainlen, compresseddeltalen)
+        return _deltainfo(dist, deltalen, (header, data), base,
+                         chainbase, chainlen, compresseddeltalen)
 
     def _addrevision(self, node, rawtext, transaction, link, p1, p2, flags,
                      cachedelta, ifh, dfh, alwayscache=False):
@@ -1981,7 +1993,7 @@
         curr = len(self)
         prev = curr - 1
         offset = self.end(prev)
-        delta = None
+        deltainfo = None
         p1r, p2r = self.rev(p1), self.rev(p2)
 
         # full versions are inserted when the needed deltas
@@ -1995,17 +2007,20 @@
         for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta):
             nominateddeltas = []
             for candidaterev in candidaterevs:
-                candidatedelta = self._builddelta(node, candidaterev, p1, p2,
-                                                  btext, cachedelta, fh,
-                                                  flags)
-                if self._isgooddelta(candidatedelta, textlen):
+                candidatedelta = self._builddeltainfo(node, candidaterev, p1,
+                                                      p2, btext, cachedelta,
+                                                      fh, flags)
+                if self._isgooddeltainfo(candidatedelta, textlen):
                     nominateddeltas.append(candidatedelta)
             if nominateddeltas:
-                delta = min(nominateddeltas, key=lambda x: x[1])
+                deltainfo = min(nominateddeltas, key=lambda x: x.deltalen)
                 break
 
-        if delta is not None:
-            dist, l, data, base, chainbase, chainlen, compresseddeltalen = delta
+        if deltainfo is not None:
+            base = deltainfo.base
+            chainbase = deltainfo.chainbase
+            data = deltainfo.data
+            l = deltainfo.deltalen
         else:
             rawtext = self._buildtext(node, p1, p2, btext, cachedelta, fh,
                                       flags)
--- a/tests/test-revlog-raw.py	Fri Jan 12 18:10:03 2018 +0100
+++ b/tests/test-revlog-raw.py	Fri Jan 12 18:58:44 2018 +0100
@@ -20,7 +20,7 @@
 
 # The test wants to control whether to use delta explicitly, based on
 # "storedeltachains".
-revlog.revlog._isgooddelta = lambda self, d, textlen: self.storedeltachains
+revlog.revlog._isgooddeltainfo = lambda self, d, textlen: self.storedeltachains
 
 def abort(msg):
     print('abort: %s' % msg)