diff mercurial/phases.py @ 45789:09735cde6275

phases: allow registration and boundary advancement with revision sets The core internals either use revision sets already or can trivially use them. Use the new interface in cg1unpacker.apply to avoid materializing the list of all new nodes as it is normally just a revision range. This avoids about 67 Bytes / changeset on AMD64 in peak RSS. Differential Revision: https://phab.mercurial-scm.org/D9232
author Joerg Sonnenberger <joerg@bec.de>
date Mon, 19 Oct 2020 02:54:12 +0200
parents 29a259be6424
children 5d65e04b6a80
line wrap: on
line diff
--- a/mercurial/phases.py	Sun Oct 18 22:18:02 2020 +0200
+++ b/mercurial/phases.py	Mon Oct 19 02:54:12 2020 +0200
@@ -510,21 +510,25 @@
         tr.addfilegenerator(b'phase', (b'phaseroots',), self._write)
         tr.hookargs[b'phases_moved'] = b'1'
 
-    def registernew(self, repo, tr, targetphase, nodes):
+    def registernew(self, repo, tr, targetphase, nodes, revs=None):
+        if revs is None:
+            revs = []
         repo = repo.unfiltered()
-        self._retractboundary(repo, tr, targetphase, nodes)
+        self._retractboundary(repo, tr, targetphase, nodes, revs=revs)
         if tr is not None and b'phases' in tr.changes:
             phasetracking = tr.changes[b'phases']
             torev = repo.changelog.rev
             phase = self.phase
-            revs = [torev(node) for node in nodes]
+            revs = [torev(node) for node in nodes] + sorted(revs)
             revs.sort()
             for rev in revs:
                 revphase = phase(repo, rev)
                 _trackphasechange(phasetracking, rev, None, revphase)
         repo.invalidatevolatilesets()
 
-    def advanceboundary(self, repo, tr, targetphase, nodes, dryrun=None):
+    def advanceboundary(
+        self, repo, tr, targetphase, nodes, revs=None, dryrun=None
+    ):
         """Set all 'nodes' to phase 'targetphase'
 
         Nodes with a phase lower than 'targetphase' are not affected.
@@ -535,26 +539,27 @@
         """
         # Be careful to preserve shallow-copied values: do not update
         # phaseroots values, replace them.
+        if revs is None:
+            revs = []
         if tr is None:
             phasetracking = None
         else:
             phasetracking = tr.changes.get(b'phases')
 
         repo = repo.unfiltered()
+        revs = [repo[n].rev() for n in nodes] + [r for r in revs]
 
         changes = set()  # set of revisions to be changed
         delroots = []  # set of root deleted by this path
         for phase in (phase for phase in allphases if phase > targetphase):
             # filter nodes that are not in a compatible phase already
-            nodes = [
-                n for n in nodes if self.phase(repo, repo[n].rev()) >= phase
-            ]
-            if not nodes:
+            revs = [rev for rev in revs if self.phase(repo, rev) >= phase]
+            if not revs:
                 break  # no roots to move anymore
 
             olds = self.phaseroots[phase]
 
-            affected = repo.revs(b'%ln::%ln', olds, nodes)
+            affected = repo.revs(b'%ln::%ld', olds, revs)
             changes.update(affected)
             if dryrun:
                 continue
@@ -611,9 +616,11 @@
                     _trackphasechange(phasetracking, r, phase, targetphase)
         repo.invalidatevolatilesets()
 
-    def _retractboundary(self, repo, tr, targetphase, nodes):
+    def _retractboundary(self, repo, tr, targetphase, nodes, revs=None):
         # Be careful to preserve shallow-copied values: do not update
         # phaseroots values, replace them.
+        if revs is None:
+            revs = []
         if targetphase in (archived, internal) and not supportinternal(repo):
             name = phasenames[targetphase]
             msg = b'this repository does not support the %s phase' % name
@@ -624,7 +631,7 @@
         tonode = repo.changelog.node
         currentroots = {torev(node) for node in self.phaseroots[targetphase]}
         finalroots = oldroots = set(currentroots)
-        newroots = [torev(node) for node in nodes]
+        newroots = [torev(node) for node in nodes] + [r for r in revs]
         newroots = [
             rev for rev in newroots if self.phase(repo, rev) < targetphase
         ]
@@ -679,7 +686,7 @@
         self.invalidate()
 
 
-def advanceboundary(repo, tr, targetphase, nodes, dryrun=None):
+def advanceboundary(repo, tr, targetphase, nodes, revs=None, dryrun=None):
     """Add nodes to a phase changing other nodes phases if necessary.
 
     This function move boundary *forward* this means that all nodes
@@ -691,9 +698,11 @@
 
     Returns a set of revs whose phase is changed or should be changed
     """
+    if revs is None:
+        revs = []
     phcache = repo._phasecache.copy()
     changes = phcache.advanceboundary(
-        repo, tr, targetphase, nodes, dryrun=dryrun
+        repo, tr, targetphase, nodes, revs=revs, dryrun=dryrun
     )
     if not dryrun:
         repo._phasecache.replace(phcache)
@@ -713,14 +722,16 @@
     repo._phasecache.replace(phcache)
 
 
-def registernew(repo, tr, targetphase, nodes):
+def registernew(repo, tr, targetphase, nodes, revs=None):
     """register a new revision and its phase
 
     Code adding revisions to the repository should use this function to
     set new changeset in their target phase (or higher).
     """
+    if revs is None:
+        revs = []
     phcache = repo._phasecache.copy()
-    phcache.registernew(repo, tr, targetphase, nodes)
+    phcache.registernew(repo, tr, targetphase, nodes, revs=revs)
     repo._phasecache.replace(phcache)