changeset 36744:33275ab5e837 stable

revlog: do not use delta for lfs revisions This is similar to what we have done for changegroups. It is needed to make sure the delta application code path can assume deltas are always against vanilla (ex. non-LFS) rawtext so the next fix becomes possible. Differential Revision: https://phab.mercurial-scm.org/D2068
author Jun Wu <quark@fb.com>
date Tue, 13 Feb 2018 11:35:32 -0800
parents d031609b3cb7
children 369aadf7a326
files mercurial/revlog.py tests/test-lfs-bundle.t tests/test-revlog-raw.py
diffstat 3 files changed, 22 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/revlog.py	Tue Feb 06 19:08:25 2018 -0800
+++ b/mercurial/revlog.py	Tue Feb 13 11:35:32 2018 -0800
@@ -407,6 +407,9 @@
         for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta):
             nominateddeltas = []
             for candidaterev in candidaterevs:
+                # no delta for rawtext-changing revs (see "candelta" for why)
+                if revlog.flags(candidaterev) & REVIDX_RAWTEXT_CHANGING_FLAGS:
+                    continue
                 candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh)
                 if revlog._isgooddeltainfo(candidatedelta, revinfo.textlen):
                     nominateddeltas.append(candidatedelta)
@@ -2090,7 +2093,14 @@
             deltacomputer = _deltacomputer(self)
 
         revinfo = _revisioninfo(node, p1, p2, btext, textlen, cachedelta, flags)
-        deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
+
+        # no delta for flag processor revision (see "candelta" for why)
+        # not calling candelta since only one revision needs test, also to
+        # avoid overhead fetching flags again.
+        if flags & REVIDX_RAWTEXT_CHANGING_FLAGS:
+            deltainfo = None
+        else:
+            deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
 
         if deltainfo is not None:
             base = deltainfo.base
--- a/tests/test-lfs-bundle.t	Tue Feb 06 19:08:25 2018 -0800
+++ b/tests/test-lfs-bundle.t	Tue Feb 13 11:35:32 2018 -0800
@@ -90,10 +90,7 @@
   ---- Applying src-normal.bundle to dst-normal ----
   OK
   ---- Applying src-normal.bundle to dst-lfs ----
-   X@2: unpacking bcc7d23fa6b7: integrity check failed on data/X.i:2
-   Y@2: unpacking 46017a6640e7: integrity check failed on data/Y.i:2
-  2 integrity errors encountered!
-  (first damaged changeset appears to be 2)
+  CRASHED
   ---- Applying src-lfs.bundle to dst-normal ----
   OK
   ---- Applying src-lfs.bundle to dst-lfs ----
--- a/tests/test-revlog-raw.py	Tue Feb 06 19:08:25 2018 -0800
+++ b/tests/test-revlog-raw.py	Tue Feb 13 11:35:32 2018 -0800
@@ -114,6 +114,8 @@
             else:
                 # suboptimal deltaparent
                 deltaparent = min(0, parentrev)
+            if not rlog.candelta(deltaparent, r):
+                deltaparent = -1
             return {'node': rlog.node(r), 'p1': pnode, 'p2': node.nullid,
                     'cs': rlog.node(rlog.linkrev(r)), 'flags': rlog.flags(r),
                     'deltabase': rlog.node(deltaparent),
@@ -151,12 +153,14 @@
     for r in rlog:
         p1 = rlog.node(r - 1)
         p2 = node.nullid
-        if r == 0:
+        if r == 0 or (rlog.flags(r) & revlog.REVIDX_EXTSTORED):
             text = rlog.revision(r, raw=True)
             cachedelta = None
         else:
-            # deltaparent is more interesting if it has the EXTSTORED flag.
-            deltaparent = max([0] + [p for p in range(r - 2) if rlog.flags(p)])
+            # deltaparent cannot have EXTSTORED flag.
+            deltaparent = max([-1] +
+                              [p for p in range(r)
+                               if rlog.flags(p) & revlog.REVIDX_EXTSTORED == 0])
             text = None
             cachedelta = (deltaparent, rlog.revdiff(deltaparent, r))
         flags = rlog.flags(r)
@@ -262,8 +266,9 @@
         result.append((text, rawtext))
 
         # Verify flags like isdelta, isext work as expected
-        if bool(rlog.deltaparent(rev) > -1) != isdelta:
-            abort('rev %d: isdelta is ineffective' % rev)
+        # isdelta can be overridden to False if this or p1 has isext set
+        if bool(rlog.deltaparent(rev) > -1) and not isdelta:
+            abort('rev %d: isdelta is unexpected' % rev)
         if bool(rlog.flags(rev)) != isext:
             abort('rev %d: isext is ineffective' % rev)
     return result