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.
| pulkit |
| hg-reviewers |
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.
| Automatic diff as part of commit; lint not applicable. |
| Automatic diff as part of commit; unit tests not applicable. |
โ
refresh by Heptapod after a successful CI run (๐ ๐)
โ This patch is intended for stable โ

โ
refresh by Heptapod after a successful CI run (๐ ๐)
โ This patch is intended for stable โ

| Path | Packages | |||
|---|---|---|---|---|
| M | mercurial/filelog.py (4 lines) | |||
| M | mercurial/revlogutils/rewrite.py (84 lines) | |||
| A | M | (bin) | tests/bundles/issue6528.hg-v1 | |
| A | M | (bin) | tests/bundles/issue6528.hg-v2 | |
| M | tests/test-issue6528.t (93 lines) |
| ) | ) | ||||
| from .interfaces import ( | from .interfaces import ( | ||||
| repository, | repository, | ||||
| util as interfaceutil, | util as interfaceutil, | ||||
| ) | ) | ||||
| from .utils import storageutil | from .utils import storageutil | ||||
| from .revlogutils import ( | from .revlogutils import ( | ||||
| constants as revlog_constants, | constants as revlog_constants, | ||||
| rewrite, | |||||
| ) | ) | ||||
| @interfaceutil.implementer(repository.ifilestorage) | @interfaceutil.implementer(repository.ifilestorage) | ||||
| class filelog(object): | class filelog(object): | ||||
| def __init__(self, opener, path): | def __init__(self, opener, path): | ||||
| self._revlog = revlog.revlog( | self._revlog = revlog.revlog( | ||||
| opener, | opener, | ||||
| raise error.Abort( | raise error.Abort( | ||||
| _( | _( | ||||
| b'revlog storage does not support missing ' | b'revlog storage does not support missing ' | ||||
| b'parents write mode' | b'parents write mode' | ||||
| ) | ) | ||||
| ) | ) | ||||
| with self._revlog._writing(transaction): | with self._revlog._writing(transaction): | ||||
| deltas = rewrite.filter_delta_issue6528(self._revlog, deltas) | |||||
| return self._revlog.addgroup( | return self._revlog.addgroup( | ||||
| deltas, | deltas, | ||||
| linkmapper, | linkmapper, | ||||
| transaction, | transaction, | ||||
| addrevisioncb=addrevisioncb, | addrevisioncb=addrevisioncb, | ||||
| duplicaterevisioncb=duplicaterevisioncb, | duplicaterevisioncb=duplicaterevisioncb, | ||||
| ) | ) | ||||
| ENTRY_DELTA_BASE, | ENTRY_DELTA_BASE, | ||||
| ENTRY_LINK_REV, | ENTRY_LINK_REV, | ||||
| ENTRY_NODE_ID, | ENTRY_NODE_ID, | ||||
| ENTRY_PARENT_1, | ENTRY_PARENT_1, | ||||
| ENTRY_PARENT_2, | ENTRY_PARENT_2, | ||||
| ENTRY_SIDEDATA_COMPRESSED_LENGTH, | ENTRY_SIDEDATA_COMPRESSED_LENGTH, | ||||
| ENTRY_SIDEDATA_COMPRESSION_MODE, | ENTRY_SIDEDATA_COMPRESSION_MODE, | ||||
| ENTRY_SIDEDATA_OFFSET, | ENTRY_SIDEDATA_OFFSET, | ||||
| REVIDX_ISCENSORED, | |||||
| REVLOGV0, | REVLOGV0, | ||||
| REVLOGV1, | REVLOGV1, | ||||
| ) | ) | ||||
| from ..i18n import _ | from ..i18n import _ | ||||
| from .. import ( | from .. import ( | ||||
| error, | error, | ||||
| mdiff, | |||||
| pycompat, | pycompat, | ||||
| revlogutils, | revlogutils, | ||||
| util, | util, | ||||
| ) | ) | ||||
| from ..utils import ( | from ..utils import ( | ||||
| storageutil, | storageutil, | ||||
| ) | ) | ||||
| from . import ( | from . import ( | ||||
| if not to_fix: | if not to_fix: | ||||
| msg = _(b"no affected revisions were found for '%s'\n") | msg = _(b"no affected revisions were found for '%s'\n") | ||||
| ui.write(msg % filename) | ui.write(msg % filename) | ||||
| continue | continue | ||||
| if not dry_run: | if not dry_run: | ||||
| _reorder_filelog_parents(repo, fl, sorted(to_fix)) | _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( | def repair_issue6528( | ||||
| ui, repo, dry_run=False, to_report=None, from_report=None, paranoid=False | ui, repo, dry_run=False, to_report=None, from_report=None, paranoid=False | ||||
| ): | ): | ||||
| from .. import store # avoid cycle | from .. import store # avoid cycle | ||||
| @contextlib.contextmanager | @contextlib.contextmanager | ||||
| def context(): | def context(): | ||||
| if dry_run or to_report: # No need for locking | if dry_run or to_report: # No need for locking | ||||
| $ hg debugrevlogindex D.txt | $ hg debugrevlogindex D.txt | ||||
| rev linkrev nodeid p1 p2 | rev linkrev nodeid p1 p2 | ||||
| 0 6 2a8d3833f2fb 000000000000 000000000000 | 0 6 2a8d3833f2fb 000000000000 000000000000 | ||||
| 1 7 2a80419dfc31 000000000000 2a8d3833f2fb | 1 7 2a80419dfc31 000000000000 2a8d3833f2fb | ||||
| 2 8 65aecc89bb5d 2a80419dfc31 000000000000 | 2 8 65aecc89bb5d 2a80419dfc31 000000000000 | ||||
| $ hg debug-repair-issue6528 | $ hg debug-repair-issue6528 | ||||
| no affected revisions were found | no affected revisions were found | ||||
| $ hg st | $ 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 .. | |||||