# HG changeset patch # User Pierre-Yves David # Date 2024-02-21 12:05:29 # Node ID ac1c751884406f561b68bf40607339c06ed8605a # Parent e57d4b868a3eca680e9a700204771ac5569cd18d 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%) diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py --- a/mercurial/bundlerepo.py +++ b/mercurial/bundlerepo.py @@ -269,9 +269,10 @@ class bundlephasecache(phases.phasecache 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 diff --git a/mercurial/phases.py b/mercurial/phases.py --- a/mercurial/phases.py +++ b/mercurial/phases.py @@ -624,10 +624,11 @@ class phasecache: 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 @@ class phasecache: 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 @@ class phasecache: 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