diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py --- a/mercurial/debugcommands.py +++ b/mercurial/debugcommands.py @@ -1470,6 +1470,12 @@ _(b'repair revisions listed in this report file'), _(b'FILE'), ), + ( + b'', + b'paranoid', + False, + _(b'check that both detection methods do the same thing'), + ), ] + cmdutil.dryrunopts, ) @@ -1491,6 +1497,11 @@ Note that this does *not* mean that this repairs future affected revisions, that needs a separate fix at the exchange level that hasn't been written yet (as of 5.9rc0). + + There is a `--paranoid` flag to test that the fast implementation is correct + by checking it against the slow implementation. Since this matter is quite + urgent and testing every edge-case is probably quite costly, we use this + method to test on large repositories as a fuzzing method of sorts. """ cmdutil.check_incompatible_arguments( opts, 'to_report', ['from_report', 'dry_run'] @@ -1498,6 +1509,7 @@ dry_run = opts.get('dry_run') to_report = opts.get('to_report') from_report = opts.get('from_report') + paranoid = opts.get('paranoid') # TODO maybe add filelog pattern and revision pattern parameters to help # narrow down the search for users that know what they're looking for? @@ -1506,7 +1518,12 @@ raise error.Abort(_(msg)) rewrite.repair_issue6528( - ui, repo, dry_run=dry_run, to_report=to_report, from_report=from_report + ui, + repo, + dry_run=dry_run, + to_report=to_report, + from_report=from_report, + paranoid=paranoid, ) diff --git a/mercurial/revlogutils/rewrite.py b/mercurial/revlogutils/rewrite.py --- a/mercurial/revlogutils/rewrite.py +++ b/mercurial/revlogutils/rewrite.py @@ -673,7 +673,9 @@ _reorder_filelog_parents(repo, fl, sorted(to_fix)) -def repair_issue6528(ui, repo, dry_run=False, to_report=None, from_report=None): +def repair_issue6528( + ui, repo, dry_run=False, to_report=None, from_report=None, paranoid=False +): from .. import store # avoid cycle @contextlib.contextmanager @@ -720,6 +722,12 @@ affected = _is_revision_affected_fast( repo, fl, filerev, metadata_cache ) + if paranoid: + slow = _is_revision_affected(fl, filerev) + if slow != affected: + msg = _(b"paranoid check failed for '%s' at node %s") + node = binascii.hexlify(fl.node(filerev)) + raise error.Abort(msg % (filename, node)) if affected: msg = b"found affected revision %d for filelog '%s'\n" ui.warn(msg % (filerev, path)) diff --git a/tests/test-completion.t b/tests/test-completion.t --- a/tests/test-completion.t +++ b/tests/test-completion.t @@ -267,7 +267,7 @@ config: untrusted, exp-all-known, edit, local, source, shared, non-shared, global, template continue: dry-run copy: forget, after, at-rev, force, include, exclude, dry-run - debug-repair-issue6528: to-report, from-report, dry-run + debug-repair-issue6528: to-report, from-report, paranoid, dry-run debugancestor: debugantivirusrunning: debugapplystreamclonebundle: diff --git a/tests/test-issue6528.t b/tests/test-issue6528.t --- a/tests/test-issue6528.t +++ b/tests/test-issue6528.t @@ -220,6 +220,25 @@ 0 6 2a8d3833f2fb 000000000000 000000000000 1 7 2a80419dfc31 2a8d3833f2fb 000000000000 +Test the --paranoid option + $ hg debug-repair-issue6528 --dry-run --paranoid + found affected revision 1 for filelog 'data/D.txt.i' + found affected revision 1 for filelog 'data/b.txt.i' + found affected revision 3 for filelog 'data/b.txt.i' + $ hg st + M D.txt + M b.txt + $ hg debugrevlogindex b.txt + rev linkrev nodeid p1 p2 + 0 2 05b806ebe5ea 000000000000 000000000000 + 1 3 a58b36ad6b65 05b806ebe5ea 000000000000 + 2 6 216a5fe8b8ed 000000000000 000000000000 + 3 7 ea4f2f2463cc 216a5fe8b8ed 000000000000 + $ hg debugrevlogindex D.txt + rev linkrev nodeid p1 p2 + 0 6 2a8d3833f2fb 000000000000 000000000000 + 1 7 2a80419dfc31 2a8d3833f2fb 000000000000 + Run the fix $ hg debug-repair-issue6528 found affected revision 1 for filelog 'data/D.txt.i'