diff --git a/mercurial/filelog.py b/mercurial/filelog.py --- a/mercurial/filelog.py +++ b/mercurial/filelog.py @@ -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, diff --git a/mercurial/revlogutils/rewrite.py b/mercurial/revlogutils/rewrite.py --- a/mercurial/revlogutils/rewrite.py +++ b/mercurial/revlogutils/rewrite.py @@ -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 ): diff --git a/tests/bundles/issue6528.hg-v1 b/tests/bundles/issue6528.hg-v1 new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@