Commit Graph

917 Commits

Author SHA1 Message Date
Matt Harbison
1abecad109 revset: add the 'subrepo' symbol
This returns the csets where matching subrepos have changed with respect to the
containing repo's first parent.  The second parent shouldn't matter, because it
is either syncing up to the first parent (i.e. it hasn't changed from the
current branch's POV), or the merge changed it with respect to the first parent
(which already adds it to the set).

There's already a 'subrepo' fileset, but it is prefixed with 'set:', so there
should be no ambiguity (in code anyway).  The only test I see for it is to
revert subrepos named by a glob pattern (in test-subrepo.t, line 58).  Since it
doesn't return a tracked file, neither 'log "set:subrepo()"' nor
'files "set:subrepo()"' print anything.  Therefore, it seems useful to have a
revset that will return something for log (and can be added to a revsetalias to
be chained with 'file' revsets.)

It might be nice to be able to filter for added, modified and removed
separately, but add/remove should be rare.  It might also be nice to be able to
do a 'contains' check, in addition to this mutated check.  Maybe it is possible
to get those with the existing 'adds', 'contains', 'modifies' and 'removes' by
teaching them to chase explicit paths into subrepos.

I'm not sure if this should be added to the 'modifies adds removes' line in
revset.optimize() (since it is doing an AMR check on .hgsubstate), or if it is
OK to put into 'safesymbols' (things like 'file' are on the list, and that takes
a regex, among other patterns).
2015-03-25 14:56:54 -04:00
Yuya Nishihara
e50dcd48fb revset: drop translation marker from error message of _notpublic()
It is a kind of an internal error. End user won't see it.
2015-05-19 23:29:20 +09:00
Yuya Nishihara
9dda746eb9 revset: drop docstring from internal _notpublic() function
It shouldn't be listed in "hg help revset".
2015-05-19 23:26:25 +09:00
Laurent Charignon
be38dd4abe revset: optimize not public revset
This patvh speeds up the computation of the not public() changeset
and incidentally speed up the computation of divergents() changeset on our big
repo by 100x from 50% to 0.5% of the time spent in smartlog with evolve.

In this patch we optimize not public() to _notpublic() (new revset) and use
the work on phaseset (from the previous commit) to be able to compute
_notpublic() quickly.

We use a non-lazy approach making the assumption the number of notpublic
change will not be in the order of magnitude of the repo size. Adopting a
lazy approach gives a speedup of 5x (vs 100x) only due to the overhead of the
code for lazy generation.
2015-04-24 14:30:30 -07:00
Augie Fackler
a5b17bd9d1 cleanup: use __builtins__.any instead of util.any
any() is available in all Python versions we support now.
2015-05-16 14:30:07 -04:00
Pierre-Yves David
49fcb055f4 generatorset: use 'next()' to simplify the code
The 'next()' built-in accept a default value. This remove the needs to check if
self non-empty before returning a value.
2015-05-17 18:06:09 -07:00
Pierre-Yves David
db5d2b0a12 revset: use 'next()' to detect end of iteration in 'last'
The 'next()' built-in can return a default value, allow to get rid of the
confusing try/except code flow.
2015-05-17 18:00:38 -07:00
Pierre-Yves David
95c104ceb7 revset: use 'next()' to detect end of iteration in 'limit'
The 'next()' built-in can return a default value, allow to get rid of the
confusing try/except code flow.
2015-05-17 17:58:39 -07:00
Pierre-Yves David
3e86398675 _revancestors: use 'next' to remove the verbose try except clauses
The 'next()' built-in can return a default value, making the final iteration
case simpler and clearer.
2015-05-17 17:54:58 -07:00
Yuya Nishihara
498cbbe4ca revset: extract addset._iterordered to free function
It never uses self, so let's make it less dependent on variables.
2015-05-16 21:42:09 +09:00
Yuya Nishihara
4f23717a35 revset: use fastasc/fastdesc switch consistently in addset.__iter__ 2015-05-16 14:05:02 +09:00
Yuya Nishihara
be1e504983 revset: drop redundant filteredset from right-hand side set of "or" operation
Since b4681ae82d4a, it should no longer be necessary because the addset can
remove duplicates correctly.
2015-03-30 20:56:37 +09:00
Pierre-Yves David
fc3daddf63 revset: fix iteration over ordered addset composed of non-ordered operands
Before this change, doing ordered iteration over an 'addset' object composed of
operands without fastasc or fastdesc method could result in duplicated entries.
This was the result of applying '_iterordered' on an unordered set.

We fix it by ensuring we iterate over the set in a sorted order. Using the fast
iterator when it exists on any operand. We kill the '_iterator' method in the
process because it did not make a lot of sense independently.

Thanks goes to Yuya Nishihara for reporting the issue and analysing the cause.
2015-05-15 00:25:43 -07:00
Yuya Nishihara
7c8dcbb212 revset: remove unused 'only' from methods table
The infix 'only' operator is mapped to 'only()' function by optimize(), so
it won't be looked up as a method. The test shows it.
2015-05-15 22:38:24 +09:00
Matt Mackall
e71173010b merge with stable 2015-05-15 11:52:09 -05:00
Yuya Nishihara
17d1eb2f7e revset: test current behavior of addset class
The addset class isn't simple and it has a hidden bug that will be fixed by
future patches. So let's test the current behavior.
2015-03-30 19:51:40 +09:00
Yuya Nishihara
5780b536c6 revset: remove duplicated definition of choice() from addset._iterordered()
choice() is already defined before val1 = None. Perhaps there was merge or
rebase error.
2015-04-27 23:03:20 +09:00
Yuya Nishihara
4290eff5ce revset: add wdir() function to specify workingctx revision by command
The main purpose of wdir() is to annotate working-directory files.

Currently many commands and revsets cannot handle workingctx and may raise
exception. For example, -r ":wdir()" results in TypeError. This problem will
be addressed by future patches.

We could add "wdir" symbol instead, but it would conflict with the existing
tag, bookmark or branch. So I decided not to.

List of commands that will potentially support workingctx revision:

  command   default  remarks
  --------  -------  -----------------------------------------------------
  annotate  p1       useful
  archive   p1       might be useful
  cat       p1       might be useful on Windows (no cat)
  diff      p1:wdir  (default)
  export    p1       might be useful if wctx can have draft commit message
  files     wdir     (default)
  grep      tip:0    might be useful
  identify  wdir     (default)
  locate    wdir     (default)
  log       tip:0    might be useful with -p or -G option
  parents   wdir     (default)
  status    wdir     (default)

This patch includes minimal test of "hg status" that should be able to handle
the workingctx revision.
2014-08-16 13:44:16 +09:00
Durham Goode
23a18a419d revbranchcache: store repo on the object
Previously we would instantiate the revbranchcache with a repo object, use it
briefly, then require it be passed in every time we wanted to fetch any
information. This seems unnecessary since it's obviously specific to that repo
(since it was constructed with it).

This patch stores the repo on the revbranchcache object, and removes the repo
parameter from the various functions on that class. This has the other nice
benefit of removing the double-revbranchcache-read that existed before (it was
read once for the branch revset, and once for the repo.revbranchcache).
2015-02-10 19:57:51 -08:00
Yuya Nishihara
34da300653 revset: replace "working copy" with "working directory" in function help 2015-03-17 20:50:19 +09:00
Jordi Gutiérrez Hermoso
8eb132f5ea style: kill ersatz if-else ternary operators
Although Python supports `X = Y if COND else Z`, this was only
introduced in Python 2.5. Since we have to support Python 2.4, it was
a very common thing to write instead `X = COND and Y or Z`, which is a
bit obscure at a glance. It requires some intricate knowledge of
Python to understand how to parse these one-liners.

We change instead all of these one-liners to 4-liners. This was
executed with the following perlism:

    find -name "*.py" -exec perl -pi -e 's,(\s*)([\.\w]+) = \(?(\S+)\s+and\s+(\S*)\)?\s+or\s+(\S*)$,$1if $3:\n$1    $2 = $4\n$1else:\n$1    $2 = $5,' {} \;

I tweaked the following cases from the automatic Perl output:

    prev = (parents and parents[0]) or nullid
    port = (use_ssl and 443 or 80)
    cwd = (pats and repo.getcwd()) or ''
    rename = fctx and webutil.renamelink(fctx) or []
    ctx = fctx and fctx or ctx
    self.base = (mapfile and os.path.dirname(mapfile)) or ''

I also added some newlines wherever they seemd appropriate for readability

There are probably a few ersatz ternary operators still in the code
somewhere, lurking away from the power of a simple regex.
2015-03-13 17:00:06 -04:00
Augie Fackler
0b9e6790bf revset: use UnknownIdentifier where appropriate 2015-01-26 14:32:30 -05:00
Yuya Nishihara
3adf9bf0f3 revset: extend fullreposet to make "null" revision magically appears in set
As per fullreposet.__and__, it can omit the range check of rev.  Therefore,
"null" revision is accepted automagically.

It seems this can fix many query results involving null symbol.  Originally,
the simplest "(null)" query did fail if there were hidden revisions.  Tests
are randomly chosen.

fullreposet mimics the behavior of localrepo, where "null" revision is not
listed but contained.
2015-01-08 23:05:45 +09:00
Yuya Nishihara
f6f2cc07d6 revset: duplicate spanset.__contains__ to fullreposet for modification
fcccbf073394 says we should avoid function calls in __contains__, so
super(fullreposet, self).__contains__(rev) is not an option.

Actually the super call doubled the benchmark result of trivial query:

revisions:
0) 6aa81b0c4658 (tip when I wrote this patch)
1) rev == node.nullrev or super(fullreposet, self).__contains__(rev)

revset #0: tip:0
0) wall 0.008441 comb 0.010000 user 0.010000 sys 0.000000 (best of 282)
1) wall 0.016152 comb 0.010000 user 0.010000 sys 0.000000 (best of 146)
2015-01-10 18:09:25 +09:00
Yuya Nishihara
ee4ca20b38 revset: have all() filter out null revision
I'm not sure if "all()" should filter out "null", but "all()" is stated as
'the same as "0:tip"' (except that it doesn't reorder the subset, I think.)

This patch is intended to avoid exposing a fullreposet to graphmod.dagwalker(),
which would result in strange drawing in future version:

  |
  o  changeset:   0:f8035bb17114
  |  user:        test
  |  date:        Thu Jan 01 00:00:00 1970 +0000
  |  summary:     add a

caused by:

    parents = sorted(set([p.rev() for p in ctx.parents()
                          if p.rev() in revs]))

We cannot add "and p.rev() != nullrev" here because revs may actually include
"null" revision.
2015-01-10 14:49:50 +09:00
Yuya Nishihara
bc28702606 revset: drop unnecessary calls of getall() with empty argument
If x is None, getall(repo, subset, x) == subset.
2015-01-10 16:41:36 +09:00
Matt Mackall
b907416f7b merge with stable 2015-03-02 01:20:14 -06:00
Mads Kiilerich
56207b4242 revisionbranchcache: fall back to slow path if starting readonly (issue4531)
Transitioning to Mercurial versions with revision branch cache could be slow as
long as all operations were readonly (revset queries) and the cache would be
populated but not written back.

Instead, fall back to using the consistently slow path when readonly and the
cache doesn't exist yet. That avoids the overhead of populating the cache
without writing it back.

If not readonly, it will still populate all missing entries initially. That
avoids repeated writing of the cache file with small updates, and it also makes
sure a fully populated cache available for the readonly operations.
2015-02-06 02:52:10 +01:00
FUJIWARA Katsunori
8a439b3cc6 revset: mask specific names for named() predicate
Before this patch, revset predicate "tag()" and "named('tags')" differ
from each other, because the former doesn't include "tip" but the
latter does.

For equivalence, "named('tags')" shouldn't include the revision
corresponded to "tip". But just removing "tip" from the "tags"
namespace causes breaking backward compatibility, even though "tip"
itself is planned to be eliminated, as mentioned below.

    http://selenic.com/pipermail/mercurial-devel/2015-February/066157.html

To mask specific names ("tip" in this case) for "named()" predicate,
this patch introduces "deprecated" into "namespaces", and makes
"named()" predicate examine whether each names are masked by the
namespace, to which they belong.

"named()" will really work correctly after 3.3.1 (see a3c326a7f57a for
detail), and fixing this on STABLE before 3.3.1 can prevent initial
users of "named()" from expecting "named('tags')" to include "tip".

It is reason why this patch is posted for STABLE, even though problem
itself isn't so serious.

This may have to be flagged as "(BC)", if applied on DEFAULT.
2015-02-05 14:45:49 +09:00
FUJIWARA Katsunori
c3172b4737 revset: get revision number of each node from target namespaces
Before this patch, revset predicate "named()" uses each nodes gotten
from target namespaces directly.

This causes problems below:

  - combination of other predicates doesn't work correctly, because
    they assume that revisions are listed up in number

  - "hg log" doesn't show any revisions for "named()" result, because:

    - "changeset_printer" stores formatted output for each revisions
      into dict with revision number (= ctx.rev()) as a key of them

    - "changeset_printer.flush(rev)" writes stored output for
      the specified revision, but

    - "commands.log" invokes it with the node, gotten from "named()"

  - "hg debugrevspec" shows nodes (= may be binary) directly

Difference between revset predicate "tag()" and "named('tags')" in
tests is fixed in subsequent patch.
2015-02-03 21:56:29 +09:00
FUJIWARA Katsunori
6a05d7fab8 revset: raise RepoLookupError to make present() predicate continue the query
Before this patch, "bookmark()", "named()" and "tag()" predicates
raise "Abort", when the specified pattern doesn't match against
existing ones.

This prevents "present()" predicate from continuing the query, because
it only catches "RepoLookupError".

This patch raises "RepoLookupError" instead of "Abort", to make
"present()" predicate continue the query, even if "bookmark()",
"named()" or "tag()" in the sub-query of it are aborted.

This patch doesn't contain raising "RepoLookupError" for "re:" pattern
in "tag()", because "tag()" treats it differently from others. Actions
of each predicates at failure of pattern matching can be summarized as
below:

  predicate  "literal:"  "re:"
  ---------- ----------- ------------
  bookmark   abort       abort
  named      abort       abort
  tag        abort       continue (*1)

  branch     abort       continue (*2)
  ---------- ----------- ------------

"tag()" may have to abort in the (*1) case for similarity, but this
change may break backward compatibility of existing revset queries. It
seems to have to be changed on "default" branch (with "BC" ?).

On the other hand, (*2) seems to be reasonable, even though it breaks
similarity, because "branch()" in this case doesn't check exact
existence of branches, but does pick up revisions of which branch
matches against the pattern.

This patch also adds tests for "branch()" to clarify behavior around
"present()" of similar predicates, even though this patch doesn't
change "branch()".
2015-01-31 01:00:50 +09:00
Yuya Nishihara
b5f973788a revset: fix ancestors(null) to include null revision (issue4512)
Since fe39bbbf31f0, null parent is explicitly excluded. So, there is no reason
to have nullrev in the initial seen set.
2015-01-25 20:20:27 +09:00
Yuya Nishihara
78d778b5ef revset: allow rev(-1) to indicate null revision (BC)
This can simplify the conversion from numeric revision to string. Without it,
we have to handle -1 specially because repo['-1'] != repo[-1].

The -1 revision is not officially documented, but this change makes sense
assuming that "rev(%d)" exists for scripting or third-party tools.
2015-01-10 12:56:38 +09:00
Martin von Zweigbergk
4b40ac0110 log: evaluate filesets on working copy, not its parent
When running "hg log 'set:added()'", we create two matchers: one used
for producing the revset and one used for finding files to match. In
185b6b930e8c (graphlog: evaluate FILE/-I/-X filesets on the working
dir, 2012-02-26), we started passing a revision argument along from
what's currently in cmdutil._makelogrevset() to
revset._matchfiles(). When the revision was an empty string, it
referred to the working copy. This was subtly done with "repo[rev or
None]". Then, in 5ff5c5c9e69f (revset: avoid recalculating filesets,
2014-10-22), that conversion from empty string to None was lost. Note
that repo[''] is equivalent to repo['.'], not repo[None].

