copies: add a config to limit the number of candidates to check in heuristics

The heuristics algorithm find possible candidates for move/copy and then check
whether they are actually a copy or move. In some cases, there can be lot of
candidates possible which can actually slow down the algorithm.

This patch introduces a config option
`experimental.copytrace.movecandidateslimit` using which one can limit the
candidates to check. The limit defaults to 100.

Thanks to Yuya for suggesting to skip copytracing for that file with a
warning.

Differential Revision: https://phab.mercurial-scm.org/D987
This commit is contained in:
Pulkit Goyal 2017-10-10 02:25:03 +05:30
parent 3fba6ca94a
commit 98c13e4c70
3 changed files with 80 additions and 0 deletions

View File

@ -330,6 +330,9 @@ coreconfigitem('experimental', 'clientcompressionengines',
coreconfigitem('experimental', 'copytrace', coreconfigitem('experimental', 'copytrace',
default='on', default='on',
) )
coreconfigitem('experimental', 'copytrace.movecandidateslimit',
default=100,
)
coreconfigitem('experimental', 'copytrace.sourcecommitlimit', coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
default=100, default=100,
) )

View File

@ -11,6 +11,8 @@ import collections
import heapq import heapq
import os import os
from .i18n import _
from . import ( from . import (
match as matchmod, match as matchmod,
node, node,
@ -644,6 +646,11 @@ def _heuristicscopytracing(repo, c1, c2, base):
[experimental] [experimental]
copytrace = heuristics copytrace = heuristics
In some cases the copy/move candidates found by heuristics can be very large
in number and that will make the algorithm slow. The number of possible
candidates to check can be limited by using the config
`experimental.copytrace.movecandidateslimit` which defaults to 100.
""" """
if c1.rev() is None: if c1.rev() is None:
@ -704,6 +711,17 @@ def _heuristicscopytracing(repo, c1, c2, base):
# f is guaranteed to be present in c2, that's why # f is guaranteed to be present in c2, that's why
# c2.filectx(f) won't fail # c2.filectx(f) won't fail
f2 = c2.filectx(f) f2 = c2.filectx(f)
# we can have a lot of candidates which can slow down the heuristics
# config value to limit the number of candidates moves to check
maxcandidates = repo.ui.configint('experimental',
'copytrace.movecandidateslimit')
if len(movecandidates) > maxcandidates:
repo.ui.status(_("skipping copytracing for '%s', more "
"candidates than the limit: %d\n")
% (f, len(movecandidates)))
continue
for candidate in movecandidates: for candidate in movecandidates:
f1 = c1.filectx(candidate) f1 = c1.filectx(candidate)
if _related(f1, f2, anc.rev()): if _related(f1, f2, anc.rev()):

View File

@ -201,6 +201,65 @@ Check a few potential move candidates
$ cd .. $ cd ..
$ rm -rf repo $ rm -rf repo
Test the copytrace.movecandidateslimit with many move candidates
----------------------------------------------------------------
$ hg init repo
$ initclient repo
$ cd repo
$ echo a > a
$ hg add a
$ hg ci -m initial
$ hg mv a foo
$ echo a > b
$ echo a > c
$ echo a > d
$ echo a > e
$ echo a > f
$ echo a > g
$ hg add b
$ hg add c
$ hg add d
$ hg add e
$ hg add f
$ hg add g
$ hg ci -m 'mv a foo, add many files'
$ hg up -q ".^"
$ echo b > a
$ hg ci -m 'mod a'
created new head
$ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
@ changeset: ef716627c70bf4ca0bdb623cfb0d6fe5b9acc51e
| desc: mod a
| o changeset: 8329d5c6bf479ec5ca59b9864f3f45d07213f5a4
|/ desc: mv a foo, add many files
o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
desc: initial
With small limit
$ hg rebase -s 2 -d 1 --config experimental.copytrace.movecandidateslimit=0
rebasing 2:ef716627c70b "mod a" (tip)
skipping copytracing for 'a', more candidates than the limit: 7
other [source] changed a which local [dest] deleted
use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
unresolved conflicts (see hg resolve, then hg rebase --continue)
[1]
$ hg rebase --abort
rebase aborted
With default limit which is 100
$ hg rebase -s 2 -d 1
rebasing 2:ef716627c70b "mod a" (tip)
merging foo and a to foo
saved backup bundle to $TESTTMP/repo/.hg/strip-backup/ef716627c70b-24681561-rebase.hg (glob)
$ cd ..
$ rm -rf repo
Move file in one branch and delete it in another Move file in one branch and delete it in another
----------------------------------------------- -----------------------------------------------