comparison mercurial/repoview.py @ 32477:20c1c2fb8106

hidden: simplify the computation of consistency blocker For a couple of years, we now have precomputed set for all mutable phases. We can use this set restrict our search and quickly detect non-hideable children of hideable changesets. This speeds up the hidden computation. See docstring of the new function for details. This new version reuses the '_domainancestors' function to keep the computation of revealed changeset in O(len(visible)) Below are perfvolatilesets timing from two Mozilla repositories with different contents. hidden cache is disabled while obtaining them. 1) Mozilla repository with: * 400667 changesets * 35 hidden changesets (first rev-268334) * 288 visible drafts * 1 unstable changeset Before: ! visible ! wall 0.001744 comb 0.000000 user 0.000000 sys 0.000000 (best of 1563) After: ! visible ! wall 0.000742 comb 0.000000 user 0.000000 sys 0.000000 (best of 3755) The timing above include the computation of obsolete changeset: ! obsolete ! wall 0.000396 comb 0.000000 user 0.000000 sys 0.000000 (best of 6816) So adjusted time give 1.3ms before versus 0.3ms after. A 4x speedup. 2) Mozilla repository with: * 405645 changesets * 4312 hidden changesets (first rev-326004) * 264 visible drafts * 1 unstable changeset Before: ! visible ! wall 0.025476 comb 0.030000 user 0.030000 sys 0.000000 (best of 111) After ! visible ! wall 0.007703 comb 0.010000 user 0.010000 sys 0.000000 (best of 358) The timing above include the computation of obsolete changeset: ! obsolete ! wall 0.006408 comb 0.010000 user 0.010000 sys 0.000000 (best of 404) So adjusted time give 19ms before versus 1.3ms after. A 17x speedup.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Sun, 21 May 2017 16:01:20 +0200
parents e5e31b0fc924
children 1cc7c96cad75
comparison
equal deleted inserted replaced
32476:e5e31b0fc924 32477:20c1c2fb8106
8 8
9 from __future__ import absolute_import 9 from __future__ import absolute_import
10 10
11 import copy 11 import copy
12 import hashlib 12 import hashlib
13 import heapq
14 import struct 13 import struct
15 14
16 from .node import nullrev 15 from .node import nullrev
17 from . import ( 16 from . import (
18 error, 17 error,
61 A second pass will be done to apply "dynamic blocker" like bookmarks or 60 A second pass will be done to apply "dynamic blocker" like bookmarks or
62 working directory parents. 61 working directory parents.
63 62
64 """ 63 """
65 assert not repo.changelog.filteredrevs 64 assert not repo.changelog.filteredrevs
66 hidden = set(hideablerevs(repo)) 65 hidden = hideablerevs(repo)
67 if hidden: 66 if hidden:
68 getphase = repo._phasecache.phase 67 pfunc = repo.changelog.parentrevs
69 getparentrevs = repo.changelog.parentrevs 68
70 # Skip heads which are public (guaranteed to not be hidden) 69 mutablephases = (phases.draft, phases.secret)
71 heap = [-r for r in repo.changelog.headrevs() if getphase(repo, r)] 70 mutable = repo._phasecache.getrevset(repo, mutablephases)
72 heapq.heapify(heap) 71 blockers = _consistencyblocker(pfunc, hidden, mutable)
73 heappop = heapq.heappop 72
74 heappush = heapq.heappush 73 if blockers:
75 seen = set() # no need to init it with heads, they have no children 74 hidden = hidden - _domainancestors(pfunc, blockers, mutable)
76 while heap:
77 rev = -heappop(heap)
78 # All children have been processed so at that point, if no children
79 # removed 'rev' from the 'hidden' set, 'rev' is going to be hidden.
80 blocker = rev not in hidden
81 for parent in getparentrevs(rev):
82 if parent == nullrev:
83 continue
84 if blocker:
85 # If visible, ensure parent will be visible too
86 hidden.discard(parent)
87 # - Avoid adding the same revision twice
88 # - Skip nodes which are public (guaranteed to not be hidden)
89 pre = len(seen)
90 seen.add(parent)
91 if pre < len(seen) and getphase(repo, rev):
92 heappush(heap, -parent)
93 return hidden 75 return hidden
76
77 def _consistencyblocker(pfunc, hideable, domain):
78 """return non-hideable changeset blocking hideable one
79
80 For consistency, we cannot actually hide a changeset if one of it children
81 are visible, this function find such children.
82 """
83 others = domain - hideable
84 blockers = set()
85 for r in others:
86 for p in pfunc(r):
87 if p != nullrev and p in hideable:
88 blockers.add(r)
89 break
90 return blockers
94 91
95 def _domainancestors(pfunc, revs, domain): 92 def _domainancestors(pfunc, revs, domain):
96 """return ancestors of 'revs' within 'domain' 93 """return ancestors of 'revs' within 'domain'
97 94
98 - pfunc(r): a funtion returning parent of 'r', 95 - pfunc(r): a funtion returning parent of 'r',