The consequence of this, to the user, is that when running "hg log
'set:added()'", the file matcher matches files added in the working
copy, while the revset matcher matches revisions that touch files
added in the parent of the working copy. As a result, only revisions
that touch any files added in the parent of the working copy will be
considered, but they will only be included if they also touch files
added in the working copy.

Fix the bug by converting '' to None again, but make it a little more
explicit this time (plus, we now have tests for it).
2015-01-21 15:23:13 -08:00
Yuya Nishihara
4c1f7f24d7 revset: drop factory that promotes spanset to fullreposet
All callers use fullreposet where appropriate.

Backed out changeset 6c2c046ac382
2015-01-08 23:43:15 +09:00
Yuya Nishihara
878c8b67df revset: specify fullreposet without using spanset factory
The factory function will be removed because the subsequent patches will
make fullreposet(repo) not fully compatible with spanset(repo).
2015-01-08 23:46:54 +09:00
Yuya Nishihara
25fac1a15b revset: make match function initiate query from full set by default
This change is intended to avoid exposing the implementation detail to
callers. I'm going to extend fullreposet to support "null" revision, so
these mfunc calls will have to use fullreposet() instead of spanset().
2015-02-02 22:21:07 +09:00
FUJIWARA Katsunori
ac41d830e2 revset: check for collisions between alias argument names in the declaration
Before this patch, collisions between alias argument names in the
declaration are ignored, and this silently causes unexpected alias
evaluation.

This patch checks for such collisions, and aborts (or shows a warning) when
collisions are detected.

This patch doesn't add a test to "test-revset.t", because a doctest is
enough to test the collisions detection itself.
2015-01-10 23:18:11 +09:00
FUJIWARA Katsunori
e416b72fc5 revset: parse alias declaration strictly by _parsealiasdecl
Before this patch, alias declaration is parsed by string base
operations: matching against "^([^(]+)\(([^)]+)\)$" and splitting by
",".

This overlooks many syntax errors like below (see the previous patch
introducing "_parsealiasdecl" for detail):

  - un-closed parenthesis causes being treated as "alias symbol"
  - symbol/function name aren't examined whether they are valid or not
  - invalid argument list causes unexpected argument names

To parse alias declaration strictly, this patch replaces parsing
implementation by "_parsealiasdecl".

This patch tests only one typical declaration error case, because
error detection itself is already tested in the doctest of
"_parsealiasdecl".

This also removes class property "args" and "error", because these are
certainly initialized in "revsetalias.__init__".
2015-01-10 23:18:11 +09:00
FUJIWARA Katsunori
87958c780f revset: introduce "_parsealiasdecl" to parse alias declarations strictly
This patch introduces "_parsealiasdecl" to parse alias declarations
strictly. For example, "_parsealiasdecl" can detect problems below,
which current implementation can't.

  - un-closed parenthesis causes being treated as "alias symbol"

    because all of declarations not in "func(....)" style are
    recognized as "alias symbol".

    for example, "foo($1, $2" is treated as the alias symbol.

  - alias symbol/function names aren't examined whether they are valid
    as symbol or not

    for example, "foo bar" can be treated as the alias symbol, but of
    course such invalid symbol can't be referred in revset.

  - just splitting argument list by "," causes overlooking syntax
    problems in the declaration

    for example, all of invalid declarations below are overlooked:

    - foo("bar")     => taking one argument named as '"bar"'
    - foo("unclosed) => taking one argument named as '"unclosed'
    - foo(bar::baz)  => taking one argument named as 'bar::baz'
    - foo(bar($1))   => taking one argument named as 'bar($1)'

To decrease complication of patch, current implementation for alias
declarations is replaced by "_parsealiasdecl" in the subsequent
patch. This patch just introduces it.

This patch defines "_parsealiasdecl" not as a method of "revsetalias"
class but as a one of "revset" module, because of ease of testing by
doctest.

This patch factors some helper functions for "tree" out, because:

  - direct accessing like "if tree[0] == 'func' and len(tree) > 1"
    decreases readability

  - subsequent patch (and also existing code paths, in the future) can
    use them for readability

This patch also factors "_tokenizealias" out, because it can be used
also for parsing alias definitions strictly.
2015-01-10 23:18:11 +09:00
FUJIWARA Katsunori
883b1f7edf revset: store full detail into revsetalias.error for error source distinction
Before this patch, any errors in the declaration of revset alias
aren't detected at all, and there is no information about error source
in the error message.

As a part of preparation for parsing alias declarations and
definitions more strictly, this patch stores full detail into
"revsetalias.error" for error source distinction.

This makes raising "Abort" and warning potential errors just use
"revsetalias.error" without any message composing.
2015-01-10 23:18:11 +09:00
FUJIWARA Katsunori
ae25ee95c4 revset: factor out composing error message for ParseError to reuse
This patch defines the composing function not in "ParseError" class but
in "revset" module, because:

  - "_()" shouldn't be used in "ParseError", to avoid adding "from
    i18n import _" i18n" to "error" module

  - generalizing message composition of"ParseError" for all code paths
    other than revset isn't the purpose of this patch

    we should also take care of showing "unexpected leading
    whitespace" for some code paths, to generalize widely.
2015-01-10 23:18:11 +09:00
FUJIWARA Katsunori
48233206c2 revset: make tokenize extensible to parse alias declarations and definitions
Before this patch, "tokenize" doesn't recognize the symbol starting
with "$" as a valid one.

This prevents revset alias declarations and definitions from being
parsed with "tokenize", because "$" may be used as the initial letter
of alias arguments.

BTW, the alias argument name doesn't require leading "$" itself, in
fact. But we have to assume that users may use "$" as the initial
letter of argument names in their aliases, because examples in "hg
help revsets" uses such names for a long time.

To make "tokenize" extensible to parse alias declarations and
definitions, this patch introduces optional arguments "syminitletters"
and "symletters". Giving these sets can change the policy of "valid
symbol" in tokenization easily.

This patch keeps original examination of letter validity for
reviewability, even though there is redundant interchanging between
"chr"/"ord" at initialization of "_syminitletters" and "_symletters".
At most 256 times examination (per initialization) is cheaper enough
than revset evaluation itself.

This patch is a part of preparation for parsing alias declarations and
definitions more strictly.
2015-01-10 23:18:11 +09:00
Sean Farley
f534500188 namespaces: add revset for 'named(namespace)'
This patch adds functionality for listing all changesets in a given namespace
via the revset language.
2015-01-13 15:07:08 -08:00
Matt Mackall
d829c30933 merge with stable 2015-01-14 12:50:46 -08:00
Yuya Nishihara
47e97cb140 revset: fix spanset.isascending() to honor sort() or reverse() request
Because spanset.isascending() ignored the ascending flag, the result of
"fullreposet() & x" was always sorted in ascending order.

The test case is carefully chosen to call fullreposet.__and__.
2015-01-10 21:31:59 +09:00
Yuya Nishihara
bf8b92850c revset: simplify fullreposet.__and__ to call sort() with boolean flag
Note that sort() takes a boolean flag, so other.sort(reverse) was wrong.
It just worked fine because there is a top-level function, reverse().
2015-01-10 21:36:42 +09:00
Martin von Zweigbergk
c91c749e46 filelog: fix backwards comment for 'backrevref' 2015-01-12 09:46:56 -08:00
Martin von Zweigbergk
63a49977e2 filelog: remove trailing "form feed" character 2015-01-12 09:49:25 -08:00
Martin von Zweigbergk
3e0453e7c4 filelog: remove unused variable 'lkr'
It's used further down, but it's overwritten before, so it's
technically a dead assignment, but unnecessary nevertheless.
2015-01-12 09:48:05 -08:00
Mads Kiilerich
61a36ea4fe revset: use localrepo revbranchcache for branch name filtering
Branch name filtering in revsets was expensive. For every rev it created a
changectx and called .branch() which retrieved the branch name from the
changelog.

Instead, use the revbranchcache.

The revbranchcache is used read-only. The revset implementation with generators
and callbacks makes it hard to figure out when we are done using/updating the
cache and could write it back. It would also be 'tricky' to lock the repo for
writing from within a revset execution. Finally, the branchmap update will
usually make sure that the cache is updated before any revset can be run.
The revbranchcache is used without any locking but is short-lived and used in a
tight loop where we can assume that the changelog doesn't change ... or where
it not is relevant to us if it does.

perfrevset 'branch(mobile)' on mozilla-central.
Before:
! wall 10.989637 comb 10.970000 user 10.940000 sys 0.030000 (best of 3)
After, no cache:
! wall 7.368656 comb 7.370000 user 7.360000 sys 0.010000 (best of 3)
After, with cache:
! wall 0.528098 comb 0.530000 user 0.530000 sys 0.000000 (best of 18)

The performance improvement even without cache come from being based on
branchinfo on the changelog instead of using ctx.branch().

Some tests are added to verify that the revbranchcache works and keep an eye on
when the cache files actually are updated.
2015-01-08 00:01:03 +01:00
Yuya Nishihara
b67b0a75ea revset: drop pre-lazyset optimization for stringset of subset == entire repo
It was introduced at deb42ca4dd93, where spanset.__contains__() did not exist.
Nowadays, we have to pay huge penalty for len(subset).

The following example showed that OR operation could be O(n * m^2)
(n: len(repo), m: number of OR operators, m >= 2) probably because of
filteredset.__len__.

revset #0: 0|1|2|3|4|5|6|7|8|9
0) wall 8.092713 comb 8.090000 user 8.090000 sys 0.000000 (best of 3)
1) wall 0.445354 comb 0.450000 user 0.430000 sys 0.020000 (best of 22)
2) wall 0.000389 comb 0.000000 user 0.000000 sys 0.000000 (best of 7347)
(0: 3.2.4, 1: 3.1.2, 2: this patch)
2015-01-03 10:25:08 +09:00
Pierre-Yves David
56b039c98c revset: fix first and last for generatorset (issue4465)
The code was just plain wrong.
2014-12-01 05:18:12 -08:00
Sean Farley
2a4b30c27c revset: use '%' as an operator for 'only'
With this patch, we can make it much easier to specify 'only(A,B)' ->
A%B. Similarly, 'only(A)' -> A%.

On Windows, '%' is a semi-reserved symbol in the following way: using non-bash
shells (e.g. cmd.exe but NOT PowerShell, ConEmu, and cmder), %var% is only
expanded when 'var' exists and is surrounded by '%'.

That only leaves batch scripts which could prove to be problematic. I posit
that this isn't a big issue because any developer of batch scripts already
knows that to use '%' one needs to escape it by using a double '%%'.

Alternatives to '%' could be '=' but that might be limiting our future if we
ever decide to use temporary assignments in a revset.
2014-11-06 14:55:18 -08:00
Yuya Nishihara
23dc58b88d revset: have rev() validate input by repo.changelog.__contains__()
fullreposet.__contains__() will be rewritten in order to support "null"
revision, and "rev()" won't be possible to rely on it.

This backs out 23ac42e12ce5, but there is no performance regression now.

revisions:
0) bd19f94d30e9 "l not in fullreposet(repo)"
1) this patch   "l not in repo.changelog"

revset #0: rev(210000)
0) wall 0.000056 comb 0.000000 user 0.000000 sys 0.000000 (best of 48036)
1) wall 0.000049 comb 0.000000 user 0.000000 sys 0.000000 (best of 54969)
2015-02-04 21:37:06 +09:00
Matt Mackall
8fae3e2918 merge with stable 2015-02-03 17:54:01 -06:00
FUJIWARA Katsunori
e08054a75c revset: replace parsing alias definition by _parsealiasdefn to parse strictly
Before this patch, referring alias arguments is parsed by string base
operation "str.replace".

This causes problems below (see the previous patch introducing
"_parsealiasdefn" for detail)

  - the shorter name argument breaks referring the longer name
  - argument names in the quoted string are broken

This patch replaces parsing alias definition by "_parsealiasdefn" to
parse strictly.
2015-02-02 23:07:04 +09:00
FUJIWARA Katsunori
b7991124ca revset: introduce _parsealiasdefn to parse alias definitions strictly
This patch introduces "_parsealiasdefn" to parse alias definitions
strictly. For example, it can avoid problems below, which current
implementation can't.

  - the shorter name argument breaks referring the longer name one in
    the definition, if the former is completely prefix of the latter

    for example, the alias definition "foo($1, $10) = $1 or $10" is
    parsed as "_aliasarg('$1') or _aliasarg('$1')0" and causes parse
    error, because tail "0" of "_aliasarg('$1')0" is invalid.

  - argument names in the quoted string are broken

    for example, the definition "foo($1) = $1 or desc('$1')" is parsed
    as "_aliasarg('$1') or desc('_aliasarg(\'$1\')')" and causes
    unexpected description matching against not '$1' but '_aliasarg(\'$1\')'.

To decrease complication of patch, current implementation for alias
definitions is replaced by "_parsealiasdefn" in the subsequent
patch. This patch just introduces it.

This patch defines "_parsealiasdefn" not as a method of "revsetalias"
class but as a one of "revset" module, because of ease of testing by
doctest.
2015-02-02 23:07:04 +09:00
FUJIWARA Katsunori
fa0f66b4fb revset: introduce new operator "##" to concatenate strings/symbols at runtime
Before this patch, there is no way to concatenate strings at runtime.

For example, to search for the issue ID "1234" in descriptions against
all of "issue 1234", "issue:1234", issue1234" and "bug(1234)"
patterns, the revset below should be written fully from scratch for
each issue ID.

    grep(r"\bissue[ :]?1234\b|\bbug\(1234\)")

This patch introduces new infix operator "##" to concatenate
strings/symbols at runtime. Operator symbol "##" comes from the same
one of C pre-processor. This concatenation allows parametrizing a part
of strings in revset queries.

