Bryan O'Sullivan <bryano@fb.com> [Tue, 16 Apr 2013 10:08:20 -0700] rev 18988
parsers: a C implementation of the new ancestors algorithm
The performance of both the old and new Python ancestor algorithms
depends on the number of revs they need to traverse. Although the
new algorithm performs far better than the old when revs are
numerically and topologically close, both algorithms become slow
under other circumstances, taking up to 1.8 seconds to give answers
in a Linux kernel repo.
This C implementation of the new algorithm is a fairly straightforward
transliteration. The only corner case of interest is that it raises
an OverflowError if the number of GCA candidates found during the
first pass is greater than 24, to avoid the dual perils of fixnum
overflow and trying to allocate too much memory. (If this exception
is raised, the Python implementation is used instead.)
Performance numbers are good: in a Linux kernel repo, time for "hg
debugancestors" on two distant revs (
24bf01de7537 and
c2a8808f5943)
is as follows:
Old Python: 0.36 sec
New Python: 0.42 sec
New C: 0.02 sec
For a case where the new algorithm should perform well:
Old Python: 1.84 sec
New Python: 0.07 sec
New C: measures as zero when using --time
(This commit includes a paranoid cross-check to ensure that the
Python and C implementations give identical answers. The above
performance numbers were measured with that check disabled.)
Bryan O'Sullivan <bryano@fb.com> [Tue, 16 Apr 2013 10:08:19 -0700] rev 18987
revlog: choose a consistent ancestor when there's a tie
Previously, we chose a rev based on numeric ordering, which could
cause "the same merge" in topologically identical but numerically
different repos to choose different merge bases.
We now choose the lexically least node; this is stable across
different revlog orderings.
Bryan O'Sullivan <bryano@fb.com> [Tue, 16 Apr 2013 10:08:18 -0700] rev 18986
ancestor: a new algorithm that is faster for nodes near tip
Instead of walking all the way to the root of the DAG, we generate
a set of candidate GCA revs, then figure out which ones will win
the race to the root (usually without needing to traverse all the
way to the root).
In the common case of nodes that are close to each other in both
revision number and topology, this is usually a big win: it makes
"hg --time debugancestors" up to 9 times faster than the more general
ancestor function when measured on heads of the linux-2.6 hg repo.
Victory is not assured, however. The older function can still win
by a large margin if one node is much closer to the root than the
other, or by a much smaller amount if one is an ancestor of the
other.
For now, we've also got a small paranoid harness function that calls
both ancestor functions on every input and ensures that they give
equivalent answers.
Even without the checker function, the old ancestor function needs
to stay alive for the time being, as its generality is used by
context.filectx.merge.
Pierre-Yves David <pierre-yves.david@logilab.fr> [Tue, 16 Apr 2013 15:33:18 +0200] rev 18985
update: allow dirty update to foreground (successors)
Update to "foreground" are no longer seen as cross branch update. "Foreground"
are descendants or successors (or successors of descendants (or descendant of
successors (etc))). This allows to update with uncommited changes that get
automatically merged.
This changeset is a small step forward. We want to allow dirty update to
"background" (precursors) and takes obsolescence in account when finding the
default update destination. But those requires deeper changes and will comes in
later changesets.
Pierre-Yves David <pierre-yves.david@logilab.fr> [Tue, 16 Apr 2013 15:16:33 +0200] rev 18984
obsolete: extract foreground computation from bookmark.validdest
This foreground logic will be reused by update logic.
Pierre-Yves David <pierre-yves.david@logilab.fr> [Mon, 15 Apr 2013 17:10:58 +0200] rev 18983
destroyed: invalidate phraserevs cache in all case (
issue3858)
When revisions are destroyed, the `phaserevs` cache becomes invalid in most case.
This cache hold a `{rev => phase}` mapping and revision number most likely
changed.
Since
1c8e0d6ac3b0, we filter unknown phases' roots after changesets
destruction. When some roots are filtered the `phaserevs` cache is invalidated.
But not if none root where destroyed.
We now invalidate the cache in all case filtered root or not.
This bug was a bit tricky to reproduce as in most case we either:
* rebase a set a draft changeset including root (phaserev invalidated)
* strip tip-most changesets (no re-numbering of revision)
Note that the invalidation of `phaserevs` are not strictly needed when only
tip-most part of the history have been destroyed. But I do not expect the
overhead to be significant.
Mads Kiilerich <madski@unity3d.com> [Mon, 15 Apr 2013 01:59:11 +0200] rev 18982
largefiles: deprecate --all-largefiles for pull
The same can be achieved with --lfrev pulled() and we shouldn't advertise
unnecessary command line options.
Mads Kiilerich <madski@unity3d.com> [Mon, 15 Apr 2013 01:59:11 +0200] rev 18981
largefiles: implement pull --all-largefiles as a special case of --lfrev
Mads Kiilerich <madski@unity3d.com> [Mon, 15 Apr 2013 01:59:11 +0200] rev 18980
largefiles: drop --cache-largefiles again
This goes a step further than
d69585a5c5c0 and backs out the unreleased
--cache-largefiles option. The same can be achieved with --lfrev heads(pulled()) and
we shouldn't introduce unnecessary command line options.
Mads Kiilerich <madski@unity3d.com> [Mon, 15 Apr 2013 01:59:04 +0200] rev 18979
largefiles: introduce pulled() revset expression for use in --lfrev
This provides a general way to do what already can be done with
--all-largefiles and --cache-largefiles.