issue6528: also filter delta on the fly when applying a changegroup stable
authorPierre-Yves David <pierre-yves.david@octobus.net>
Sat, 07 Aug 2021 14:12:28 +0200
branchstable
changeset 47821 c30ca163b45e
parent 47820 436932c2cfaa
child 47822 2813d406b036
issue6528: also filter delta on the fly when applying a changegroup This ensure that corrupted clone does not spread corruption to "fixed" version. This might come at a performance cost, we will had a config option to control this behavior in the next changesets. Differential Revision: https://phab.mercurial-scm.org/D11270
mercurial/filelog.py
mercurial/revlogutils/rewrite.py
tests/bundles/issue6528.hg-v1
tests/bundles/issue6528.hg-v2
tests/test-issue6528.t
--- a/mercurial/filelog.py	Sat Aug 07 14:13:53 2021 +0200
+++ b/mercurial/filelog.py	Sat Aug 07 14:12:28 2021 +0200
@@ -20,6 +20,7 @@
 from .utils import storageutil
 from .revlogutils import (
     constants as revlog_constants,
+    rewrite,
 )
 
 
@@ -158,6 +159,9 @@
             )
 
         with self._revlog._writing(transaction):
+
+            deltas = rewrite.filter_delta_issue6528(self._revlog, deltas)
+
             return self._revlog.addgroup(
                 deltas,
                 linkmapper,
--- a/mercurial/revlogutils/rewrite.py	Sat Aug 07 14:13:53 2021 +0200
+++ b/mercurial/revlogutils/rewrite.py	Sat Aug 07 14:12:28 2021 +0200
@@ -29,6 +29,7 @@
     ENTRY_SIDEDATA_COMPRESSED_LENGTH,
     ENTRY_SIDEDATA_COMPRESSION_MODE,
     ENTRY_SIDEDATA_OFFSET,
+    REVIDX_ISCENSORED,
     REVLOGV0,
     REVLOGV1,
 )