In the case of example above, the definition of the revset alias using
operator "##" below can search issue ID "1234" in complicated patterns
by "issue(1234)" simply:

    issue($1) = grep(r"\bissue[ :]?" ## $1 ## r"\b|\bbug\(" ## $1 ## r"\)")

"##" operator does:

  - concatenate not only strings but also symbols into the string

    Exact distinction between strings and symbols seems not to be
    convenience, because it is tiresome for users (and
    "revset.getstring" treats both similarly)

    For example of revset alias "issue()", "issue(1234)" is easier
    than "issue('1234')".

  - have higher priority than any other prefix, infix and postfix
    operators (like as "##" of C pre-processor)

    This patch (re-)assigns the priority 20 to "##", and 21 to "(",
    because priority 19 is already assigned to "-" as prefix "negate".
2015-01-06 23:46:18 +09:00
Pierre-Yves David
1ed0c1e70a revset-filelog: handle hidden linkrev for file missing for head (issue4490)
The fix for linkrev pointing to hidden revision was crashing when the file was
missing from head's manifest. We now properly handle this case.

(yes I feel silly)
2015-01-06 11:23:38 -08:00
Matt Mackall
1c9cf418be merge with stable 2015-01-05 15:46:14 -06:00
FUJIWARA Katsunori
ec7eaba601 revset: delay showing parse error for the revset alias until it is referred
Before this patch, a problematic revset alias aborts execution
immediately, even if it isn't referred in the specified revset.

If old "hg" may be used too (for example, bisecting Mercurial itself),
it is also difficult to write alias definitions using features newly
introduced by newer "hg" into configuration files, because such alias
definitions cause unexpected abortion at parsing revset aliases with
old "hg".

This patch delays showing parse error for the revset alias until it is
actually referred at runtime.

This patch detects referring problematic aliases in "_expandaliases"
by examination of "revsetalias.error", which is initialized with the
error message only when parsing fails.

For usability, this patch also warns about problematic aliases, even
if they aren't referred at runtime. This should help users to know
potential problems in their alias definitions earlier.
2015-01-05 11:02:04 +09:00
Pierre-Yves David
a533fb454c linkrev-filelog: handle filtered linkrev with no visible children (issue4307)
If the file revision with a filtered linkrev does not have any
(unfiltered) children, we cannot use it to bound the search for
another introduction. Instead, we have to look at the file revision
used by each head changeset. If one of them uses this file revision, we
know there is another occurrence and we have a starting point. See
inline comments for details.

Adding some kind of permanent reference of all the introductions of a
file revision instead of just the first one would be much better. But
this is more difficult. I hope to take that into account in the next
repository format.
2014-12-29 18:35:23 -08:00
Pierre-Yves David
e3f2a2625a linkrev: work around linkrev to filtered entry in 'filelog' revset
This revset is used by 'hg log FILENAME'. This prevent bugs when used on
a repository with hidden revisions.

Instead of just discarding file revisions whose linkrevs point to filtered
revisions, we put them aside and post-process them trying to find a non-filtered
introduction. See inline documentation for details about how it works.

This only fixes some of the problems. Once again, more will be needed when we can
cannot rely on child revisions of a file to find linkrev-shadowned revisions.

A test is added for 'hg log' catching such cases.
2014-12-29 17:23:16 -08:00
Pierre-Yves David
0344ecbf5b linkrev: also adjust linkrev when bootstrapping 'follow' revset
The follow revset (used by `hg log --follow`) now uses the new 'introrev'
method to bootstrap its traversal. This catches issues from linkrev-shadowing of
the changesets introducing the version of a file in source changeset.

A new test has been added to display pathological cases.

Another test is affected because it was meant to test this behavior but actually
failed to do so for half of the output. The output are now similar.
2014-12-29 23:40:24 -08:00
Pierre-Yves David
d713bc119f revset: avoid returning duplicates when returning ancestors
Before this patch, _revancestors were giving false result when a revision was
duplicated in the input. Duplicated entry are rare but may happen when using the
`%lx` notation internally.

This series has no visible impact on the performance of the function according
to benchmark.
2014-03-26 15:55:50 -07:00
Pierre-Yves David
ed0fe85776 revset: use an iterator instead of a dequeue in ancestors()
The dequeue was actually just used to be able to pop value one at a time.
Building the dequeue means we are reading all the input value at once at the
beginning of the evaluation. This defeat the lazyness of revset.

We replace the deque with iterator usage for the sake of simplicity and
lazyness.

This provide massive speedup to get the first result if the input set is big

max(::all())
before) wall 0.001917 comb 0.000000 user 0.000000 sys 0.000000 (best of 1115)
after)  wall 0.000107 comb 0.000000 user 0.000000 sys 0.000000 (best of 22222)
2014-03-26 16:21:30 -07:00
Martin von Zweigbergk
dc6f60fee9 revset: return early when revs is empty
By introducing an early return in _revancestors() when revs is empty,
we make it so inputrev is never None, which simplifies the subsequent
code.
2015-05-06 11:29:09 -07:00
Pierre-Yves David
1130b9cf61 revset: rename 'revsnode' to 'inputrev' in ancestors
We usually use 'node' for variable containing 20 bytes hash. There is nothing
nodish in this variable, so we rename it to "inputrev" as it old the next entry
of the iteration.
2014-03-26 16:14:30 -07:00
Pierre-Yves David
a3cd232465 revset: make generatorset.__nonzero__ lazy
The 'for r in self:' call could trigger full consumption of the generator while
we only need a single value. We also fast path if a single value got already
computed. See inline comment for more details.

This provide massive speedup for lazy operation using boolean testing.

max(::tip)
1e5463ae4044) wall 0.055609 comb 0.060000 user 0.060000 sys 0.000000 (best of 100)
after change) wall 0.000109 comb 0.000000 user 0.000000 sys 0.000000 (best of 19146)
2015-05-04 12:36:48 -07:00
Jordi Gutiérrez Hermoso
c93dcba997 revset: don't error out if tokens parse as existing symbols
It makes perfect sense for tokens to parse as existing revset symbols
(revset functions), and doesn't break anything, since parsing symbols
as functions works correctly in the presence of parens. For example,
if "only" is a bookmark, this used to error out,

   hg log -r "only(only, @)"

which shouldn't, as the inner "only" is unambiguously not a function.

So we just remove the symbolset function and replace its calling site
with the stringset function.

For the tests, we confirm that "date" and "only" are both parsed as
revision names both inside revset expressions (e.g. an expression
containing ::) and inside old-style revision expressions (e.g. those
containing the name of the revision alone).
2015-05-03 12:28:15 -04:00
Pierre-Yves David
77c097ded9 revset: narrow the subset using smartset operation in roots()
We were manually creating a base with explicit subset testing. We should let
smartset magic happen and optimise that logic if needed.

benchmark show some massive speedup when "parents set" is huge and "subset" is
small.

revset: 42:68 and roots(42:tip)
0) wall 0.011322 comb 0.010000 user 0.010000 sys 0.000000 (best of 161)
1) wall 0.002282 comb 0.010000 user 0.010000 sys 0.000000 (best of 1082)

Minor speedup in simple case (were fullreposet helps)

revset: roots(0::tip)
0) wall 0.095688 comb 0.100000 user 0.100000 sys 0.000000 (best of 85)
1) wall 0.084448 comb 0.080000 user 0.080000 sys 0.000000 (best of 95)

revset: roots((0:tip)::)
0) wall 0.146752 comb 0.140000 user 0.140000 sys 0.000000 (best of 58)
1) wall 0.143538 comb 0.140000 user 0.140000 sys 0.000000 (best of 59)

And small overhead then the "parents set" is fairly complicated (transforming it
into a revset once and for all appears to be faster).

revset: roots((tip~100::) - (tip~100::tip))
0) wall 0.004652 comb 0.010000 user 0.010000 sys 0.000000 (best of 544)
1) wall 0.004878 comb 0.010000 user 0.010000 sys 0.000000 (best of 479)

revset: roots((0::) - (0::tip))
0) wall 0.146587 comb 0.150000 user 0.150000 sys 0.000000 (best of 53)
1) wall 0.157192 comb 0.160000 user 0.160000 sys 0.000000 (best of 53)

revset: first(roots((0::) - (0::tip)))
0) wall 0.152924 comb 0.150000 user 0.150000 sys 0.000000 (best of 57)
1) wall 0.153192 comb 0.160000 user 0.160000 sys 0.000000 (best of 55)
2014-10-11 01:17:40 -07:00
Yuya Nishihara
72198a2056 revset: add 'only' to DoS-safe symbols
There is no reason to disable it in hgweb because the same query can be
written without using 'only()'.
2014-12-03 22:56:42 +09:00
Yuya Nishihara
f62323518b revset: move 'only' so that functions are sorted alphabetically 2014-12-03 22:52:54 +09:00
Matt Mackall
289d6b53bc merge with stable 2014-12-01 19:34:11 -06:00
Siddharth Agarwal
b3be1bdf41 revset.only: use cl.findmissingrevs
ancestor.missingancestors is really an implementation detail.
2014-11-14 16:38:58 -08:00
Pierre-Yves David
515b17f5ef revset-matching: call 'getset' on a 'fullreposet'
Calling 'baseset(repo.changelog)' builds a list for all revisions in
the repo. And we already have the lazy and efficient 'fullreposet'
class for this purpose.

This gives us the usual benefits of the fullreposet but it is less visible
because the matching process itself is very expensive:

revset) matching(100)
before) wall 6.413281 comb 6.420000 user 5.910000 sys 0.510000 (best of 3)
after)  wall 6.173608 comb 6.170000 user 5.750000 sys 0.420000 (best of 3)

However for some complex list, this provide a massive speedup

revset) matching(parents(100))
before) wall 23.890740 comb 23.890000 user 23.450000 sys 0.440000 (best of 3)
after)  wall 6.382280 comb 6.390000 user 5.930000 sys 0.460000 (best of 3)
2014-10-16 23:15:35 -07:00
Pierre-Yves David
7b5edd0cf5 revset-parentspec: call 'getset' on a 'fullreposet'
Calling 'baseset(repo.changelog)' builds a list for all revisions in
the repo. And we already have the lazy and efficient 'fullreposet'
class for this purpose.

This gives us the usual benefits of the fullreposet:

revset) 100^1
before) wall 0.002694 comb 0.000000 user 0.000000 sys 0.000000 (best of 897)
after)  wall 0.000997 comb 0.000000 user 0.000000 sys 0.000000 (best of 2324)

revset) parents(100)^1
before) wall 0.003832 comb 0.000000 user 0.000000 sys 0.000000 (best of 587)
after)  wall 0.001034 comb 0.000000 user 0.000000 sys 0.000000 (best of 2309)

revset) (100^1)^1
before) wall 0.005616 comb 0.000000 user 0.000000 sys 0.000000 (best of 405)
after)  wall 0.001030 comb 0.000000 user 0.000000 sys 0.000000 (best of 2258)
2014-10-16 23:15:06 -07:00
Pierre-Yves David
f1982bfd1d revset-children: call 'getset' on a 'fullreposet'
Calling 'baseset(repo.changelog)' builds a list for all revisions in the
repo. And we already have the lazy and efficient 'fullreposet' class
for this purpose.

This gives us the usual benefits of the fullreposet:

revset) children(tip~100)
before) wall 0.007469 comb 0.010000 user 0.010000 sys 0.000000 (best of 338)
after)  wall 0.003356 comb 0.000000 user 0.000000 sys 0.000000 (best of 755)
2014-10-16 23:14:17 -07:00
Pierre-Yves David
593610531e revset-ancestorspec: call 'getset' on a 'fullreposet'
Calling 'baseset(repo.changelog)' builds a list for all revisions in
the repo. And we already have the lazy and efficient 'fullreposet'
class for this purpose.

This gives us the usual benefits of the fullreposet:

revset) 100~5
before) wall 0.002712 comb 0.000000 user 0.000000 sys 0.000000 (best of 918)
after)  wall 0.000996 comb 0.000000 user 0.000000 sys 0.000000 (best of 2493)

revset) parents(100)~5
before) wall 0.003812 comb 0.010000 user 0.010000 sys 0.000000 (best of 667)
after)  wall 0.001038 comb 0.000000 user 0.000000 sys 0.000000 (best of 2361)

revset) (100~5)~5
before) wall 0.005614 comb 0.000000 user 0.000000 sys 0.000000 (best of 446)
after)  wall 0.001035 comb 0.000000 user 0.000000 sys 0.000000 (best of 2424)
2014-10-16 23:11:25 -07:00
Pierre-Yves David
985922c845 revset-rangeset: call 'getset' on a 'fullreposet'
Calling 'baseset(repo.changelog)' builds a list for all revisions in
the repo. And we already have the lazy and efficient 'fullreposet'
class for this purpose.

This gives us the usual benefit ofs the fullreposet:

revset) 10:100
before) wall 0.002774 comb 0.000000 user 0.000000 sys 0.000000 (best of 797)
after)  wall 0.001977 comb 0.000000 user 0.000000 sys 0.000000 (best of 1244)

revset) parents(10):parents(100)
before) wall 0.005054 comb 0.000000 user 0.000000 sys 0.000000 (best of 481)
after)  wall 0.002060 comb 0.000000 user 0.000000 sys 0.000000 (best of 1056)
2014-10-16 23:10:44 -07:00
Mads Kiilerich
523c87c1fe spelling: fixes from proofreading of spell checker issues 2014-04-17 22:47:38 +02:00
Pierre-Yves David
2463533597 addset: fix first and last on sorted addset (issue4426)
The lazy sorting were not enforced on addset. This was made visible through MQ.
2014-11-01 22:58:30 +00:00
Martin von Zweigbergk
ef6448aa8b revset: don't recreate matcher for every revision
The matcher variable 'm' in checkstatus() is reset to None on each
call, so the caching of the matcher no longer happens as it was
intended. This seems to be a regression in 6b9fbae54476 (revset: added
lazyset implementation to checkstatus, 2014-01-03).

Fix by moving the cached matcher into the enclosing function so it's
actually cached across calls. This speeds up

  hg log -r 'modifies(mercurial/context.py)' >/dev/null

from 7.5s to 4s.

Also see similar fix in 5ff5c5c9e69f (revset: avoid recalculating
filesets, 2014-10-22).
2014-10-31 10:41:36 -07:00
Durham Goode
c9e0ce83ec revset: fix O(2^n) perf regression in addset
hg log -r 1 ... -r 100 was never returning due to a regression in the
way addset computes __nonzero__. It used 'bool(self._r1 or self._r2)'
which required executing self._r1.__nonzero__ twice (once for the or,
once for the bool). hg log with a lot of -r's happens to build a one
sided addset tree of N length, which ends up being 2^N performance.

This patch fixes it by converting to bool before or'ing.

This problem can be repro'd with something as simple as:

hg log `for x in $(seq 1 50) ; do echo "-r $x "; done`

Adding '1 + 2 + ... + 20' to the revsetbenchmark.txt didn't seem to repro the
problem, so I wasn't able to add a revset benchmark for this issue.
2014-10-28 14:06:06 -07:00
Yuya Nishihara
740a18d819 revset: avoid O(n) lookup of invalid revision in rev()
0cc5c10d5dc7 was not the final version of that patch.  It was really slow
because `l not in repo.changelog` iterates revisions up to `l`.  Instead,
rev() should utilize spanset.__contains__().

revset #0: rev(210000)
0) wall 0.000039 comb 0.000000 user 0.000000 sys 0.000000 (best of 67978)
1) wall 0.002721 comb 0.000000 user 0.000000 sys 0.000000 (best of 1055)
2) wall 0.000059 comb 0.000000 user 0.000000 sys 0.000000 (best of 45599)
(0: 3.2-rc, 1: 0cc5c10d5dc7, 2: this patch)

Note that the benchmark result described in 0cc5c10d5dc7 is wrong because
it is the one of the initial version.
2014-10-23 21:53:37 +09:00
Yuya Nishihara
bac0595bd4 revset: have rev() drop out-of-range or filtered rev explicitly (issue4396)
The recent optimization of "and" operation relies on the assumption that
the rhs set does not contain invalid revisions.  So rev() has to remove
invalid revisions.

This is still faster than using `.filter(lambda r: r == l)`.

