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
--- 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 ..