--- a/contrib/perf.py Fri Aug 17 15:32:38 2018 -0700
+++ b/contrib/perf.py Fri Aug 17 16:11:35 2018 -0700
@@ -790,6 +790,63 @@
timer(d)
fm.end()
+@command('perfphasesremote',
+ [], "[DEST]")
+def perfphasesremote(ui, repo, dest=None, **opts):
+ """benchmark time needed to analyse phases of the remote server"""
+ from mercurial.node import (
+ bin,
+ )
+ from mercurial import (
+ exchange,
+ hg,
+ phases,
+ )
+ timer, fm = gettimer(ui, opts)
+
+ path = ui.paths.getpath(dest, default=('default-push', 'default'))
+ if not path:
+ raise error.abort(('default repository not configured!'),
+ hint=("see 'hg help config.paths'"))
+ dest = path.pushloc or path.loc
+ branches = (path.branch, opts.get('branch') or [])
+ ui.status(('analysing phase of %s\n') % util.hidepassword(dest))
+ revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
+ other = hg.peer(repo, opts, dest)
+
+ # easier to perform discovery through the operation
+ op = exchange.pushoperation(repo, other)
+ exchange._pushdiscoverychangeset(op)
+
+ remotesubset = op.fallbackheads
+
+ with other.commandexecutor() as e:
+ remotephases = e.callcommand('listkeys',
+ {'namespace': 'phases'}).result()
+ del other
+ publishing = remotephases.get('publishing', False)
+ if publishing:
+ ui.status(('publishing: yes\n'))
+ else:
+ ui.status(('publishing: no\n'))
+
+ nodemap = repo.changelog.nodemap
+ nonpublishroots = 0
+ for nhex, phase in remotephases.iteritems():
+ if nhex == 'publishing': # ignore data related to publish option
+ continue
+ node = bin(nhex)
+ if node in nodemap and int(phase):
+ nonpublishroots += 1
+ ui.status(('number of roots: %d\n') % len(remotephases))
+ ui.status(('number of known non public roots: %d\n') % nonpublishroots)
+ def d():
+ phases.remotephasessummary(repo,
+ remotesubset,
+ remotephases)
+ timer(d)
+ fm.end()
+
@command('perfmanifest',[
('m', 'manifest-rev', False, 'Look up a manifest node revision'),
('', 'clear-disk', False, 'clear on-disk caches too'),
--- a/mercurial/phases.py Fri Aug 17 15:32:38 2018 -0700
+++ b/mercurial/phases.py Fri Aug 17 16:11:35 2018 -0700
@@ -664,9 +664,39 @@
* `heads`: define the first subset
* `roots`: define the second we subtract from the first"""
+ # prevent an import cycle
+ # phases > dagop > patch > copies > scmutil > obsolete > obsutil > phases
+ from . import dagop
+
repo = repo.unfiltered()
- revs = repo.revs('heads(::%ln - (%ln::%ln))', heads, roots, heads)
- return pycompat.maplist(repo.changelog.node, revs)
+ cl = repo.changelog
+ rev = cl.nodemap.get
+ if not roots:
+ return heads
+ if not heads or heads == [nullrev]:
+ return []
+ # The logic operated on revisions, convert arguments early for convenience
+ new_heads = set(rev(n) for n in heads if n != nullid)
+ roots = [rev(n) for n in roots]
+ if not heads or not roots:
+ return heads
+ # compute the area we need to remove
+ affected_zone = repo.revs("(%ld::%ld)", roots, new_heads)
+ # heads in the area are no longer heads
+ new_heads.difference_update(affected_zone)
+ # revisions in the area have children outside of it,
+ # They might be new heads
+ candidates = repo.revs("parents(%ld + (%ld and merge())) and not null",
+ roots, affected_zone)
+ candidates -= affected_zone
+ if new_heads or candidates:
+ # remove candidate that are ancestors of other heads
+ new_heads.update(candidates)
+ prunestart = repo.revs("parents(%ld) and not null", new_heads)
+ pruned = dagop.reachableroots(repo, candidates, prunestart)
+ new_heads.difference_update(pruned)
+
+ return pycompat.maplist(cl.node, sorted(new_heads))
def newcommitphase(ui):
"""helper to get the target phase of new commit
--- a/mercurial/revlog.py Fri Aug 17 15:32:38 2018 -0700
+++ b/mercurial/revlog.py Fri Aug 17 16:11:35 2018 -0700
@@ -263,13 +263,17 @@
if endidx is None:
endidx = len(revs)
- # Trim empty revs at the end, but never the very first revision of a chain
- while endidx > 1 and endidx > startidx and length(revs[endidx - 1]) == 0:
- endidx -= 1
+ # If we have a non-emtpy delta candidate, there are nothing to trim
+ if revs[endidx - 1] < len(revlog):
+ # Trim empty revs at the end, except the very first revision of a chain
+ while (endidx > 1
+ and endidx > startidx
+ and length(revs[endidx - 1]) == 0):
+ endidx -= 1
return revs[startidx:endidx]
-def _segmentspan(revlog, revs):
+def _segmentspan(revlog, revs, deltainfo=None):
"""Get the byte span of a segment of revisions
revs is a sorted array of revision numbers
@@ -295,7 +299,14 @@
"""
if not revs:
return 0
- return revlog.end(revs[-1]) - revlog.start(revs[0])
+ if deltainfo is not None and len(revlog) <= revs[-1]:
+ if len(revs) == 1:
+ return deltainfo.deltalen
+ offset = revlog.end(len(revlog) - 1)
+ end = deltainfo.deltalen + offset
+ else:
+ end = revlog.end(revs[-1])
+ return end - revlog.start(revs[0])
def _slicechunk(revlog, revs, deltainfo=None, targetsize=None):
"""slice revs to reduce the amount of unrelated data to be read from disk.
@@ -527,7 +538,7 @@
yield revs
return
- if deltainfo is not None:
+ if deltainfo is not None and deltainfo.deltalen:
revs = list(revs)
revs.append(nextrev)
@@ -2471,7 +2482,8 @@
deltachain = []
chunks = _slicechunk(self, deltachain, deltainfo)
- distance = max(map(lambda revs:_segmentspan(self, revs), chunks))
+ all_span = [_segmentspan(self, revs, deltainfo) for revs in chunks]
+ distance = max(all_span)
else:
distance = deltainfo.distance
--- a/tests/test-bookmarks-pushpull.t Fri Aug 17 15:32:38 2018 -0700
+++ b/tests/test-bookmarks-pushpull.t Fri Aug 17 16:11:35 2018 -0700
@@ -141,10 +141,10 @@
bundle2-output: payload chunk size: 23
bundle2-output: closing payload chunk
bundle2-output: bundle part: "check:phases"
- bundle2-output-part: "check:phases" 48 bytes payload
+ bundle2-output-part: "check:phases" 24 bytes payload
bundle2-output: part 2: "CHECK:PHASES"
bundle2-output: header chunk size: 19
- bundle2-output: payload chunk size: 48
+ bundle2-output: payload chunk size: 24
bundle2-output: closing payload chunk
bundle2-output: bundle part: "pushkey"
bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
@@ -180,9 +180,9 @@
bundle2-input: part parameters: 0
bundle2-input: found a handler for part check:phases
bundle2-input-part: "check:phases" supported
- bundle2-input: payload chunk size: 48
+ bundle2-input: payload chunk size: 24
bundle2-input: payload chunk size: 0
- bundle2-input-part: total payload size 48
+ bundle2-input-part: total payload size 24
bundle2-input: part header size: 90
bundle2-input: part type: "PUSHKEY"
bundle2-input: part id: "3"
@@ -253,10 +253,10 @@
bundle2-output: payload chunk size: 23
bundle2-output: closing payload chunk
bundle2-output: bundle part: "check:phases"
- bundle2-output-part: "check:phases" 48 bytes payload
+ bundle2-output-part: "check:phases" 24 bytes payload
bundle2-output: part 2: "CHECK:PHASES"
bundle2-output: header chunk size: 19
- bundle2-output: payload chunk size: 48
+ bundle2-output: payload chunk size: 24
bundle2-output: closing payload chunk
bundle2-output: bundle part: "bookmarks"
bundle2-output-part: "bookmarks" 23 bytes payload
@@ -293,9 +293,9 @@
bundle2-input: part parameters: 0
bundle2-input: found a handler for part check:phases
bundle2-input-part: "check:phases" supported
- bundle2-input: payload chunk size: 48
+ bundle2-input: payload chunk size: 24
bundle2-input: payload chunk size: 0
- bundle2-input-part: total payload size 48
+ bundle2-input-part: total payload size 24
bundle2-input: part header size: 16
bundle2-input: part type: "BOOKMARKS"
bundle2-input: part id: "3"
--- a/tests/test-contrib-perf.t Fri Aug 17 15:32:38 2018 -0700
+++ b/tests/test-contrib-perf.t Fri Aug 17 16:11:35 2018 -0700
@@ -103,6 +103,8 @@
perfpathcopies
(no help text available)
perfphases benchmark phasesets computation
+ perfphasesremote
+ benchmark time needed to analyse phases of the remote server
perfrawfiles (no help text available)
perfrevlogchunks
Benchmark operations on revlog chunks.
@@ -212,4 +214,7 @@
contrib/perf.py:\d+: (re)
> from mercurial import (
import newer module separately in try clause for early Mercurial
+ contrib/perf.py:\d+: (re)
+ > from mercurial import (
+ import newer module separately in try clause for early Mercurial
[1]