revset #0: rev(25)
0) wall 0.026341 comb 0.020000 user 0.020000 sys 0.000000 (best of 113)
1) wall 0.000038 comb 0.000000 user 0.000000 sys 0.000000 (best of 66567)
2) wall 0.000062 comb 0.000000 user 0.000000 sys 0.000000 (best of 43699)
(0: 428fa22fb2d1^, 1: 3.2-rc, 2: this patch)
2014-10-19 16:48:33 +09:00
Matt Mackall
56b374dd4e revset: avoid recalculating filesets
This fixes a regression in ea41ca830940 that moved matcher building
into a callback, thus causing it be rebuilt for each revision matched
against.
2014-10-22 15:47:27 -05:00
Pierre-Yves David
0d2e3a1dee revset-phases: prefetch attributes in phasesrelated revsets
Pre-fetching attributes gives a significant performance boost. Such is Python.


draft()
0) wall 0.011661 comb 0.010000 user 0.010000 sys 0.000000 (best of 205)
1) wall 0.009804 comb 0.000000 user 0.000000 sys 0.000000 (best of 231)

draft() - ::bookmark()
0) wall 0.014173 comb 0.010000 user 0.010000 sys 0.000000 (best of 177)
1) wall 0.012966 comb 0.010000 user 0.010000 sys 0.000000 (best of 182)
2014-10-16 17:46:58 -07:00
Pierre-Yves David
8347f164c0 revset-phases: do not cache phase-related filters
The phase retrieval is fast enough to not require caching the result of the
functions.

draft()
0) wall 0.017209 comb 0.020000 user 0.020000 sys 0.000000 (best of 149)
1) wall 0.011654 comb 0.010000 user 0.010000 sys 0.000000 (best of 186)

public()
0) wall 0.018687 comb 0.010000 user 0.010000 sys 0.000000 (best of 128)
1) wall 0.013290 comb 0.010000 user 0.010000 sys 0.000000 (best of 181)

secret()
0) wall 0.017464 comb 0.020000 user 0.020000 sys 0.000000 (best of 127)
1) wall 0.011499 comb 0.000000 user 0.000000 sys 0.000000 (best of 196)

draft() - ::bookmark()
0) wall 0.020099 comb 0.020000 user 0.020000 sys 0.000000 (best of 127)
1) wall 0.014399 comb 0.020000 user 0.020000 sys 0.000000 (best of 169)
2014-10-11 01:21:47 -07:00
Pierre-Yves David
4de6496309 revset-node: speedup by a few hundred fold
Instead of checking all elements of the subset against a single rev, just check
if this rev is in the subset. The old way was inherited from when the subset was
a list.

Non surprise, this provide massive speedup.


id("b7dc31e4baa4")
before) wall 0.008205 comb 0.000000 user 0.000000 sys 0.000000 (best of 302)
after)  wall 0.000069 comb 0.000000 user 0.000000 sys 0.000000 (best of 34518)

revset #1: public() and id("b7dc31e4baa4")
before) wall 0.019763 comb 0.020000 user 0.020000 sys 0.000000 (best of 124)
after)  wall 0.000101 comb 0.000000 user 0.000000 sys 0.000000 (best of 20130)
2014-10-11 01:39:20 -07:00
Pierre-Yves David
7268257aae revset-only: use subset & instead of filtering
The & version is more likely to be optimised.

only(.)
before) wall 0.003216 comb 0.000000 user 0.000000 sys 0.000000 (best of 768)
after)  wall 0.001086 comb 0.000000 user 0.000000 sys 0.000000 (best of 2231)

only(default, stable)
before) wall 0.018469 comb 0.020000 user 0.020000 sys 0.000000 (best of 138)
after)  wall 0.015888 comb 0.010000 user 0.010000 sys 0.000000 (best of 156)
2014-10-10 17:28:18 -07:00
Pierre-Yves David
4e015a4853 revset-_ancestor: use & instead of filter
The & operation is more likely optimised.

::10
before) wall 0.028189 comb 0.030000 user 0.030000 sys 0.000000 (best of 100)
after)  wall 0.001050 comb 0.000000 user 0.000000 sys 0.000000 (best of 2326)

::tip
before) wall 0.081132 comb 0.080000 user 0.080000 sys 0.000000 (best of 100)
after)  wall 0.055418 comb 0.050000 user 0.050000 sys 0.000000 (best of 100)
2014-09-30 15:03:54 -05:00
Pierre-Yves David
98eb7704b3 revset-only: use __nonzero__ to check if a revset is empty
For some smartsets, computing length is more expensive than checking if the set
is empty.
2014-10-08 02:45:21 -07:00
Pierre-Yves David
4ec24e2ba6 _spanset: drop __getitem__ implementation
It is expensive and not part of the official smartset API.
2014-10-15 12:38:47 -07:00
Pierre-Yves David
b634e6fb8f filteredset: drop __getitem__ implementation
It is expensive and not part of the official smartset API.
2014-10-15 12:38:32 -07:00
Pierre-Yves David
8f9f017c39 generatorset: implement __len__
It was the only smartset class without a `__len__` implementation.
2014-10-15 04:28:55 -07:00
Pierre-Yves David
d4bf12d496 revset: make __len__ part of the offical API
It is common for code to ask for the length of a revset. In fact, all but
generatorset already implement it.
2014-10-15 04:26:23 -07:00
Mads Kiilerich
4353d6acbb revset: better naming of variables containing the value of a single argument
Calling them args is not helpful.
2014-10-15 04:08:06 +02:00
Pierre-Yves David
551481efc6 spanset: remove .set() definition
All my friends are dead.
2014-10-10 13:09:22 -07:00
Pierre-Yves David
cdaf453077 generatorset: remove .set() definition
All my friends are dead.
2014-10-10 13:08:49 -07:00
Pierre-Yves David
9531e16b0d addset: remove .set() definition
All my friends are dead.
2014-10-10 13:08:28 -07:00
Pierre-Yves David
f957be2403 filteredset: remove .set() definition
All my friends are dead.
2014-10-10 13:08:10 -07:00
Pierre-Yves David
fcdeb29add baseset: remove set() definition
All my friends are dead.
2014-10-10 13:07:35 -07:00
Pierre-Yves David
a9fcdb25c5 abstractsmartset: remove set() method definition
Now that all usages have been removed, we can drop this not so useful part of
the API. We can note that the name was wrong all along...
2014-10-10 11:27:57 -07:00
Pierre-Yves David
70851c278d match: check if an object is a baseset using isascending instead of set
The `set()` method is going away.
2014-10-10 14:27:05 -07:00
Pierre-Yves David
0de25934dc getset: check if an object is a baseset using isascending instead of set
The `set()` method is going away.
2014-10-10 14:22:23 -07:00
Pierre-Yves David
c249a728eb fullreposet: detect smartset using "isascending" instead of "set"
The `.set()` function is going away.
2014-10-10 13:24:57 -07:00
Pierre-Yves David
be86e2f6f1 fullreposet: drop custom sets but not smartsets detection
All custom classes use by revsets are smartsets now. We drop the special-casing.
2014-10-10 13:21:05 -07:00
Pierre-Yves David
e0b5b0a127 addset: drop .set() usage during iteration
We can use the containment check directly.
2014-10-10 12:30:00 -07:00
Pierre-Yves David
efff35ee9d baseset: access _set directly for containment check
The `.set()` method is going away.
2014-10-10 12:31:22 -07:00
Pierre-Yves David
5049b858d9 baseset: make _set a property cache
This will remove the need for `baseset.set()`.
2014-10-10 12:30:56 -07:00
Pierre-Yves David
a54d940320 revset-_hexlist: remove usage of set()
All smartset classes have fast lookup, so this function will be removed soon.
2014-10-08 02:52:10 -07:00
Pierre-Yves David
76a0476bf7 revset-_intlist: remove usage of set()
All smartset classes have fast lookup, so this function will be removed soon.
2014-10-08 02:51:54 -07:00
Pierre-Yves David
3094e008ed revset-_list: remove usage of set()
All smartset classes have fast lookup, so this function will be removed soon.
2014-10-08 02:51:16 -07:00
Pierre-Yves David
2c5bccb146 revset-roots: remove usage of set()
All smartset classes have fast lookup, so this function will be removed soon.
2014-10-08 02:50:20 -07:00
Pierre-Yves David
b1e5f6cb89 revset-origin: remove usage of set()
All smartset classes have fast lookup, so this function will be removed soon.
2014-10-08 02:49:17 -07:00
Pierre-Yves David
29984785df revset-last: remove usage of set()
All smartset classes have fast lookup, so this function will be removed soon.
2014-10-08 02:48:56 -07:00
Pierre-Yves David
113095a6b7 revset-limit: remove usage of set()
All smartset classes have fast lookup, so this function will be removed soon.
2014-10-08 02:48:24 -07:00
Pierre-Yves David
6847074b2d revset-destination: remove usage of set()
All smartset classes have fast lookup, so this function will be removed soon.
2014-10-08 02:47:46 -07:00
Pierre-Yves David
1ecbe47993 revset-children: remove usage of set()
All smartset classes have fast lookup, so this function will be removed soon.
2014-10-08 02:47:24 -07:00
Pierre-Yves David
4186e2d344 revset-branch: remove usage of set()
All smartset classes have fast lookup, so this function will be removed soon.
2014-10-08 02:47:00 -07:00
Pierre-Yves David
afe4b27987 revset-rangeset: remove usage of set()
All smartset classes have fast lookup, so this function will be removed soon.
2014-10-08 02:45:53 -07:00
Pierre-Yves David
ca06344dab revset-only: remove usage of set()
All smartset classes have fast lookup, so this function will be removed soon.
2014-10-08 02:45:43 -07:00
Pierre-Yves David
4e9488a8f8 revset: cache most conditions used in filter
Except when stated otherwise, the condition used in `smartset.filter` will be
cached. A new argument has been introduced to disable that behavior. We use it
for filters created from `and` and `sub` operations.

This gives massive performance boosts for revsets with expensive conditions.

revset: branch(stable) or branch(default)
before) wall 4.329070 comb 4.320000 user 4.310000 sys 0.010000 (best of 3)
after)  wall 2.356451 comb 2.360000 user 2.330000 sys 0.030000 (best of 4)

revset: author(mpm) or author(lmoscovicz)
before) wall 4.434719 comb 4.440000 user 4.440000 sys 0.000000 (best of 3)
after)  wall 2.321720 comb 2.320000 user 2.320000 sys 0.000000 (best of 4)
2014-10-09 22:57:52 -07:00
Pierre-Yves David
372cc7c36d baseset: empty or one-element sets are ascending and descending
The empty set is full of interesting properties. In the ordering case, the one
element set is too.
2014-10-09 04:12:20 -07:00
Pierre-Yves David
090fe27a36 filteredset: drop explicit order management
Now that all low-level smartset classes have proper ordering and fast iteration
management, we can just rely on the subset in filteredset.
2014-10-07 01:33:05 -07:00
Pierre-Yves David
d521f34fda revset: restore order of or operation as in Mercurial 2.9
Lazy revset broke the ordering of the `or` revset. We now stop assuming that
two ascending revset are combine into an ascending one.

Behavior in 3.0:

  3:4 or 2:5 == [2, 3, 4, 5]

Behavior in 2.9:

  3:4 or 2:5 == [3, 4, 2, 5]

We are adding a test for it.

For unclear reason, the performance `or` revset with expensive filter are
getting even worse than they used to be. This is probably caused by extra
uncached containment check or iteration.

revset #9: author(lmoscovicz) or author(mpm)
before) wall 3.487583 comb 3.490000 user 3.490000 sys 0.000000 (best of 3)
after)  wall 4.481486 comb 4.480000 user 4.470000 sys 0.010000 (best of 3)


revset #10: author(mpm) or author(lmoscovicz)
before) wall 3.164839 comb 3.170000 user 3.160000 sys 0.010000 (best of 3)
after)  wall 4.574965 comb 4.570000 user 4.570000 sys 0.000000 (best of 3)
2014-10-09 04:24:51 -07:00
Pierre-Yves David
2213bfcae4 revset-_descendant: rework the whole sorting and combining logic
We use the & operator to combine with subset (since this is more likely to be
optimised than filter) and we enforce the sorting of the result. Without this
enforced sorting, we may result in a different iteration order than the set
_descendent was computed from.

This reverts a bad `test-glog.t` change from 7904906883bd.

Another side effect is that `test-mq.t` shows `qparent::` including `-1` if
`qparent is -1`. This sound like a positive change.

This has good and bad impacts on the benchmarks, here is a good ones:

revset: 0::
before) wall 0.045489 comb 0.040000 user 0.040000 sys 0.000000 (best of 100)
after)  wall 0.034330 comb 0.030000 user 0.030000 sys 0.000000 (best of 100)

revset: roots((0::) - (0::tip))
before)  wall 0.134090 comb 0.140000 user 0.140000 sys 0.000000 (best of 63)
after) wall 0.128346 comb 0.130000 user 0.130000 sys 0.000000 (best of 69)

revset: ::p1(p1(tip))::
before) wall 0.143892 comb 0.140000 user 0.140000 sys 0.000000 (best of 55)
after)  wall 0.124502 comb 0.130000 user 0.130000 sys 0.000000 (best of 65)

revset: roots((0:tip)::)
before) wall 0.204966 comb 0.200000 user 0.200000 sys 0.000000 (best of 43)
after) wall 0.184455 comb 0.180000 user 0.180000 sys 0.000000 (best of 47)

Here is a bad one:

revset: (20000::) - (20000)
before) wall 0.009592 comb 0.010000 user 0.010000 sys 0.000000 (best of 222)
after)  wall 0.029837 comb 0.030000 user 0.030000 sys 0.000000 (best of 100)
2014-10-09 09:12:54 -07:00
Pierre-Yves David
b33f0a62a0 addset: do lazy sorting
The previous implementation was consuming the whole revset when asked for any
sort. The addset class is now doing lazy sorting like all other smarset classes.

This has no significant impact in the benchmark as-is. But this is important
to later change.
2014-10-09 20:15:41 -07:00
Pierre-Yves David
cdcb3820d1 baseset: drop custom __sub__ method
This add method is enforcing non-laziness, disabling multiple optimisations.

Benchmarks do not spot any significant difference but real usecase may. This
will also be important for further improvements to addset later in this series.
2014-10-09 04:29:18 -07:00
Pierre-Yves David
32d4f6ce1e baseset: drop custom __and__ method
This add method is enforcing non-laziness, disabling multiple optimisations.

Benchmarks do not spot any significant regression but real usecase may. This
even gives some speedup in some cases:

revset #15: min(0::)
before) wall 0.001247 comb 0.000000 user 0.000000 sys 0.000000 (best of 1814)
after)  wall 0.000942 comb 0.000000 user 0.000000 sys 0.000000 (best of 2367)

This will also be important for further improvement to addset later in this series.
2014-10-09 04:27:25 -07:00
Pierre-Yves David
35f0c6215a baseset: drop custom __add__ method
This add method is enforcing non-laziness, disabling multiple optimisations.

Benchmarks do not spot any significant differences but real usecase may. This
will also be important for further improvements to addset later in this series.
2014-10-09 04:27:01 -07:00
Pierre-Yves David
89697960fb smartset: drop infamous ascending, descending
All your friends are dead.
2014-10-07 01:46:53 -07:00
Pierre-Yves David
1f08d3a119 fullreposet: use isascending instead of ascending to recognise smartsets
`ascending` is going to be removed.
2014-10-07 01:41:14 -07:00
Pierre-Yves David
6da3ca17ab fullreposet: use sort to enforce the order
The `ascending` and `descending` methods are useless.
2014-10-07 01:41:26 -07:00
Pierre-Yves David
40789b5325 revancestors: replace descending with sort(reverse=False) 2014-10-07 01:48:34 -07:00
Pierre-Yves David
9ae79aaf3a _descendants: replace ascending() with sort() 2014-10-07 01:41:02 -07:00
Pierre-Yves David
59a9933f96 _descendants: directly use smartset
As `addset` objects are proper smartset objects, we do not need to make any
transformation of the result.
2014-10-07 01:36:53 -07:00
Pierre-Yves David
eb55591aca baseset: explicitly track order of the baseset
A baseset starts without an explicit order. But as soon as a sort is requested,
we simply register that the baseset has an order and use the ordered version of
the list to behave accordingly.

