##// END OF EJS Templates
phases: large rewrite on retract boundary...
marmoute -
r52302:2f39c7ae default
parent child Browse files
Show More
@@ -677,15 +677,7 b' class phasecache:'
677
677
678 def _retractboundary(self, repo, tr, targetphase, nodes=None, revs=None):
678 def _retractboundary(self, repo, tr, targetphase, nodes=None, revs=None):
679 if targetphase == public:
679 if targetphase == public:
680 return False
680 return {}
681 # Be careful to preserve shallow-copied values: do not update
682 # phaseroots values, replace them.
683 if revs is None:
684 revs = []
685 if nodes is None:
686 nodes = []
687 if not revs and not nodes:
688 return False
689 if (
681 if (
690 targetphase == internal
682 targetphase == internal
691 and not supportinternal(repo)
683 and not supportinternal(repo)
@@ -695,34 +687,103 b' class phasecache:'
695 name = phasenames[targetphase]
687 name = phasenames[targetphase]
696 msg = b'this repository does not support the %s phase' % name
688 msg = b'this repository does not support the %s phase' % name
697 raise error.ProgrammingError(msg)
689 raise error.ProgrammingError(msg)
690 assert repo.filtername is None
691 cl = repo.changelog
692 torev = cl.index.rev
693 new_revs = set()
694 if revs is not None:
695 new_revs.update(revs)
696 if nodes is not None:
697 new_revs.update(torev(node) for node in nodes)
698 if not new_revs: # bail out early to avoid the loadphaserevs call
699 return {} # note: why do people call retractboundary with nothing ?
698
700
699 torev = repo.changelog.index.rev
701 if nullrev in new_revs:
702 raise error.Abort(_(b'cannot change null revision phase'))
703
704 # Compute change in phase roots by walking the graph
705 #
706 # note: If we had a cheap parent β†’ children mapping we could do
707 # something even cheaper/more-bounded
708 #
709 # The idea would be to walk from item in new_revs stopping at
710 # descendant with phases >= target_phase.
711 #
712 # 1) This detect new_revs that are not new_roots (either already >=
713 # target_phase or reachable though another new_revs
714 # 2) This detect replaced current_roots as we reach them
715 # 3) This can avoid walking to the tip if we retract over a small
716 # branch.
717 #
718 # So instead, we do a variation of this, we walk from the smaller new
719 # revision to the tip to avoid missing any potential children.
720 #
721 # The following code would be a good candidate for native code… if only
722 # we could knew the phase of a changeset efficiently in native code.
723 parents = cl.parentrevs
724 phase = self.phase
725 new_roots = set() # roots added by this phases
726 changed_revs = {} # revision affected by this call
727 replaced_roots = set() # older roots replaced by this call
700 currentroots = self._phaseroots[targetphase]
728 currentroots = self._phaseroots[targetphase]
701 finalroots = oldroots = set(currentroots)
729 start = min(new_revs)
702 newroots = [torev(node) for node in nodes] + [r for r in revs]
730 end = len(cl)
703 newroots = [
731 rev_phases = [None] * (end - start)
704 rev for rev in newroots if self.phase(repo, rev) < targetphase
732 for r in range(start, end):
705 ]
706
733
707 if newroots:
734 # gather information about the current_rev
708 if nullrev in newroots:
735 r_phase = phase(repo, r)
709 raise error.Abort(_(b'cannot change null revision phase'))
736 p_phase = None # phase inherited from parents
710 # do not break the CoW assumption of the shallow copy
737 p1, p2 = parents(r)
711 currentroots = currentroots.copy()
738 if p1 >= start:
712 currentroots.update(newroots)
739 p1_phase = rev_phases[p1 - start]
740 if p1_phase is not None:
741 p_phase = p1_phase
742 if p2 >= start:
743 p2_phase = rev_phases[p2 - start]
744 if p2_phase is not None:
745 if p_phase is not None:
746 p_phase = max(p_phase, p2_phase)
747 else:
748 p_phase = p2_phase
713
749
714 # Only compute new roots for revs above the roots that are being
750 # assess the situation
715 # retracted.
751 if r in new_revs and r_phase < targetphase:
716 minnewroot = min(newroots)
752 if p_phase is None or p_phase < targetphase:
717 aboveroots = [rev for rev in currentroots if rev >= minnewroot]
753 new_roots.add(r)
718 updatedroots = repo.revs(b'roots(%ld::)', aboveroots)
754 rev_phases[r - start] = targetphase
755 changed_revs[r] = r_phase
756 elif p_phase is None:
757 rev_phases[r - start] = r_phase
758 else:
759 if p_phase > r_phase:
760 rev_phases[r - start] = p_phase
761 else:
762 rev_phases[r - start] = r_phase
763 if p_phase == targetphase:
764 if p_phase > r_phase:
765 changed_revs[r] = r_phase
766 elif r in currentroots:
767 replaced_roots.add(r)
719
768
720 finalroots = {rev for rev in currentroots if rev < minnewroot}
769 if new_roots:
721 finalroots.update(updatedroots)
770 assert changed_revs
722 if finalroots != oldroots:
771 final_roots = new_roots | currentroots - replaced_roots
723 self._updateroots(repo, targetphase, finalroots, tr)
772 self._updateroots(repo, targetphase, final_roots, tr)
724 return True
773 if targetphase > 1:
725 return False
774 retracted = set(changed_revs)
775 for lower_phase in range(1, targetphase):
776 lower_roots = self._phaseroots.get(lower_phase)
777 if lower_roots is None:
778 continue
779 if lower_roots & retracted:
780 simpler_roots = lower_roots - retracted
781 self._updateroots(repo, lower_phase, simpler_roots, tr)
782 return changed_revs
783 else:
784 assert not changed_revs
785 assert not replaced_roots
786 return {}
726
787
727 def register_strip(
788 def register_strip(
728 self,
789 self,
General Comments 0
You need to be logged in to leave comments. Login now