##// END OF EJS Templates
revset: optimize "draft() & ::x" pattern...
Jun Wu -
r34067:c6c8a52e default
parent child Browse files
Show More
@@ -75,27 +75,49 b' def _walkrevtree(pfunc, revs, startdepth'
75 if prev != node.nullrev:
75 if prev != node.nullrev:
76 heapq.heappush(pendingheap, (heapsign * prev, pdepth))
76 heapq.heappush(pendingheap, (heapsign * prev, pdepth))
77
77
78 def _genrevancestors(repo, revs, followfirst, startdepth, stopdepth):
78 def _genrevancestors(repo, revs, followfirst, startdepth, stopdepth, cutfunc):
79 if followfirst:
79 if followfirst:
80 cut = 1
80 cut = 1
81 else:
81 else:
82 cut = None
82 cut = None
83 cl = repo.changelog
83 cl = repo.changelog
84 def pfunc(rev):
84 def plainpfunc(rev):
85 try:
85 try:
86 return cl.parentrevs(rev)[:cut]
86 return cl.parentrevs(rev)[:cut]
87 except error.WdirUnsupported:
87 except error.WdirUnsupported:
88 return (pctx.rev() for pctx in repo[rev].parents()[:cut])
88 return (pctx.rev() for pctx in repo[rev].parents()[:cut])
89 if cutfunc is None:
90 pfunc = plainpfunc
91 else:
92 pfunc = lambda rev: [r for r in plainpfunc(rev) if not cutfunc(r)]
93 revs = revs.filter(lambda rev: not cutfunc(rev))
89 return _walkrevtree(pfunc, revs, startdepth, stopdepth, reverse=True)
94 return _walkrevtree(pfunc, revs, startdepth, stopdepth, reverse=True)
90
95
91 def revancestors(repo, revs, followfirst, startdepth=None, stopdepth=None):
96 def revancestors(repo, revs, followfirst=False, startdepth=None,
97 stopdepth=None, cutfunc=None):
92 """Like revlog.ancestors(), but supports additional options, includes
98 """Like revlog.ancestors(), but supports additional options, includes
93 the given revs themselves, and returns a smartset
99 the given revs themselves, and returns a smartset
94
100
95 Scan ends at the stopdepth (exlusive) if specified. Revisions found
101 Scan ends at the stopdepth (exlusive) if specified. Revisions found
96 earlier than the startdepth are omitted.
102 earlier than the startdepth are omitted.
103
104 If cutfunc is provided, it will be used to cut the traversal of the DAG.
105 When cutfunc(X) returns True, the DAG traversal stops - revision X and
106 X's ancestors in the traversal path will be skipped. This could be an
107 optimization sometimes.
108
109 Note: if Y is an ancestor of X, cutfunc(X) returning True does not
110 necessarily mean Y will also be cut. Usually cutfunc(Y) also wants to
111 return True in this case. For example,
112
113 D # revancestors(repo, D, cutfunc=lambda rev: rev == B)
114 |\ # will include "A", because the path D -> C -> A was not cut.
115 B C # If "B" gets cut, "A" might want to be cut too.
116 |/
117 A
97 """
118 """
98 gen = _genrevancestors(repo, revs, followfirst, startdepth, stopdepth)
119 gen = _genrevancestors(repo, revs, followfirst, startdepth, stopdepth,
120 cutfunc)
99 return generatorset(gen, iterasc=False)
121 return generatorset(gen, iterasc=False)
100
122
101 def _genrevdescendants(repo, revs, followfirst):
123 def _genrevdescendants(repo, revs, followfirst):
@@ -1577,6 +1577,37 b' def _notpublic(repo, subset, x):'
1577 getargs(x, 0, 0, "_notpublic takes no arguments")
1577 getargs(x, 0, 0, "_notpublic takes no arguments")
1578 return _phase(repo, subset, phases.draft, phases.secret)
1578 return _phase(repo, subset, phases.draft, phases.secret)
1579
1579
1580 # for internal use
1581 @predicate('_phaseandancestors(phasename, set)', safe=True)
1582 def _phaseandancestors(repo, subset, x):
1583 # equivalent to (phasename() & ancestors(set)) but more efficient
1584 # phasename could be one of 'draft', 'secret', or '_notpublic'
1585 args = getargs(x, 2, 2, "_phaseandancestors requires two arguments")
1586 phasename = getsymbol(args[0])
1587 s = getset(repo, fullreposet(repo), args[1])
1588
1589 draft = phases.draft
1590 secret = phases.secret
1591 phasenamemap = {
1592 '_notpublic': draft,
1593 'draft': draft, # follow secret's ancestors
1594 'secret': secret,
1595 }
1596 if phasename not in phasenamemap:
1597 raise error.ParseError('%r is not a valid phasename' % phasename)
1598
1599 minimalphase = phasenamemap[phasename]
1600 getphase = repo._phasecache.phase
1601
1602 def cutfunc(rev):
1603 return getphase(repo, rev) < minimalphase
1604
1605 revs = dagop.revancestors(repo, s, cutfunc=cutfunc)
1606
1607 if phasename == 'draft': # need to remove secret changesets
1608 revs = revs.filter(lambda r: getphase(repo, r) == draft)
1609 return subset & revs
1610
1580 @predicate('public()', safe=True)
1611 @predicate('public()', safe=True)
1581 def public(repo, subset, x):
1612 def public(repo, subset, x):
1582 """Changeset in public phase."""
1613 """Changeset in public phase."""
@@ -369,6 +369,11 b' def _optimize(x, small):'
369 wb, tb = _optimize(x[2], True)
369 wb, tb = _optimize(x[2], True)
370 w = min(wa, wb)
370 w = min(wa, wb)
371
371
372 # (draft/secret/_notpublic() & ::x) have a fast path
373 m = _match('_() & ancestors(_)', ('and', ta, tb))
374 if m and getsymbol(m[1]) in {'draft', 'secret', '_notpublic'}:
375 return w, _build('_phaseandancestors(_, _)', m[1], m[2])
376
372 # (::x and not ::y)/(not ::y and ::x) have a fast path
377 # (::x and not ::y)/(not ::y and ::x) have a fast path
373 m = _matchonly(ta, tb) or _matchonly(tb, ta)
378 m = _matchonly(ta, tb) or _matchonly(tb, ta)
374 if m:
379 if m:
@@ -4321,3 +4321,147 b' Test obsstore related revsets'
4321
4321
4322 $ hg log -r 'successors(B+A)-contentdivergent()-obsolete()' -T '{desc}\n'
4322 $ hg log -r 'successors(B+A)-contentdivergent()-obsolete()' -T '{desc}\n'
4323 Z
4323 Z
4324
4325 Test `draft() & ::x` optimization
4326
4327 $ hg init $TESTTMP/repo2
4328 $ cd $TESTTMP/repo2
4329 $ hg debugdrawdag <<'EOS'
4330 > P5 S1
4331 > | |
4332 > S2 | D3
4333 > \|/
4334 > P4
4335 > |
4336 > P3 D2
4337 > | |
4338 > P2 D1
4339 > |/
4340 > P1
4341 > |
4342 > P0
4343 > EOS
4344 $ hg phase --public -r P5
4345 $ hg phase --force --secret -r S1+S2
4346 $ hg log -G -T '{rev} {desc} {phase}' -r 'sort(all(), topo, topo.firstbranch=P5)'
4347 o 8 P5 public
4348 |
4349 | o 10 S1 secret
4350 | |
4351 | o 7 D3 draft
4352 |/
4353 | o 9 S2 secret
4354 |/
4355 o 6 P4 public
4356 |
4357 o 5 P3 public
4358 |
4359 o 3 P2 public
4360 |
4361 | o 4 D2 draft
4362 | |
4363 | o 2 D1 draft
4364 |/
4365 o 1 P1 public
4366 |
4367 o 0 P0 public
4368
4369 $ hg debugrevspec --verify -p analyzed -p optimized 'draft() & ::(((S1+D1+P5)-D3)+S2)'
4370 * analyzed:
4371 (and
4372 (func
4373 ('symbol', 'draft')
4374 None)
4375 (func
4376 ('symbol', 'ancestors')
4377 (or
4378 (list
4379 (and
4380 (or
4381 (list
4382 ('symbol', 'S1')
4383 ('symbol', 'D1')
4384 ('symbol', 'P5')))
4385 (not
4386 ('symbol', 'D3')))
4387 ('symbol', 'S2')))))
4388 * optimized:
4389 (func
4390 ('symbol', '_phaseandancestors')
4391 (list
4392 ('symbol', 'draft')
4393 (or
4394 (list
4395 (difference
4396 (func
4397 ('symbol', '_list')
4398 ('string', 'S1\x00D1\x00P5'))
4399 ('symbol', 'D3'))
4400 ('symbol', 'S2')))))
4401 $ hg debugrevspec --verify -p analyzed -p optimized 'secret() & ::9'
4402 * analyzed:
4403 (and
4404 (func
4405 ('symbol', 'secret')
4406 None)
4407 (func
4408 ('symbol', 'ancestors')
4409 ('symbol', '9')))
4410 * optimized:
4411 (func
4412 ('symbol', '_phaseandancestors')
4413 (list
4414 ('symbol', 'secret')
4415 ('symbol', '9')))
4416 $ hg debugrevspec --verify -p analyzed -p optimized '7 & ( (not public()) & ::(tag()) )'
4417 * analyzed:
4418 (and
4419 ('symbol', '7')
4420 (and
4421 (not
4422 (func
4423 ('symbol', 'public')
4424 None))
4425 (func
4426 ('symbol', 'ancestors')
4427 (func
4428 ('symbol', 'tag')
4429 None))))
4430 * optimized:
4431 (and
4432 ('symbol', '7')
4433 (func
4434 ('symbol', '_phaseandancestors')
4435 (list
4436 ('symbol', '_notpublic')
4437 (func
4438 ('symbol', 'tag')
4439 None))))
4440 $ hg debugrevspec --verify -p optimized '(not public()) & ancestors(S1+D2+P5, 1)'
4441 * optimized:
4442 (and
4443 (func
4444 ('symbol', '_notpublic')
4445 None)
4446 (func
4447 ('symbol', 'ancestors')
4448 (list
4449 (func
4450 ('symbol', '_list')
4451 ('string', 'S1\x00D2\x00P5'))
4452 ('symbol', '1'))))
4453 $ hg debugrevspec --verify -p optimized '(not public()) & ancestors(S1+D2+P5, depth=1)'
4454 * optimized:
4455 (and
4456 (func
4457 ('symbol', '_notpublic')
4458 None)
4459 (func
4460 ('symbol', 'ancestors')
4461 (list
4462 (func
4463 ('symbol', '_list')
4464 ('string', 'S1\x00D2\x00P5'))
4465 (keyvalue
4466 ('symbol', 'depth')
4467 ('symbol', '1')))))
General Comments 0
You need to be logged in to leave comments. Login now