We will want to properly record the order at creation time in the future. This
would unlock more optimisation and avoid some sorting.
2014-10-03 03:29:55 -05:00
Pierre-Yves David
cf7077b249 baseset: fix isascending and isdescending
We now have sufficient information to return the proper value there.
2014-10-03 03:31:05 -05:00
Pierre-Yves David
ff023f566d baseset: prepare lazy ordering in __iter__
We'll explicitly track the order of the baseset to take advantage of the
ascending and descending lists during iteration.
2014-10-03 03:26:18 -05:00
Pierre-Yves David
d2f9fa68fe baseset: implement a fastasc and fastdesc
Baseset contains already-computed revisions. It is considered "cheap" to do
operations on an already-computed set. So we add attributes to hold version of
the list in ascending and descending order and use them for `fastasc` and
`fastdesc`. Having distinct lists is important to provide correct iteration in
all cases. Altering a python list will impact an iterator connected to it.

eg: not preserving order at iterator creation time

    >>> l = [0, 1]
    >>> i = iter(l)
    >>> l.reverse()
    >>> list(i)
    [1, 0]

eg: corrupting in progress iteration

    >>> l = [0, 1]
    >>> i = iter(l)
    >>> i.next()
    0
    >>> l.reverse()
    >>> i.next()
    0
2014-10-03 03:19:23 -05:00
Pierre-Yves David
b09ad7ecb4 baseset: stop inheriting from built-in list class
The baseset is doing more and more smartset magic and using its list-like
property less and less. So we store the list of revisions in an explicit
attribute and stop inheriting.

This requires reimplementing some basic methods.
2014-10-06 11:03:30 -07:00
Pierre-Yves David
734133be26 rangeset: use first and last instead of direct indexing
This makes it compatible with all smarsets classes.
2014-10-06 23:45:07 -07:00
Pierre-Yves David
38a691e7c7 filteredset: implement first and last 2014-10-07 00:18:08 -07:00
Pierre-Yves David
51a5e9775c baseset: implement first and last methods 2014-10-06 14:42:00 -07:00
Pierre-Yves David
98513b6f74 generatorset: implement first and last methods 2014-10-06 12:52:36 -07:00
Pierre-Yves David
0a7da549e2 addset: implement first and last methods
The implementation is non-lazy for now. One may want to make it more lazy in the
future.
2014-10-06 11:57:59 -07:00
Pierre-Yves David
0567fe01bf spanset: implement first and last methods 2014-10-06 11:54:53 -07:00
Pierre-Yves David
798e6b00b0 smartset: add first and last methods
In multiple places in the code, we use `someset[0]` or `someset[-1]`. This
works only because the `someset` is usually a baseset. For the same reason we
introduce a `first` and `last` methods to be implemented for all smartset
classes.
2014-10-06 11:46:53 -07:00
Pierre-Yves David
a814455e99 revset-last: remove user of baseset.append
A `baseset` has multiple cached results and will get even more in the future.
Making it an object "populated once" like the other smartsets makes it both safer
and simpler. The append method will be removed at some point.
2014-10-08 00:55:09 -07:00
Pierre-Yves David
e7663a53cd revset-limit: remove user of baseset.append
A `baseset` has multiple cached results and will get even more in the future.
Making it an object "populated once" like the other smartsets makes it both safer
and simpler. The append method will be removed at some point.
2014-10-06 10:57:01 -07:00
Pierre-Yves David
9f5274f4bc baseset: use default value instead of [] when possible
For pure cleanup purposes, we replace all the occurences of `baseset([])` with
`baseset()`.
2014-10-06 10:41:43 -07:00
Pierre-Yves David
a046529f73 generatorset: implement isascending and isdescending 2014-10-04 06:17:18 -07:00
Pierre-Yves David
d4b459bd9f generatorset: explicitly track iteration order
The expected iteration order may be different than the fast iteration order (eg:
ancestors(42) is expected to be iterated upward but is fast/lazy to compute
downward.

So we explicitly track the iteration order and enforce it if the manual
iteration is requested.

Default expected iteration order of a generator set is ascending because I'm
not aware of any descending revset that need a generatorset. The first to find
such descending revset will have the pleasure to make this configurable.
2014-10-03 21:11:56 -07:00
Pierre-Yves David
a82beab10d addset: drop caching through generatorset
The utility of this cache is debatable (no visible benchmark impact) and using
generatorset for such purpose makes the code complicated.

We drop it for now. Someone can reintroduce a smart version of it in the future
if it is detected to be relevant.
2014-10-03 20:23:02 -07:00
Pierre-Yves David
e6831448a3 generatorset: get list-based fast iterations after the generator is consumed
When all revisions are known, we shortcut most of the class logic to use list
iteration instead. The cost of the sort is expected to be non-significant. The
list creation and sorting could be done lazily in the future. We have to copy
the list to not break existing iterator created before we finished consuming the
generator.
2014-10-03 21:01:30 -07:00
Pierre-Yves David
1d2cf353fc generatorset: move iteration code into _iterator
_iterator handles the generator iteration. The `__iter__` method will need
changes to handle ordering-related information.
2014-10-03 20:48:28 -07:00
Pierre-Yves David
a0f1c697e2 generatorset: stop using a base as the _genlist
It does not add anything and makes it more complicated to have a simple baseset
implementation.
2014-10-03 20:43:48 -07:00
Pierre-Yves David
9d3c052ee3 generatorset: drop the leading underscore in the class name
This is a real smart set now.
2014-10-03 20:12:02 -07:00
Pierre-Yves David
dc2b8470bf generatorset: update the docstring now that it is a smartset
The documentation was still stating that this class was not a smartset. We drop
that part.
2014-10-03 20:14:43 -07:00
Pierre-Yves David
ccc0b916ad addset: drop the leading underscore from the class name
This class is now a real smartset.
2014-10-03 20:18:48 -07:00
Pierre-Yves David
e434af74be addset: this is a smartset, update the docstring
The documentation was still stating that this class is a not a smartset. We drop
that part.
2014-10-03 20:17:12 -07:00
Pierre-Yves David
d1e22facbe addset: use the ascending argument in _iterordered
Fix a bug where fastasc and fastdesc were iterator in the same order as
self._ascending.
2014-10-09 05:27:23 -07:00
Pierre-Yves David
cc531eaf7c revset: remove the now unused _descgeneratorset class 2014-10-03 12:54:56 -05:00
Pierre-Yves David
5660381e46 revset: use _generatorset in _revancestors
The _descgeneratorset class is going away.
2014-10-03 12:53:41 -05:00
Pierre-Yves David
0064df5af6 revset: remove now unused class _ascgeneratorset 2014-10-03 12:52:49 -05:00
Pierre-Yves David
2c0f15affd revset: use _generatorset directly in _revdescendant
_ascgeneratorset is going away.
2014-10-03 12:52:17 -05:00
Pierre-Yves David
d8ee591ede generatorset: move membership testing on ordered gen to the main class
We are phasing out the ordered version of the class to simplify the code.
2014-10-03 12:46:34 -05:00
Pierre-Yves David
f6fa8eb009 generatorset: make use of the new mechanism in the subclass
Until we remove them, we use the new parameter of _generatorset to make sure
the code is run.
2014-10-03 12:36:57 -05:00
Pierre-Yves David
8182bcd552 generatorset: make it possible to use gen as fastasc or fastdesc
We gain a parameter to inform that the generator is ascending or descending. If
the generator is ordered, it is also used for the `fastasc` or `fastdesc`
version.

The _ascgeneratorset and _descgeneratorset class will be removed soon.
2014-10-03 12:36:08 -05:00
Pierre-Yves David
360df469a0 baseset: rely on the abstractsmartset implementation for filter 2014-10-03 03:19:00 -05:00
Pierre-Yves David
1173000a7c _orderedsetmixin: drop this now unused class
All my friends are dead.
2014-10-02 19:48:14 -05:00
Pierre-Yves David
214e70e3ed spanset: drop _orderedsetmixin inheritance
The min/max method are as well provided by abstractsmartset.
2014-10-02 19:47:33 -05:00
Pierre-Yves David
5c0b91dc51 orderedlazyset: drop this now unused class
All my friends are dead.
2014-10-03 01:44:52 -05:00
Pierre-Yves David
2d5a7f7706 _descendant: use filteredset instead of orderedlazyset
The orderedlazyset class is going away. Filteredset gives the same service.
2014-10-02 19:43:42 -05:00
Pierre-Yves David
5081443516 addset: use the base implementation for ascending and descending 2014-10-03 01:37:13 -05:00
Pierre-Yves David
c77388089d addset: use base implementation for __filter__ 2014-10-03 01:34:25 -05:00
Pierre-Yves David
02ce29364d addset: use base implementation for __add__ 2014-10-03 01:33:32 -05:00
Pierre-Yves David
355c9d986e addset: use base implementation for __sub__ 2014-10-03 01:32:50 -05:00
Pierre-Yves David
a24bd6fb5b addset: use base implementation for __and__ 2014-10-03 01:31:46 -05:00
Pierre-Yves David
c65b8b42bd addset: promote to real smartset
Better revset performance are also achieved with less overlay. There is no good
reason for addset to not be a smartset. We can replace the `_orderedsetmixin`
inheritance since `abstractsmartset` has efficient min and max too.
2014-10-02 19:42:06 -05:00
Pierre-Yves David
7a25a7121b addset: add a __nonzero__ method
This is required to be a full smartset (not sure what was happening before
that...)
2014-10-03 00:12:22 -05:00
Pierre-Yves David
6a1c6ffa59 addset: offer a fastasc and fastdesc methods
If the underlying object offers fast iterators, we use them to provide fast
iterators too.
2014-10-02 23:38:30 -05:00
Pierre-Yves David
89b6f70699 addset: split simple and ordered iteration
We have two goals here. First, we would like to restore the former iteration
order we had in 2.9. Second, we want this logic to be reusable for `fastasc`
and `fastdesc` methods.
2014-10-02 23:28:18 -05:00
Pierre-Yves David
5559000069 generatorset: promote to smartset
This is not going to be efficient but we need all basic set classes to be smartsets
for the other classes to work.
2014-10-03 01:55:09 -05:00
Pierre-Yves David
58b382b0f7 generatorset: implement __nonzero__
This is necessary to become a real smartset.
2014-10-03 01:56:57 -05:00
Pierre-Yves David
a14781af28 spanset: use base implementation for __add__ 2014-10-03 00:31:33 -05:00
Pierre-Yves David
215016c505 spanset: use base implementation for __sub__ 2014-10-03 00:31:18 -05:00
Pierre-Yves David
8f595a844a spanset: use base implementation for __and__ 2014-10-03 00:30:58 -05:00
Pierre-Yves David
12baf0e606 spanset: use base implementation for filter 2014-10-03 00:39:57 -05:00
Pierre-Yves David
5d23f77ec3 filteredset: use base implementation for filter 2014-10-03 01:27:00 -05:00
Pierre-Yves David
1be20553d2 filteredset: use base implementation for __add__ 2014-10-03 01:25:35 -05:00
Pierre-Yves David
23bcf240b5 filteredset: use base implementation for __sub__ 2014-10-03 01:24:30 -05:00
Pierre-Yves David
24ee9a4abf filteredset: use base implementation for __and__ 2014-10-03 01:23:12 -05:00
Pierre-Yves David
13924bc45b abstractsmartset: add default implementation for __sub__ 2014-10-02 19:22:17 -05:00
Pierre-Yves David
67a9c485c6 abstractsmartset: add default implementation for __add__ 2014-10-02 19:22:03 -05:00
Pierre-Yves David
47e527a95f abstractsmartset: add default implementation for __and__ 2014-10-02 19:21:40 -05:00
Pierre-Yves David
8a3b420ade abstractsmartset: add default implementation for filter 2014-10-01 00:26:50 -05:00
Pierre-Yves David
133cc5824b lazyset: rename the class to filteredset
All smartsets try to be lazy. The purpose of this class is to apply a
filter on another set. So we rename the class (and all its occurences) to
`filteredset`.
2014-10-03 01:16:23 -05:00
Pierre-Yves David
c7274e7678 lazyset: add order awareness to the class
Just a bit of extra code makes the lazyset aware of order. This renders
orderedlazyset useless.

At some point, the `subset` will become responsible for this ordering logic. But
we are not there yet because the various objects used as subsets are not good enough.
2014-10-02 19:14:03 -05:00
Pierre-Yves David
0b05dee60c lazyset: remove min/max
This is now handled by abstractsmartset.
2014-10-02 19:03:14 -05:00
Pierre-Yves David
76604324cd baseset: remove min/max methods
This is now handled by the base class.
2014-10-02 19:02:50 -05:00
Pierre-Yves David
fb4c81e11e abstractsmartset: add a default implementation for min and max
This default implementation takes advantage of the fast iterator if available.
2014-10-02 18:59:41 -05:00
Pierre-Yves David
d810f109b3 lazyset: drop now useless ascending/descending definition 2014-10-02 18:52:09 -05:00
Pierre-Yves David
4be4f3fe52 lazyset: inherit the fastasc and fastdesc method from subset
When the filtered subset has such methods, we can use them. It is implemented
as properties to be able to quickly return None if no corresponding fastasc exists
on the subset.
2014-09-30 23:36:57 -05:00
Pierre-Yves David
b0f4537a2a lazyset: split the iteration logic from the condition filtering logic
So that the filter can be reused by `fastasc` or `fastdesc`.
2014-10-02 18:25:37 -05:00
Pierre-Yves David
5310fa5e65 spanset: do a single range check in __contains__
Now that `start <= end` is always true, we can simplify this function.
2014-10-02 17:53:55 -05:00
Pierre-Yves David
9d76d87327 spanset: enforce the order lazily to gain fastasc and fastdesc methods
Instead of having the direction of iteration enforced through the ordering of
`start` and `end` attributes of spanset, we encode the iteration direction in
an explicit attribute and always store start < end.  The logic for sort and
reverse has to be updated. The __iter__ is now based on the newly introduced
`fastasc` and `fastdesc` methods.

This will allow other code simplifications in the future.
2014-10-02 18:02:17 -05:00
Pierre-Yves David
82a1d861c5 abstractsmartset: document the fastasc and fastdesc attributes/methods
See the in-line documentation for details. (This is the beginning of a massive
overhaul of revset).
2014-09-30 22:26:34 -05:00
Pierre-Yves David
177faece69 spanset: remove ascending/descending implementation
We can rely on their implementation in abstractsmartset.
2014-10-02 18:35:56 -05:00
Pierre-Yves David
2b0dd7c610 baseset: remove ascending/descending redefinition
We can rely on the abstractsmartset implementation.
2014-10-02 18:35:00 -05:00
Pierre-Yves David
765584f8b2 abstractsmartset: default implementation for ascending and descending
These two methods are actually silly aliases for `sort()` and
`sort(reverse=True)`. So we get that aliasing at the abstractsmartset level. We
will slowly phase out all the custom implementations and eventually remove any
mentions of it from the code.
2014-10-02 18:34:18 -05:00
Pierre-Yves David
1b61d96256 revert: bring back usage of subset & ps in parents
Changeset 1440ec8e33c0 switched the order of the operand of the "&" computation
to work around an issue from repo-wide spanset. The need for a workaround has been
alleviated by the introduction of `fullreposet`. So we restore it to normal.

The benchmark shows no significant changes as expected.

We also revert the bogus test change introduced by 1440ec8e33c0. The order is
actually important.
2014-09-17 04:55:55 -07:00
Pierre-Yves David
166e755bd8 revset: introduce an abstractsmartset class
This class documents all methods required by a smartset. This makes it easier
for people to respect the API and ensure we fail loudly when something does
not. It will later also contain common default implementations for multiple
methods, making it easier to have smartset classes with minimal work.
2014-10-01 15:14:36 -05:00
Pierre-Yves David
63c5d3af3b revset: add a __nonzero__ to baseset
We are about to add a base class for `baseset` with an abstract `__nonzero__`
method. So we need this method to be explicitly defined to avoid issues. The
built-in list object apparently does not have a `__nonzero__` and relies on
`__len__` for this purpose?
2014-10-01 15:03:16 -05:00
Pierre-Yves David
a44ac390ee revset: drop isinstance(baseset) in spanset.__sub__
As baseset now has a fast __contains___ operator, this `baseset.set()` dance is no
longer needed. No regressions are visible in the benchmark.
2014-10-01 15:50:54 -05:00
Pierre-Yves David
43c1a7c7b7 revset: drop isinstance(baseset) in spanset.__and__
As baseset now has a fast __contains___ operator, this `baseset.set()` dance is no
longer needed. No regressions are visible in the benchmark.
2014-10-01 15:50:40 -05:00
Pierre-Yves David
3c21cdaa54 revset: drop isinstance(baseset) from baseset.__and__
As baseset now has a fast __contains___ operator, this `baseset.set()` dance is
no longer needed. No regressions are visible in the benchmark.
2014-09-30 23:09:59 -05:00
Pierre-Yves David
3a3ec48d95 revset: use direct access to __contains__ in spanset.__sub__
Using `x.__contains__(r)` instead of `r in x` does not matter for built-in type
(set) but have a positive impact for all other classes. This will let us drop
some usage of baseset.set() in future patches. This also probably improves some
performance.
2014-10-01 15:53:42 -05:00
Pierre-Yves David
d93cff0448 revset: use a single return statement in matcher function
This makes it easy to insert post processing and debug code on the returned
value.
2014-09-30 12:39:21 -05:00
Pierre-Yves David
2a8200e655 revset: rely on built in iterator when possible in _generatorset.__iter__
Doing manual iteration is expensible. We rely on built in list iteration
whenever possible. The other case has to become a closure we cannot have a both
yield and return in the same function.
2014-04-30 16:56:23 -07:00
Pierre-Yves David
c6262025ca revset: prefetch an attribute in _generatorset.__iter__
Python's attribute lookup are expensible, lets do less of them.

This gives us a 7% speedup on this revset iteration (from 0.063403 to 0.059032)
2014-09-18 15:52:45 -07:00
Pierre-Yves David
a7bd255d53 revset: use subset & in bare p2()
This takes advantage of the `fullreposet` smartness with a nice
speedup. It's a similar speedup to `p1()` when a merge is in progress
(the non merge case is already lightning fast anyway.)
2014-09-17 11:00:03 -07:00
Pierre-Yves David
85eb5c83a9 revset: use subset & in bare p1()
This takes advantage of the `fullreposet` smartness and yields a nice
speedup.

revset #0: p1()
0) wall 0.003256 comb 0.010000 user 0.010000 sys 0.000000 (best of 527)
1) wall 0.000066 comb 0.000000 user 0.000000 sys 0.000000 (best of 23224)
2014-09-17 10:59:52 -07:00
Pierre-Yves David
8cb4d64b32 revset: use subset & in rev
This takes advantage of the `fullreposet` smartness and yields a nice
speedup.

