Bug 3604 - strip large amount of changesets causes maximum recursion depth exceeded
Summary: strip large amount of changesets causes maximum recursion depth exceeded
Status: RESOLVED FIXED
Alias: None
Product: Mercurial
Classification: Unclassified
Component: mq (show other bugs)
Version: earlier
Hardware: PC Linux
: normal bug
Assignee: Bugzilla
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-08-31 13:36 UTC by Yuya Nishihara
Modified: 2017-11-01 18:05 UTC (History)
4 users (show)

See Also:
Python Version: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Yuya Nishihara 2012-08-31 13:36 UTC
Since ec7b9bec19c9, stripping large amount of changesets causes RuntimeError at revset.

-- script to reproduce --
#!/bin/sh -e
hg init repo
cd repo

touch foo
hg add foo

for i in `seq 0 399`; do
    echo $i >> foo
    hg ci -m $i
done

hg --config extensions.mq= strip 0
----

-- traceback --
** unknown exception encountered, please report by visiting
** http://mercurial.selenic.com/wiki/BugTracker
** Python 2.7.3 (default, Aug 26 2012, 11:57:48) [GCC 4.7.1]
** Mercurial Distributed SCM (version 2.3+44-fc14953e8e34)
** Extensions loaded: mq
Traceback (most recent call last):
  File "/home/yuya/work/hghacks/mercurial/hg", line 38, in <module>
    mercurial.dispatch.run()
  File "/home/yuya/work/hghacks/mercurial/mercurial/dispatch.py", line 28, in run
    sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
  File "/home/yuya/work/hghacks/mercurial/mercurial/dispatch.py", line 65, in dispatch
    return _runcatch(req)
  File "/home/yuya/work/hghacks/mercurial/mercurial/dispatch.py", line 88, in _runcatch
    return _dispatch(req)
  File "/home/yuya/work/hghacks/mercurial/mercurial/dispatch.py", line 740, in _dispatch
    cmdpats, cmdoptions)
  File "/home/yuya/work/hghacks/mercurial/mercurial/dispatch.py", line 514, in runcommand
    ret = _runcommand(ui, options, cmd, d)
  File "/home/yuya/work/hghacks/mercurial/mercurial/dispatch.py", line 830, in _runcommand
    return checkargs()
  File "/home/yuya/work/hghacks/mercurial/mercurial/dispatch.py", line 801, in checkargs
    return cmdfunc()
  File "/home/yuya/work/hghacks/mercurial/mercurial/dispatch.py", line 737, in <lambda>
    d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
  File "/home/yuya/work/hghacks/mercurial/mercurial/util.py", line 471, in check
    return func(*args, **kwargs)
  File "/home/yuya/work/hghacks/mercurial/hgext/mq.py", line 3039, in strip
    force=opts.get('force'))
  File "/home/yuya/work/hghacks/mercurial/hgext/mq.py", line 1118, in strip
    repair.strip(self.ui, repo, revs, backup)
  File "/home/yuya/work/hghacks/mercurial/mercurial/repair.py", line 116, in strip
    rset, rset)
  File "/home/yuya/work/hghacks/mercurial/mercurial/localrepo.py", line 371, in revs
    return [r for r in m(self, range(len(self)))]
  File "/home/yuya/work/hghacks/mercurial/mercurial/revset.py", line 1752, in mfunc
    return getset(repo, subset, tree)
  File "/home/yuya/work/hghacks/mercurial/mercurial/revset.py", line 187, in getset
    return methods[x[0]](repo, subset, *x[1:])
  File "/home/yuya/work/hghacks/mercurial/mercurial/revset.py", line 260, in func
    return symbols[a[1]](repo, subset, b)
  File "/home/yuya/work/hghacks/mercurial/mercurial/revset.py", line 1329, in sort
    for r in getset(repo, subset, s):
  File "/home/yuya/work/hghacks/mercurial/mercurial/revset.py", line 187, in getset
    return methods[x[0]](repo, subset, *x[1:])
  File "/home/yuya/work/hghacks/mercurial/mercurial/revset.py", line 260, in func
    return symbols[a[1]](repo, subset, b)
  File "/home/yuya/work/hghacks/mercurial/mercurial/revset.py", line 837, in heads
    s = getset(repo, subset, x)
  File "/home/yuya/work/hghacks/mercurial/mercurial/revset.py", line 187, in getset
    return methods[x[0]](repo, subset, *x[1:])
  File "/home/yuya/work/hghacks/mercurial/mercurial/revset.py", line 243, in andset
    return getset(repo, getset(repo, subset, x), y)
  File "/home/yuya/work/hghacks/mercurial/mercurial/revset.py", line 187, in getset
    return methods[x[0]](repo, subset, *x[1:])
  File "/home/yuya/work/hghacks/mercurial/mercurial/revset.py", line 252, in notset
    s = set(getset(repo, subset, x))
  File "/home/yuya/work/hghacks/mercurial/mercurial/revset.py", line 187, in getset
    return methods[x[0]](repo, subset, *x[1:])
  File "/home/yuya/work/hghacks/mercurial/mercurial/revset.py", line 246, in orset
    xl = getset(repo, subset, x)
...
  File "/home/yuya/work/hghacks/mercurial/mercurial/revset.py", line 246, in orset
    xl = getset(repo, subset, x)
RuntimeError: maximum recursion depth exceeded
----
Comment 1 Kevin Bullock 2012-08-31 13:51 UTC
I've seen this one too.
Comment 2 Matt Mackall 2012-08-31 15:17 UTC
Adding guilty party fingered by bisect.

This first line here is the culprit:

    rset = ' or '.join([str(r) for r in tostrip])
    newbmtarget = repo.revs('sort(heads(ancestors(%r) - (%r)), -rev)',
                            rset, rset)

The large 'or' join creates a depth-N unbalanced tree structure that revset eventually recurses too deeply on. Instead, this should use the 'l' modifier:

  repo.revs('ancestors(%ld)', listofrevnums)

which builds a structure that we handle efficiently (search for _list in revset.py).
Comment 3 Augie Fackler 2012-08-31 15:45 UTC
(In reply to comment #2)
You wouldn't happen to have the guilty changeset id handy, would you?
Comment 4 Yuya Nishihara 2012-09-01 10:58 UTC
Confirmed the fix by
http://hg.intevation.org/mercurial/crew/rev/63e9b0732518

Thanks!
Comment 5 HG Bot 2012-09-01 15:02 UTC
Fixed by http://selenic.com/repo/hg/rev/7c865f30e2b8
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
strip: fix revset usage (issue3604)

The `repair` code builds a giant revset query instead of using the "%lr" idiom.
It is inefficient and crash when the number of stripped changeset is too big.

This changeset replaces the bad code by a better revset usage.

(please test the fix)
Comment 6 Yuya Nishihara 2012-09-01 23:18 UTC
Also confirmed the fix at release 2.3.1, thanks.