@@ -36,6 +37,7 @@
 
 from .. import (
     error,
+    mdiff,
     pycompat,
     revlogutils,
     util,
@@ -719,6 +721,88 @@
                 _reorder_filelog_parents(repo, fl, sorted(to_fix))
 
 
+def filter_delta_issue6528(revlog, deltas_iter):
+    """filter incomind deltas to repaire issue 6528 on the fly"""
+    metadata_cache = {}
+
+    deltacomputer = deltas.deltacomputer(revlog)
+
+    for rev, d in enumerate(deltas_iter, len(revlog)):
+        (
+            node,
+            p1_node,
+            p2_node,
+            linknode,
+            deltabase,
+            delta,
+            flags,
+            sidedata,
+        ) = d
+
+        if not revlog.index.has_node(deltabase):
+            raise error.LookupError(
+                deltabase, revlog.radix, _(b'unknown parent')
+            )
+        base_rev = revlog.rev(deltabase)
+        if not revlog.index.has_node(p1_node):
+            raise error.LookupError(p1_node, revlog.radix, _(b'unknown parent'))
+        p1_rev = revlog.rev(p1_node)
+        if not revlog.index.has_node(p2_node):
+            raise error.LookupError(p2_node, revlog.radix, _(b'unknown parent'))
+        p2_rev = revlog.rev(p2_node)
+
+        is_censored = lambda: bool(flags & REVIDX_ISCENSORED)
+        delta_base = lambda: revlog.rev(delta_base)
+        delta_base = lambda: base_rev
+        parent_revs = lambda: (p1_rev, p2_rev)
+
+        def full_text():
+            # note: being able to reuse the full text computation in the
+            # underlying addrevision would be useful however this is a bit too
+            # intrusive the for the "quick" issue6528 we are writing before the
+            # 5.8 release
+            textlen = mdiff.patchedsize(revlog.size(base_rev), delta)
+
+            revinfo = revlogutils.revisioninfo(
+                node,
+                p1_node,
+                p2_node,
+                [None],
+                textlen,
+                (base_rev, delta),
+                flags,
+            )
+            # cached by the global "writing" context
+            assert revlog._writinghandles is not None
+            if revlog._inline:
+                fh = revlog._writinghandles[0]
+            else:
+                fh = revlog._writinghandles[1]
+            return deltacomputer.buildtext(revinfo, fh)
+
+        is_affected = _is_revision_affected_fast_inner(
+            is_censored,
+            delta_base,
+            lambda: delta,
+            full_text,
+            parent_revs,
+            rev,
+            metadata_cache,
+        )
+        if is_affected:
+            d = (
+                node,
+                p2_node,
+                p1_node,
+                linknode,
+                deltabase,
+                delta,
+                flags,
+                sidedata,
+            )
+        yield d
+
+
 def repair_issue6528(
     ui, repo, dry_run=False, to_report=None, from_report=None, paranoid=False
 ):
Binary file tests/bundles/issue6528.hg-v1 has changed
Binary file tests/bundles/issue6528.hg-v2 has changed
--- a/tests/test-issue6528.t	Sat Aug 07 14:13:53 2021 +0200
+++ b/tests/test-issue6528.t	Sat Aug 07 14:12:28 2021 +0200
@@ -431,3 +431,96 @@
   $ hg debug-repair-issue6528
   no affected revisions were found
   $ hg st
+
+  $ cd ..
+
+Applying a bad bundle should fix it on the fly
+----------------------------------------------
+
+from a v1 bundle
+~~~~~~~~~~~~~~~~
+
+  $ hg debugbundle  --spec "$TESTDIR"/bundles/issue6528.hg-v1
+  bzip2-v1
+
+  $ hg init unbundle-v1
+  $ cd unbundle-v1
+
+  $ hg unbundle "$TESTDIR"/bundles/issue6528.hg-v1
+  adding changesets
+  adding manifests
+  adding file changes
+  added 8 changesets with 12 changes to 4 files
+  new changesets f5a5a568022f:3beabb508514 (8 drafts)
+  (run 'hg update' to get a working copy)
+
+Check that revision were fixed on the fly
+
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 000000000000 05b806ebe5ea
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 000000000000 216a5fe8b8ed
+
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 000000000000 2a8d3833f2fb
+
+That we don't see the symptoms of the bug
+
+  $ hg up -- -1
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg status
+
+And that the repair command does not find anything to fix
+
+  $ hg debug-repair-issue6528
+  no affected revisions were found
+
+  $ cd ..
+
+from a v2 bundle
+~~~~~~~~~~~~~~~~
+
+  $ hg debugbundle --spec "$TESTDIR"/bundles/issue6528.hg-v2
+  bzip2-v2
+
+  $ hg init unbundle-v2
+  $ cd unbundle-v2
+
+  $ hg unbundle "$TESTDIR"/bundles/issue6528.hg-v2
+  adding changesets
+  adding manifests
+  adding file changes
+  added 8 changesets with 12 changes to 4 files
+  new changesets f5a5a568022f:3beabb508514 (8 drafts)
+  (run 'hg update' to get a working copy)
+
+Check that revision were fixed on the fly
+
+  $ hg debugrevlogindex b.txt
+     rev linkrev nodeid       p1           p2
+       0       2 05b806ebe5ea 000000000000 000000000000
+       1       3 a58b36ad6b65 000000000000 05b806ebe5ea
+       2       6 216a5fe8b8ed 000000000000 000000000000
+       3       7 ea4f2f2463cc 000000000000 216a5fe8b8ed
+
+  $ hg debugrevlogindex D.txt
+     rev linkrev nodeid       p1           p2
+       0       6 2a8d3833f2fb 000000000000 000000000000
+       1       7 2a80419dfc31 000000000000 2a8d3833f2fb
+
+That we don't see the symptoms of the bug
+
+  $ hg up -- -1
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg status
+
+And that the repair command does not find anything to fix
+
+  $ hg debug-repair-issue6528
+  no affected revisions were found
+
+  $ cd ..