revset #0: rev(25)
0) wall 0.005480 comb 0.000000 user 0.000000 sys 0.000000 (best of 305)
1) wall 0.000052 comb 0.000000 user 0.000000 sys 0.000000 (best of 21891)
2014-09-17 11:00:09 -07:00
Pierre-Yves David
375f152fed revset: use subset & in origin
This takes advantage of the `fullreposet` smartness.

revset #0: origin(tip)
0) wall 0.005353 comb 0.000000 user 0.000000 sys 0.000000 (best of 354)
1) wall 0.003080 comb 0.000000 user 0.000000 sys 0.000000 (best of 446)
2014-09-17 19:52:34 -07:00
Pierre-Yves David
fe68969345 revset: use subset & in follow
This takes advantage of the `fullreposet` smartness.


revset #0: follow(COPYING)
0) wall 0.002446 comb 0.000000 user 0.000000 sys 0.000000 (best of 735)
1) wall 0.000331 comb 0.000000 user 0.000000 sys 0.000000 (best of 5672)
2014-09-17 10:59:16 -07:00
Pierre-Yves David
a3297e9a12 revset: use subset & in filelog
This takes advantage of the `fullreposet` smartness.

revset #0: file(COPYING)
0) wall 3.179066 comb 3.180000 user 3.140000 sys 0.040000 (best of 3)
1) wall 2.723699 comb 2.730000 user 2.690000 sys 0.040000 (best of 4)
2014-09-17 10:58:50 -07:00
Pierre-Yves David
244ffda42c revset: use subset & in divergent
This takes advantage of the `fullreposet` smartness.

revset #0: divergent()
0) wall 0.002047 comb 0.000000 user 0.000000 sys 0.000000 (best of 813)
1) wall 0.000052 comb 0.000000 user 0.000000 sys 0.000000 (best of 22757)
2014-09-17 10:58:39 -07:00
Pierre-Yves David
4cc5660e43 revset: use subset & in bisect
This takes advantage of the `fullreposet` smartness.

revset #0: bisect(range)
0) wall 0.014007 comb 0.010000 user 0.010000 sys 0.000000 (best of 115)
1) wall 0.005556 comb 0.010000 user 0.010000 sys 0.000000 (best of 235)
2014-09-17 10:57:57 -07:00
Pierre-Yves David
35c1eba9e6 revset: use subset & in ancestorspec
This takes advantage of the `fullreposet` smartness.


revset #0: tip~25
0) wall 0.004800 comb 0.010000 user 0.010000 sys 0.000000 (best of 259)
1) wall 0.002475 comb 0.000000 user 0.000000 sys 0.000000 (best of 717)
2014-09-17 10:57:47 -07:00
Pierre-Yves David
25b1e1b399 revset: use subset & in bookmark
Speedup, Weeeeeee!

revset #0: bookmark()
0) wall 0.002240 comb 0.000000 user 0.000000 sys 0.000000 (best of 571)
1) wall 0.000132 comb 0.000000 user 0.000000 sys 0.000000 (best of 14059)
2014-09-17 19:57:09 -07:00
Pierre-Yves David
cefa7eaabc revset: use subset & in outgoing
This should give us the same benefit as elsewhere. Result is simpler (and
"faster").

Outgoing is dominated by the discovery so no benchmark is provided.
2014-09-17 10:59:40 -07:00
Pierre-Yves David
490d3a84ce revset: avoid in loop lookup in _generatorset._consumegen
Python lookups are slow, so do all lookup outside of the for loop.

This provide a small but still significant speedup:

revset #0: 0::
0) wall 0.063258 comb 0.060000 user 0.060000 sys 0.000000 (best of 100)
1) wall 0.057776 comb 0.050000 user 0.050000 sys 0.000000 (best of 100)
2014-04-30 16:56:48 -07:00
Pierre-Yves David
ae357027fd revset: reduce dict lookup in lazyset.__contains__
Avoid an extra dict lookup when we have to compute the value. No
visible performance impact but this shaves the yak a few extra
nanometers.
2014-04-25 14:51:24 -07:00
Pierre-Yves David
e291b5bdba revset: do less lookup during spanset.__contains__
Attribute lookup is slow in python. So this version is going to be a bit
faster. This does not have a visible impact since the rest of the stack is much
slower but this shaves the yak a few extra nanometers.

Moreover the new version is more readable so it worth doing this change for code
quality purpose.

This optimisation was approved by a core python dev.
2014-04-25 17:53:58 -07:00
Pierre-Yves David
477ee214de revset: fast implementation for fullreposet.__and__
"And" operation with something that contains the whole repo should be super
cheap. Check method docstring for details.

This provide massive boost to simple revset that use `subset & xxx`

revset #0: p1(20000)
0) wall 0.002447 comb 0.010000 user 0.010000 sys 0.000000 (best of 767)
1) wall 0.000529 comb 0.000000 user 0.000000 sys 0.000000 (best of 3947)

revset #1: p2(10000)
0) wall 0.002464 comb 0.000000 user 0.000000 sys 0.000000 (best of 913)
1) wall 0.000530 comb 0.000000 user 0.000000 sys 0.000000 (best of 4226)

No other regression spotted.

More performance improvements are expected in the future as more
revset predicate are converted to use `subset & xxx`

The relaxed way `fullreposet` handles "&" operation may cause some trouble for
people comparing smartset from different filter levels. I'm not sure such people
exist and we can improve that aspect in later patches.
2014-09-24 20:11:36 -07:00
Pierre-Yves David
acb7d8cae1 revset: turn spanset into a factory function
We rename the `spanset` class to `_spanset`. `spanset` is now a function that
builds either a `fullreposet` or a `_spanset` according to the argument passed.

At some point, we may force people to explicitly use the `fullreposet`
constructor, but the current approach makes it easier to ensure we use the new
class whenever possible and focus on the benefits of this class.
2014-09-18 13:04:02 -07:00
Pierre-Yves David
8febe1e995 revert: add a fullreposet class
Every revset evaluation starts from `subset = spanset(repo)` and a lot of
revset predicates build a `spansetrepo` for their internal needs.

`spanset` is a generic class that can handle any situation. As a result a lot
of operation between spanset result in an `orderedlazyset`, a safe object but
suboptimal in may situation.

So we introduce a `fullreposet` class where some of the operation will be
overwritten to produce more interesting results.
2014-04-29 19:06:15 -07:00
Matt Mackall
0e7a6163da merge with stable 2014-09-27 13:18:10 -05:00
Pierre-Yves David
537742ab10 revset: remove nullrev from the bookmark computation
Same as for other revset we sanitize the content of the set to be able to rely
on it more.
2014-09-17 19:56:59 -07:00
Pierre-Yves David
a06107e4f9 revset: unify code flow in bookmark
We refactor the code of the bookmark revset to have a single return. This will
allow us to sanitize the content of the set.
2014-09-17 10:58:25 -07:00
Pierre-Yves David
9cdb9e5a5d revset: remove invalid value in the origin set
Same as the parents related revsets, origin had some invalid value in the
computed set. We remove them.
2014-09-17 10:59:30 -07:00
Pierre-Yves David
5005f69963 revset: remove nullrev from set computed in parents()
The old code relied on the subset contents to get rid of invalid values. We would
like to be able to rely more on the computation in parents() so we filter out
the invalid value.
2014-09-17 19:49:26 -07:00
Pierre-Yves David
1601426b0b revset: refactor parents() into a single return point
Both paths are doing similar thing in the end. We refactor the function so that
the `ps` set is commonly used at the end.

This will end excluding `nullrev` from this set in a future patch
2014-09-17 19:44:03 -07:00
Pierre-Yves David
3e189cc195 revset: remove nullrev from set computed in p1() and p2()
The old code relied on the subset contents to get rid of invalid values. We would
like to be able to rely more on the computation in p1() and p2() so we filter out
the invalid value
2014-09-17 04:40:30 -07:00
Pierre-Yves David
d0e7545de8 revset: add an optimised baseset.__contains__ (issue4371)
The baseset class is based on a python list. This means that base.__contains__
was absolutely as crappy as list.__contains__. We now rely on __contains__ from
the underlying set.

This will avoid having to explicitly convert the baseset to a set (using
baseset.set()) whenever one want fast membership test.

Apparently there is already code that forgot to do such conversions since we
observe a massive speedup in some test.

revset #25: roots((0::) - (0::tip))
0) wall 2.079454 comb 2.080000 user 2.080000 sys 0.000000 (best of 5)
1) wall 0.132970 comb 0.130000 user 0.130000 sys 0.000000 (best of 65)

No regression is observed in benchmarks.

This change improve the issue4371 back to acceptable situation (but are still
slower than manual substraction)
2014-09-16 23:59:29 -07:00
Pierre-Yves David
27c652135f revset: document the choice made in __generatorset.__iter__
The method code looks a bit ugly but has good reasons to. We document them
to prevent naive refactoring in the future.
2014-09-16 23:42:41 -07:00
Pierre-Yves David
f7b33aee4f revset: stop using a baseset instead of a plain list in _revsbetween
The function internal code needs a list. Lets use a list.
2014-09-16 22:55:49 -07:00
Pierre-Yves David
10f312d751 revset: simplify orderedlazyset creation in spanset method
We can simply use the `self.isascending` value instead of more complex if/else
clause. This get the code simpler.

Benchmarks show no performances harmed in the process.
2014-09-16 23:47:34 -07:00
Pierre-Yves David
88ccbff938 revset: use spanset.isdescending in multiple simple places
We call the method directly instead of duplicating checks.

Benchmarks show no performances harmed in the process.
2014-09-16 23:37:03 -07:00
Pierre-Yves David
440efac9e4 revset: wider definition of ascending and descending for spanset
Before this patches, empty spanset were seen as neither ascending nor
descending. This is mathematically wrong and create some edges case. We put
`isascending` and `isdescending` back on track so we can use them to simplify
some of the spanset code.

Benchmarks show no performances harmed in the process.
2014-09-16 23:34:18 -07:00
Durham Goode
ce250e375a revset: lower weight for _intlist function
The histedit command uses a revset like:

(_intlist('1234\x001235')) and merge()

Previously the optimizer gave a weight of 1.5 to the _intlist side (1 for the
function, 0.5 for the string) which caused it to process the merge() side first.
This caused it to evaluate merge against every commit in the repo, which took
2.5 seconds on a large repo.

I changed the weight of _intlist to 0, since it's a trivial calculation, which
makes it process intlist first, which makes merge apply only to the revs in the
list. Which makes the revset take 0.15 seconds now. Cutting off 2.4 seconds off
our histedit performance.

>From the revset benchmark:
revset #25: (_intlist('20000\x0020001')) and merge()
0) obsolete feature not enabled but 54243 markers found!
! wall 0.036767 comb 0.040000 user 0.040000 sys 0.000000 (best of 100)
1) obsolete feature not enabled but 54243 markers found!
! wall 0.000198 comb 0.000000 user 0.000000 sys 0.000000 (best of 9084)
2014-09-12 14:21:18 -07:00
Durham Goode
79319b785d revset: make parents() O(number of parents)
Strip executes a revset like this:

max(parents(_intlist('1234\x001235')) - _intlist('1234\x001235'))

Previously the parents() revset would do 'subset & parents' which iterates over
each item in the subset and checks if it's in parents.  subset is usually the
entire repo (a spanset) so this takes a while.

