changeset 51420:ac1c75188440

phases: invalidate the phases set less often on retract boundary We already have the information to update the phase set, so we do so directly instead of invalidating the cache. This show a sizeable speedup in our `perf::unbundle` benchmark on the many-draft mozilla-try repository. ### data-env-vars.name = mozilla-try-2023-03-22-zstd-sparse-revlog # benchmark.name = hg.perf.perf-unbundle # bin-env-vars.hg.flavor = no-rust # bin-env-vars.hg.py-re2-module = default # benchmark.variants.issue6528 = disabled # benchmark.variants.revs = last-10 before: 2.055259 seconds after: 1.887064 seconds (-8.18%) # benchmark.variants.revs = last-100 before: 2.409239 seconds after: 2.222429 seconds (-7.75%) # benchmark.variants.revs = last-1000 before: 3.945648 seconds after: 3.762480 seconds (-4.64%)
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Wed, 21 Feb 2024 13:05:29 +0100
parents e57d4b868a3e
children 2eb93812d2a5
files mercurial/bundlerepo.py mercurial/phases.py
diffstat 2 files changed, 26 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/bundlerepo.py	Wed Feb 21 13:05:23 2024 +0100
+++ b/mercurial/bundlerepo.py	Wed Feb 21 13:05:29 2024 +0100
@@ -269,9 +269,10 @@
     def _write(self, fp):
         raise NotImplementedError
 
-    def _updateroots(self, repo, phase, newroots, tr):
+    def _updateroots(self, repo, phase, newroots, tr, invalidate=True):
         self._phaseroots[phase] = newroots
-        self.invalidate()
+        if invalidate:
+            self.invalidate()
         self.dirty = True
 
 
--- a/mercurial/phases.py	Wed Feb 21 13:05:23 2024 +0100
+++ b/mercurial/phases.py	Wed Feb 21 13:05:29 2024 +0100
@@ -624,10 +624,11 @@
                 fp.write(b'%i %s\n' % (phase, hex(h)))
         self.dirty = False
 
-    def _updateroots(self, repo, phase, newroots, tr):
+    def _updateroots(self, repo, phase, newroots, tr, invalidate=True):
         self._phaseroots[phase] = newroots
-        self.invalidate()
         self.dirty = True
+        if invalidate:
+            self.invalidate()
 
         assert repo.filtername is None
         wrepo = weakref.ref(repo)
@@ -811,11 +812,23 @@
                         changed_revs[r] = r_phase
                     elif r in currentroots:
                         replaced_roots.add(r)
+            sets = self._phasesets
+            sets[targetphase].update(changed_revs)
+            for r, old in changed_revs.items():
+                if old > public:
+                    sets[old].discard(r)
 
         if new_roots:
             assert changed_revs
+
             final_roots = new_roots | currentroots - replaced_roots
-            self._updateroots(repo, targetphase, final_roots, tr)
+            self._updateroots(
+                repo,
+                targetphase,
+                final_roots,
+                tr,
+                invalidate=False,
+            )
             if targetphase > 1:
                 retracted = set(changed_revs)
                 for lower_phase in range(1, targetphase):
@@ -824,7 +837,13 @@
                         continue
                     if lower_roots & retracted:
                         simpler_roots = lower_roots - retracted
-                        self._updateroots(repo, lower_phase, simpler_roots, tr)
+                        self._updateroots(
+                            repo,
+                            lower_phase,
+                            simpler_roots,
+                            tr,
+                            invalidate=False,
+                        )
             return changed_revs
         else:
             assert not changed_revs