mercurial/repoview.py
changeset 24565 2f7cb6e6acdd
parent 24154 a41902aac76d
child 24615 9e558b788daa
--- a/mercurial/repoview.py	Tue Mar 31 22:29:12 2015 -0700
+++ b/mercurial/repoview.py	Wed Apr 01 12:50:10 2015 -0700
@@ -6,6 +6,7 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+import collections
 import copy
 import error
 import phases
@@ -13,6 +14,7 @@
 import obsolete
 import struct
 import tags as tagsmod
+from node import nullrev
 
 def hideablerevs(repo):
     """Revisions candidates to be hidden
@@ -20,23 +22,37 @@
     This is a standalone function to help extensions to wrap it."""
     return obsolete.getrevs(repo, 'obsolete')
 
-def _getstaticblockers(repo):
+def _getstatichidden(repo):
     """Cacheable revisions blocking hidden changesets from being filtered.
 
     Additional non-cached hidden blockers are computed in _getdynamicblockers.
     This is a standalone function to help extensions to wrap it."""
     assert not repo.changelog.filteredrevs
     hideable = hideablerevs(repo)
-    blockers = set()
     if hideable:
-        # We use cl to avoid recursive lookup from repo[xxx]
-        cl = repo.changelog
-        firsthideable = min(hideable)
-        revs = cl.revs(start=firsthideable)
-        tofilter = repo.revs(
-            '(%ld) and children(%ld)', list(revs), list(hideable))
-        blockers.update([r for r in tofilter if r not in hideable])
-    return blockers
+        actuallyhidden = {}
+        getphase = repo._phasecache.phase
+        getparentrevs = repo.changelog.parentrevs
+        queue = collections.deque((r, False) for r in repo.changelog.headrevs())
+        while queue:
+            rev, blocked = queue.popleft()
+            phase = getphase(repo, rev)
+            # Skip nodes which are public (guaranteed to not be hidden) and
+            # nodes which have already been processed and won't be blocked by
+            # the previous node.
+            if phase == 0 or (not blocked and rev in actuallyhidden):
+                continue
+            if rev in hideable:
+                if blocked:
+                    actuallyhidden[rev] = False
+                else:
+                    actuallyhidden.setdefault(rev, True)
+            else:
+                blocked = True
+
+            for parent in (p for p in getparentrevs(rev) if p != nullrev):
+                queue.append((parent, blocked))
+    return set(rev for rev, hidden in actuallyhidden.iteritems() if hidden)
 
 def _getdynamicblockers(repo):
     """Non-cacheable revisions blocking hidden changesets from being filtered.
@@ -137,8 +153,7 @@
         cl = repo.changelog
         hidden = tryreadcache(repo, hideable)
         if hidden is None:
-            blocked = cl.ancestors(_getstaticblockers(repo), inclusive=True)
-            hidden = frozenset(r for r in hideable if r not in blocked)
+            hidden = frozenset(_getstatichidden(repo))
             trywritehiddencache(repo, hideable, hidden)
 
         # check if we have wd parents, bookmarks or tags pointing to hidden