Reversing the parameters to be 'parents & subset' means the operation becomes
O(number of parents) instead of O(size of repo). It also means the result gets
evaluated immediately (since parents isn't a lazy set), but I think this is a
win in most scenarios.

This shaves 0.3 seconds off strip (amend/histedit/rebase/etc) for large repositories.

revset #0: parents(20000)
0) obsolete feature not enabled but 54243 markers found!
! wall 0.006256 comb 0.010000 user 0.010000 sys 0.000000 (best of 289)
1) obsolete feature not enabled but 54243 markers found!
! wall 0.000391 comb 0.000000 user 0.000000 sys 0.000000 (best of 4323)
2014-09-12 15:00:51 -07:00
Durham Goode
9d2bd7f0b2 revset: make descendants() lazier
Previously descendants() would force the provided subset to become a set.  In
the case of revsets like '(%ld::) - (%ld)' (as used by histedit) this would
force the '- (%ld)' set to be evaluated, which produced a set containing every
commit in the repo (except %ld). This takes 0.6s on large repos.

This changes descendants to trust the subset to implement __contains__
efficiently, which improves the above revset to 0.16s. Shaving 0.4 seconds off
of histedit.

revset #27: (20000::) - (20000)
0) obsolete feature not enabled but 54243 markers found!
! wall 0.023640 comb 0.020000 user 0.020000 sys 0.000000 (best of 100)
1) obsolete feature not enabled but 54243 markers found!
! wall 0.019589 comb 0.020000 user 0.020000 sys 0.000000 (best of 100)

This commit removes the final revset related perf hotspot from histedit.
Combined with the previous two patches, they shave a little over 3 seconds off
histedit on large repos.
2014-09-12 16:21:13 -07:00
Michael O'Connor
306b55bcc9 revset: bookmark revset interprets 'literal:' prefix correctly (issue4329) 2014-08-11 23:45:08 -04:00
Gregory Szorc
27315bd014 revset: optimize baseset.__sub__ (issue4313)
f5a63a5506d2 regressed performance of baseset.__sub__ by introducing
a lazyset. This patch restores that lost performance by eagerly
evaluating baseset.__sub__ if the other set is a baseset.

revsetbenchmark.py results impacted by this change:

revset #6: roots(0::tip)
0) wall 2.923473 comb 2.920000 user 2.920000 sys 0.000000 (best of 4)
1) wall 0.077614 comb 0.080000 user 0.080000 sys 0.000000 (best of 100)

revset #23: roots((0:tip)::)
0) wall 2.875178 comb 2.880000 user 2.880000 sys 0.000000 (best of 4)
1) wall 0.154519 comb 0.150000 user 0.150000 sys 0.000000 (best of 61)

On the author's machine, this slowdown manifested during evaluation of
'roots(%ln::)' in phases.retractboundary after unbundling the Firefox
repository. Using `time hg unbundle firefox.hg` as a benchmark:

Before: 8:00
After:  4:28
Delta: -3:32

For reference, the subset and cs baseset instances impacted by this
change were of lengths 193634 and 193627, respectively.

Explicit test coverage of roots(%ln::), while similar to the existing
roots(0::tip) benchmark, has been added.
2014-07-24 12:12:12 -07:00
Matt Harbison
f0308c64dd revset: avoid a ValueError when 'only()' is given an empty set
This previously died in _revdescendants() taking the min() of the first set to
only(), when it was empty.  An empty second set already worked.  Likewise,
descendants() already handled an empty set.
2014-07-18 19:46:56 -04:00
Siddharth Agarwal
5801040e81 revset: remove no longer used _missingancestors revset
This was undocumented.
2014-07-12 00:37:08 -07:00
Siddharth Agarwal
9ea47f6848 revset: replace _missingancestors optimization with only revset
(::a - ::b) is equivalent to only(a, b).
2014-07-12 00:31:36 -07:00
Matt Mackall
5157edb3f5 revset: maintain ordering when subtracting from a baseset (issue4289) 2014-07-14 17:55:31 -05:00
Pierre-Yves David
0a422cd2f2 revset: cosmetic changes in spanset range comparison
We use the python syntax for range comparison: `a < x < c`. This is shorter,
more readable and less error prone. This comparison escaped the cleanup make in
166d6dde9310
2014-04-28 15:14:11 -07:00
Pierre-Yves David
f9553b0f97 revset: drop spanset._contained
All its users inlined it for performance reasons.
(See fcccbf073394 and 166d6dde9310)
2014-04-25 23:38:24 -07:00
Pierre-Yves David
e654410fbc revset: directly use __contains__ instead of a lambda
We get rid of lambda in a bunch of other place. This is equivalent and much
faster. (no new timing as this is the same change as three other changesets)
2014-05-01 14:07:04 -07:00
Pierre-Yves David
b3f19fad6e orderedlazyset: directly use __contains__ instead of a lambda
We apply the same speedup as in spanset, getting rid of the useless lambda.
(No new timing, as this is the very same change)
2014-05-01 12:15:28 -07:00
Pierre-Yves David
68eca34f8d lazyset: directly use __contains__ instead of a lambda
We apply the same speedup as in spanset, getting rid of the useless lambda.
(No new timing, as this is the very same change)
2014-05-01 12:15:00 -07:00
Pierre-Yves David
7a5b8cbf4b spanset: directly use __contains__ instead of a lambda
Spanset are massively used in revset. First because the initial subset itself is
a repo wide spanset. We speed up the __and__ operation by getting rid of a
gratuitous lambda call. A more long terms solution would be to:

1. speed up operation between spansets,
2. have a special smartset for `all` revisions.

In the mean time, this is a very simple fix that buyback some of the performance
regression.

Below is performance benchmark for trival `and` operation between two spansets.
(Run on an unspecified fairly large repository.)

revset tip:0
2.9.2)  wall 0.282543 comb 0.280000 user 0.260000 sys 0.020000 (best of 35)
before) wall 0.819181 comb 0.820000 user 0.820000 sys 0.000000 (best of 12)
after)  wall 0.645358 comb 0.650000 user 0.650000 sys 0.000000 (best of 16)

Proof of concept implementation of an `all` smartset brings this to 0.10 but it's
too invasive for stable.
2014-04-26 00:38:02 -07:00
Pierre-Yves David
a4f88556f4 revset: also inline spanset._contained in __len__
For consistency with what happen in `__contains__`, we inline the range test
into `__len__` too.
2014-04-25 18:00:07 -07:00
Pierre-Yves David
b42c62324c revset: inline spanset containment check (fix perf regression)
Calling a function is super expensive in python. We inline the trivial range
comparison to get back to more sensible performance on common revset operation.

Benchmark result below:

Revision mapping:
0) bced32a3fd6c 2.9.2 release
1) 2ab64f462d81 current @
2) This revision


revset #0: public()
0) wall 0.010890 comb 0.010000 user 0.010000 sys 0.000000 (best of 201)
1) wall 0.012109 comb 0.010000 user 0.010000 sys 0.000000 (best of 199)
2) wall 0.012211 comb 0.020000 user 0.020000 sys 0.000000 (best of 197)

revset #1: :10000 and public()
0) wall 0.007141 comb 0.010000 user 0.010000 sys 0.000000 (best of 361)
1) wall 0.014139 comb 0.010000 user 0.010000 sys 0.000000 (best of 186)
2) wall 0.008334 comb 0.010000 user 0.010000 sys 0.000000 (best of 308)

revset #2: draft()
0) wall 0.009610 comb 0.010000 user 0.010000 sys 0.000000 (best of 279)
1) wall 0.010942 comb 0.010000 user 0.010000 sys 0.000000 (best of 243)
2) wall 0.011036 comb 0.010000 user 0.010000 sys 0.000000 (best of 239)

revset #3: :10000 and draft()
0) wall 0.006852 comb 0.010000 user 0.010000 sys 0.000000 (best of 383)
1) wall 0.014641 comb 0.010000 user 0.010000 sys 0.000000 (best of 183)
2) wall 0.008314 comb 0.010000 user 0.010000 sys 0.000000 (best of 299)

We can see this changeset gains back the regression for `and` operation on
spanset.  We are still a bit slowerfor the `public()` and `draft()`. Predicates
not touched by this changeset.
2014-04-28 15:15:36 -07:00
Pierre-Yves David
4274fa0b04 revset: fix revision filtering in spanset.contains (regression)
The argument is `x` but the variable tested for filtering is `rev`. `rev`
happens to be a revset methods, ... never part of the filtered revs. This
method is now using `rev` for everything.
2014-04-28 16:28:52 -07:00
Greg Hurrell
89c96d28b3 help: clarify distinction among contains/file/filelog
For a Mercurial new-comer, the distinction between `contains(x)`,
`file(x)`, and `filelog(x)` in the "revsets" help page may not be
obvious. This commit tries to make things more obvious (text based on
an explanation from Matt in an FB group thread).
2014-04-28 15:09:23 -07:00
Wagner Bruna
0db6df4ed7 revset, i18n: add translator comment to "only" 2014-04-22 10:12:13 -03:00
Mads Kiilerich
0e8795ccd6 spelling: fixes from spell checker 2014-04-13 19:01:00 +02:00
Mads Kiilerich
b117005b7c revlog: use context ancestor instead of changelog ancestor
We want to move in this direction.
2014-04-07 23:17:51 +02:00
Durham Goode
eac8ba4613 revset: improve roots revset performance
Previously we would iterate over every item in the subset, checking if it was in
the provided args. This often meant iterating over every rev in the repo.

Now we iterate over the args provided, checking if they exist in the subset.
On a large repo this brings setting phase boundaries (which use this revset
roots(X:: - X::Y)) down from 0.8 seconds to 0.4 seconds.

The "roots((tip~100::) - (tip~100::tip))" revset in revsetbenchmarks shows it
going from 0.12s to 0.10s, so we should be able to catch regressions here in the
future.

This actually introduces a regression in 'roots(all())' (0.2s to 0.26s) since
we're now using spansets, which are slightly slower to do containment checks on.
I believe this trade off is worth it, since it makes the revset O(number of
args) instead of O(size of repo).
2014-03-31 16:03:34 -07:00
Durham Goode
13db32b575 revset: improve _descendants performance
Previously revset._descendants would iterate over the entire subset (which is
often the entire repo) and test if each rev was in the descendants list. This is
really slow on large repos (3+ seconds).

Now we iterate over the descendants and test if they're in the subset.
This affects advancing and retracting the phase boundary (3.5 seconds down to
0.8 seconds, which is even faster than it was in 2.9). Also affects commands
that move the phase boundary (commit and rebase, presumably).

The new revsetbenchmark indicates an improvement from 0.2 to 0.12 seconds. So
future revset changes should be able to notice regressions.

I removed a bad test. It was recently added and tested '1:: and reverse(all())',
which has an amibiguous output direction.  Previously it printed in reverse order,
because we iterated over the subset (the reverse part). Now it prints in normal
order because we iterate over the 1:: . Since the revset itself doesn't imply an
order, I removed the test.
2014-03-25 14:10:01 -07:00
Pierre-Yves David
3a1c934d6a revset: raise ValueError when calling min or max on empty smartset
min([]) raise a ValueError, we do the same thing in smartset.min() and
smartset.max() for the sake of consistency.

The min/amax test are greatly improved in the process to prevent this familly
of regression
2014-03-28 17:00:13 -07:00
Pierre-Yves David
4e0cea0c36 _addset: add a __len__ method
Back in the time where repo.revs(...) returned a list, calling `len(...)` on the
result was quite common. We reinstall this on _addset.

There is absolutely no easy way to test this from the command line. The commands
using this in the evolve extension will eventually land into core.
2014-03-20 18:55:28 -07:00
Durham Goode
dd74d4bd47 revset: fix generatorset race condition
If two things were iterating over a generatorset at the same time, they could
miss out on the things the other was generating, resulting in incomplete
results. This fixes it by making it possible for two things to iterate at once,
by always checking the _genlist at the beginning of each iteration.

I was only able to repro it with pending changes from my other commits, but they
aren't ready yet. So I'm unable to add a test for now.
2014-03-25 16:10:07 -07:00
Matt Mackall
b465bcd596 merge with stable 2014-03-25 16:17:16 -05:00
Gregory Szorc
2e930ae769 revset: improve performance of _generatorset.__contains__ (issue 4201)
_generatorset.__contains__ and __contains__ from child classes were
calling into __iter__ to look for values. Since all
previously-encountered values from the generator were cached and checked
in __contains__ before this iteration, __contains__ was effectively
performing iteration busy work which could lead to an explosion of
redundant work.

This patch changes __contains__ to be more intelligent. Instead of
looking at all values via __iter__, __contains__ will instead go
straight to "new" values from the underlying generator.

On a clone of the Firefox repository with around 200,000 changesets,
this patch decreases the execution time of the revset '::(200067)::'
from ~100s to ~4s on the author's machine. Rebase operations (which use
the aforementioned revset), speed up accordingly.
2014-03-24 20:00:18 -07:00
Matt Harbison
60d20455df revset: document the regular expression support for tag(name)
This has been supported since 0041ea008c64, in 2.3.
2014-03-24 21:27:40 -04:00
Matt Mackall
4436b1c4a4 revset: try to handle hyphenated symbols if lookup callback is available
Formerly an expression like "2.4-rc::" was tokenized as 2.4|-|rc|::.
This allows dashes in symbols iff the whole symbol-like string can be
looked up. Otherwise, it's tokenized as a series of symbols and
operators.

No attempt is made to accept dashed symbols inside larger symbol-like
string, for instance foo-bar or bar-baz inside foo-bar-baz.
2014-03-18 17:54:42 -05:00
Matt Mackall
a9a943eddd revset: pass a lookup function to the tokenizer 2014-03-18 17:19:44 -05:00
Lucas Moscovicz
1ff08e4b20 revset: changed minrev and maxrev implementations to use ordered sets
Performance Benchmarking:

0) max(tip:0)
1) min(0:tip)
2) min(0::)

c6d901b5cf89 (2.9.1 release)

    0) ! wall 0.005699 comb 0.000000 user 0.000000 sys 0.000000 (best of 450)
    1) ! wall 0.005414 comb 0.010000 user 0.010000 sys 0.000000 (best of 493)
    2) ! wall 0.025951 comb 0.030000 user 0.030000 sys 0.000000 (best of 107)

a9da3f4c0086 (public tip at submission time)

    0) ! wall 0.015177 comb 0.020000 user 0.020000 sys 0.000000 (best of 175)
    1) ! wall 0.014779 comb 0.010000 user 0.010000 sys 0.000000 (best of 189)
    2) ! wall 12.345179 comb 12.350000 user 12.350000 sys 0.000000 (best of 3)

Current patches:

    0) ! wall 0.001911 comb 0.000000 user 0.000000 sys 0.000000 (best of 1357)
    1) ! wall 0.001943 comb 0.010000 user 0.010000 sys 0.000000 (best of 1406)
    2) ! wall 0.000405 comb 0.000000 user 0.000000 sys 0.000000 (best of 6761)
