Mercurial > hg
changeset 39146:f736fdbe546a stable
remotephase: avoid full changelog iteration (issue5964)
Changeset 88efb7d6bcb6 introduced a performance regression by triggering a
full ancestors walk.
This changeset reworks this logic so that we no longer walk down the full
changelog. The motivation for 88efb7d6bcb6, issue5939, is still fixed.
mercurial compared to a draft repository
----------------------------------------
8eeed92475d5: 0.012637 seconds
88efb7d6bcb6: 0.202699 seconds (x16)
46da52f4b820: 0.215551 seconds (+6%)
this code: 0.008397 seconds (-33% from base)
The payload size reduction we see in `test-bookmarks-pushpull.t` comes from a
more aggressive filter of nullid and is harmless.
author | Boris Feld <boris.feld@octobus.net> |
---|---|
date | Fri, 17 Aug 2018 20:35:52 +0200 |
parents | c89e2fb207a1 |
children | b95b48a55c36 cee9043c7dba |
files | mercurial/phases.py tests/test-bookmarks-pushpull.t |
diffstat | 2 files changed, 39 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/phases.py Fri Aug 17 16:00:32 2018 -0700 +++ b/mercurial/phases.py Fri Aug 17 20:35:52 2018 +0200 @@ -664,11 +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() + 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 - repo = repo.unfiltered() - revs = repo.revs('heads(::%ln - (%ln::%ln))', heads, roots, heads) - return pycompat.maplist(repo.changelog.node, revs) + # 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/tests/test-bookmarks-pushpull.t Fri Aug 17 16:00:32 2018 -0700 +++ b/tests/test-bookmarks-pushpull.t Fri Aug 17 20:35:52 2018 +0200 @@ -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"