2014-02-18 11:35:03 -08:00
Lucas Moscovicz
3bb3a9b599 revset: changed addset to extend _orderedsetmixin
Now _addset can use the lazy min and max implementation.
2014-03-14 14:43:44 -07:00
Pierre-Yves David
5b4ec0c02e revset: add a default argument for baseset.__init__
We are now able to create empty baseset using `baseset()` as we are able to
create empty list with `list()`.
2014-03-14 11:41:26 -07:00
Lucas Moscovicz
b693f7e6e2 revset: changed orderedlazyset to also extend _orderedsetmixin
Now orderedlazyset can use the lazy min and max implementation.
2014-03-13 11:36:45 -07:00
Lucas Moscovicz
6cf940b8a2 revset: changed spanset to extend _orderedsetmixin
Now spanset can use the lazy min and max methods implementation.
2014-03-13 11:36:11 -07:00
Lucas Moscovicz
732d8995dd revset: added _orderedsetmixin class
This class has utility methods for any ordered class to get the min and the
max values.
2014-03-12 16:40:18 -07:00
Lucas Moscovicz
829c2686af revset: added min and max methods to baseset and lazyset
This classes have no particular order so they rely on python min() and max()
implementation. This methods will be implemented in every smartset class in
future patches. For other classes there are lazy implementations that can be
made for this methods.
2014-02-19 09:28:17 -08:00
Pierre-Yves David
74abf98daf revset: add documentation and comment for _generatorset
(clean up some old irrelevant comment in the process)
2014-03-14 10:57:04 -07:00
Pierre-Yves David
170d61865e revset: add some documentation for lazyset 2014-03-14 10:55:03 -07:00
Lucas Moscovicz
6f3e54ea87 revset: added documentation and comment for spanset class 2014-03-14 10:59:51 -07:00
Lucas Moscovicz
432476d8c0 revset: changed smartset methods to return ordered addsets
Now when adding two structures that are ordered, they are wrapped into an
_addset and they get added lazily while keeping the order.
2014-03-11 17:25:53 -07:00
Lucas Moscovicz
dd9f8534d9 revset: added isascending and isdescending methods to _addset
This methods are intended to duck-type baseset, so we will still have _addset
as a private class but now we can return it without wrapping it into an
orderedlazyset or a lazyset.

These were the last methods to add for smartset compatibility.
2014-03-14 10:24:09 -07:00
Lucas Moscovicz
c5a9f97171 revset: added __add__ method to _addset
This method is intended to duck-type baseset, so we will still have _addset as a
private class but we will be able to return it without wrapping it into an
orderedlazyset or a lazyset.
2014-03-14 10:23:54 -07:00
Lucas Moscovicz
a79e6ad5a0 revset: added __sub__ mehtod to _addset
This method is intended to duck-type baseset, so we will still have _addset as a
private class but now will be able to return it without wrapping it into an
orderedlazyset or a lazyset.
2014-03-14 10:22:51 -07:00
Lucas Moscovicz
02e069f77d revset: added __and__ method to _addset
This method is intended to duck-type baseset, so we will still have _addset as a
private class but  we will be able to return it without wrapping it into an
orderedlazyset or a lazyset.
2014-03-14 10:22:29 -07:00
Lucas Moscovicz
73a28cdab8 revset: added ascending and descending methods to _addset
This methods are intended to duck-type baseset, so we will still have _addset
as a private class but will be able return it without wrapping it into an
orderedlazyset or a lazyset.
2014-03-14 10:21:56 -07:00
Lucas Moscovicz
e603775f94 revset: added filter method to _addset
This method is intended to duck-type baseset, so we will still have _addset
as a private class but we will be able return it without wrapping it into an
orderedlazyset or a lazyset.
2014-03-13 19:12:36 -07:00
Lucas Moscovicz
8adde22fdb revset: added comments to all methods needed to duck-type from baseset
All this methods are required to duck-type for any class that works as a smart
set.
2014-03-14 09:18:14 -07:00
Lucas Moscovicz
23a1573060 revset: use more explicit argument names for baseset methods
Use other instead of x and condition instead of l
2014-03-14 10:10:18 -07:00
Lucas Moscovicz
1e32ffe0b9 revset: added isascending and isdescending methods to smartset classes
This methods state if the class is sorted in an ascending or descending order

We need this to implement methods based on order on smartset classes in order
to be able to create new objects with a given order.

We cannot just rely on a simple boolean since unordered set are neither
ascending nor descending.
2014-03-11 17:09:23 -07:00
Lucas Moscovicz
8004a27cbf revset: added sort method in addset
We need this method to duck-type generatorset since this class is not going to
be used outside revset.py and we don't need to duck-type baseset.

This sort method will only do something when the addset is not already sorted
or is not sorted in the way we want it to be.
2014-03-11 17:03:43 -07:00
Lucas Moscovicz
62c7bb9117 revset: added reverse method to addset
This method is needed to duck type generatorset.
2014-03-13 18:57:30 -07:00
Lucas Moscovicz
e5f79a44be revset: changed _iterator() method on addset to work with a given order
If the two collections are in ascending order, yield their values in an
ordered way by iterating both at the same time and picking the values to
yield.
2014-03-13 13:29:04 -07:00
Lucas Moscovicz
f2b80f803a revset: changed _iterator() in addset to use the generated list when available
Now when all the elements have been generated, the iterator will just use the
generated list instead of going through all the elements again.
2014-03-13 14:51:04 -07:00
Lucas Moscovicz
1a5e79571b revset: added cached generated list to addset
This way when all the values have been generated the list can be sorted
without having to generate them all again.
2014-03-11 16:59:42 -07:00
Lucas Moscovicz
67d42c8519 revset: changed sort method to use native sort implementation of smartsets
When sort is done by revision or reversed revision number it can just call
sort on the set and doesn't have to iterate it all over again.
2014-03-13 17:15:21 -07:00
Lucas Moscovicz
6da2a5ca22 revset: fixed sorting issue with spanset
When a spanset was being sorted it didn't take into account it's current
state (ascending or descending) and it reversed itself everytime the reverse
parameter was True.

This is not yet used but it will be as soon as the sort revset is changed to
directly use the structures sort method.
2014-03-13 17:16:58 -07:00
Lucas Moscovicz
edbf51ad8f revset: added __nonzero__ method to spanset class
Implemented it in a lazy way, just look for the first non-filtered revision
and return True if there's any revision at all.
2014-03-14 09:07:59 -07:00
Lucas Moscovicz
04e9ab0a9b revset: optimized sort method in lazyset class
We are taking advantage of the smartset classes sort method when it exists and
converting the set to a baseset otherwise.
2014-03-06 09:41:47 -08:00
Durham Goode
f906635299 revset: improve head revset performance
Previously the head() revset would iterate over every item in the subset and
check if it was a head.  Since the subset is often the entire repo, this was
slow on large repos. Now we iterate over each item in the head list and check if
it's in the subset, which results in much less work.

hg log -r 'head()' on a large repo:
Before: 0.95s
After: 0.28s
2014-03-13 13:47:21 -07:00
Lucas Moscovicz
36702af6f9 revset: added ascending attribute to addset class
In case both collections are in an ascending/descending order then we will be
able to iterate them lazily while keeping the order.
2014-03-11 16:52:15 -07:00
Lucas Moscovicz
7da57d658a revset: added set method to addset to duck type generatorset
Since this class is only going to be used inside revset.py (it does not duck
type baseset) it needs to duck type only a few more methods for the next
patches.
2014-03-10 10:49:04 -07:00
Matt Mackall
064d711c69 revsets: backout f497f83593d8 due to performance regressions 2014-03-13 14:34:32 -05:00
Lucas Moscovicz
efb319fb76 revset: made addset a private class
This class is not supposed to be used outside revset.py since it only
wraps content that is used by baseset typed classes.

It only gets created by revset operations or private methods.
2014-03-12 17:20:26 -07:00
Lucas Moscovicz
a50567190d revset: made descgeneratorset a private class
This class is not supposed to be used outside revset.py since it only
wraps content that is used by baseset typed classes.

It only gets created by revset operations or private methods.
2014-03-12 17:19:46 -07:00
Lucas Moscovicz
e6b1cc49b9 revset: made ascgeneratorset a private class
This class is not supposed to be used outside revset.py since it only
wraps content that is used by baseset typed classes.

It only gets created by revset operations or private methods.
2014-03-12 17:18:54 -07:00
Lucas Moscovicz
7e33d4c691 revset: made generatorset a private class
This class are not supposed to be used outside revset.py since it only
wraps content that is used by baseset typed classes.

It only gets created by revset operations or private methods.
2014-03-12 17:07:38 -07:00
Lucas Moscovicz
2c2b32444e revset: added sort methods to generatorsets
Method needed to propagate sort calls amongst lazy structures.
The generated list (stored in the object) is sorted.

If the generated list did not contain all elements from the generator, we
take care of that before sorting the list.
2014-02-24 16:36:17 -08:00
Lucas Moscovicz
9db776218f revset: changed __add__ methods on lazy sets to return addsets (issue4191)
Performance Benchmarking:

$ hg --time log --graph --style compact --limit 6 -r 'sort((::. or bookmark()
or heads(public())), "-rev")'
time: real 1.540 secs (user 1.510+0.000 sys 0.020+0.000)

$ ./hg --time log --graph --style compact --limit 6 -r 'sort((::. or
bookmark() or heads(public())), "-rev")'
time: real 1.240 secs (user 1.190+0.000 sys 0.040+0.010)
2014-03-07 14:06:49 -08:00
Lucas Moscovicz
82e3bb4e2c revset: added addset class with its basic methods
This class addresses the problem of losing performance on the __contains__
method when adding two smart structures with fast membership testing.
2014-03-07 13:48:31 -08:00
Lucas Moscovicz
a47624e9b5 revset: changed _children method to use lazy structures 2014-02-11 14:03:43 -08:00
Lucas Moscovicz
c7b531ba29 revset: changed descendants revset to use lazy generators
Performance Benchmarking:

$ time hg log -qr "0:: and 0:5"
...

real  0m3.665s
user  0m3.364s
sys 0m0.289s

$ time ./hg log -qr "0:: and 0:5"
...

real  0m0.492s
user  0m0.394s
sys 0m0.097s
2014-02-10 12:26:45 -08:00
Lucas Moscovicz
ead9ef7efc revset: optimized _revancestors method based on order of revisions
If the revisions for which the ancestors are required are in descending order,
it lazily loads them into a heap to be able to yield values faster.
2014-02-07 13:44:57 -08:00
Lucas Moscovicz
8456e8d71a revset: changed ancestors revset to return lazy generators
This will not improve revsets like "::tip" but will do when that gets
intersected or substracted with another revset.

Performance Benchmarking:

$ time hg log -qr "draft() and ::tip"
...

real  0m3.961s
user  0m3.640s
sys 0m0.313s

$ time ./hg log -qr "draft() and ::tip"
...

real  0m1.080s
user  0m0.987s
sys 0m0.083s
2014-02-07 10:32:02 -08:00
Lucas Moscovicz
4a4c0782a7 revset: changed methods in spanset to return ordered sets
Now __sub__ and __and__ can smartly return ordered lazysets.
2014-02-18 13:07:08 -08:00
Lucas Moscovicz
82070b57ca revset: added sort method to orderedlazyset 2014-02-25 10:36:23 -08:00
Lucas Moscovicz
9ade74466e revset: added order methods to lazyset classes
This will allow revsets to ask for an ordered set when possible to be able to
work lazily with it.
2014-02-07 08:44:18 -08:00
Lucas Moscovicz
e87d3ac6ae revset: added ordered generatorset classes with __contains__ method
They stop iterating as soon as they go past the value they are looking for,
so, for values not in the generator they return faster.
2014-02-27 17:27:03 -08:00
Lucas Moscovicz
d710c5103e revset: changed generatorset code to remove unnecesary function call
Removed _nextitem() method, now __iter__ has that logic and __contains__ uses
__iter__ to check for membership.
2014-03-03 12:54:46 -08:00
Durham Goode
f2e7078d1a revset: add 'only' revset
Adds a only() revset that has two forms:

only(<set>) is equivalent to "::<set> - ::(heads() - heads(<set>::))"

only(<include>,<exclude>) is equivalent to "::<include> - ::<exclude>"

On a large repo, this implementation can process/traverse 50,000 revs in 0.7
seconds, versus 4.2 seconds using "::<include> - ::<exclude>".

This is useful for performing histedits on your branch:
hg histedit -r 'first(only(.))'

Or lifting branch foo off of branch bar:
hg rebase -d @ -s 'only(foo, bar)'

Or a variety of other uses.
2013-11-16 08:57:08 -08:00
Lucas Moscovicz
fbd41fa2f4 revset: added basic operators to orderedlazyset
Now __and__ and __sub__ return orderedlazyset.
2014-02-06 17:42:08 -08:00
Lucas Moscovicz
66c7004b8c revset: changed revset code to use filter method
Revset methods now use the filter code to apply a condition.
2014-02-06 09:28:41 -08:00
Lucas Moscovicz
e70d62798f revset: added filter method to revset classes
This method will replace the creation of lazysets inside the revset methods.
Instead, the classes that handle lazy structures will create them based on
their current order.
2014-02-06 17:18:11 -08:00
Lucas Moscovicz
2e8fa99be8 revset: added orderedlazyset class 2014-02-05 15:24:08 -08:00
Lucas Moscovicz
5d74d40ff4 revset: changed spanset __add__ implementation to work lazily
$ time hg log -qr "first(0:tip or draft())"
...

real  0m1.032s
user  0m0.841s
sys 0m0.179s

$ time ./hg log -qr "first(0:tip or draft())"
...

real  0m0.378s
user  0m0.291s
sys 0m0.085s
2014-02-13 09:18:16 -08:00
Lucas Moscovicz
3c92337f5c revset: changed lazyset __add__ implementation to work lazily
Performance Benchmarking:

$ time hg log -qr "first(author(mpm) or branch(default))"
0:3a6a38229d41

real  0m3.875s
user  0m3.818s
sys 0m0.051s

$ time ./hg log -qr "first(author(mpm) or branch(default))"
0:3a6a38229d41

real  0m0.213s
user  0m0.174s
sys 0m0.038s
2014-02-13 09:00:25 -08:00
Lucas Moscovicz
df2d5bd9ed revset: added _hexlist method to replace _list for %ln
Now %ln expression goes through _hexlist and doesn't do any unnecesary
processing anymore.
2014-02-26 17:15:55 -08:00
Lucas Moscovicz
d6c47fdc4c revset: added _intlist method to replace _list for %ld
Now %ld expression goes through _intlist and doesn't do any unnecesary
processing anymore.
2014-02-26 12:36:36 -08:00
Lucas Moscovicz
59ef037f26 revset: added __nonzero__ method to lazyset
Now it doesn't have to go through all the set and can return lazily as soon as
it finds one element.
2014-02-20 10:15:38 -08:00
Lucas Moscovicz
b6ae0f9720 revset: added cached generated list on generatorset
This allows to iterate the generatorset more than once.
2014-02-12 18:45:49 -08:00
Lucas Moscovicz
e97b3cbf9e revset: fixed bug where log -f was taking too long to return 2014-02-21 13:16:17 -08:00
Lucas Moscovicz
bee2c6a618 revset: added generatorset class with cached __contains__ method 2014-02-05 15:23:11 -08:00
Lucas Moscovicz
cf5a2af3df revset: changed last implementation to use lazy classes
Instead of using getitem just reverse the revision list and get the first
'lim' elements. With classes like spanset which are easily reversible this
will work faster.

Performance Benchmarking:

$ time hg log -qr "last(all())"
...

real  0m0.569s
user  0m0.447s
sys 0m0.122s

$ time ./hg log -qr "last(all())"
...

real  0m0.215s
user  0m0.150s
sys 0m0.063s
2014-02-19 12:56:41 -08:00
Lucas Moscovicz
131799c6de revset: changed mfunc and getset to work with old style revset methods
Now extensions shouldn't break when adding new revsets.
2014-02-18 15:54:46 -08:00