comparison 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
comparison
equal deleted inserted replaced
45788:a5206e71c536 45789:09735cde6275
508 self.dirty = True 508 self.dirty = True
509 509
510 tr.addfilegenerator(b'phase', (b'phaseroots',), self._write) 510 tr.addfilegenerator(b'phase', (b'phaseroots',), self._write)
511 tr.hookargs[b'phases_moved'] = b'1' 511 tr.hookargs[b'phases_moved'] = b'1'
512 512
513 def registernew(self, repo, tr, targetphase, nodes): 513 def registernew(self, repo, tr, targetphase, nodes, revs=None):
514 if revs is None:
515 revs = []
514 repo = repo.unfiltered() 516 repo = repo.unfiltered()
515 self._retractboundary(repo, tr, targetphase, nodes) 517 self._retractboundary(repo, tr, targetphase, nodes, revs=revs)
516 if tr is not None and b'phases' in tr.changes: 518 if tr is not None and b'phases' in tr.changes:
517 phasetracking = tr.changes[b'phases'] 519 phasetracking = tr.changes[b'phases']
518 torev = repo.changelog.rev 520 torev = repo.changelog.rev
519 phase = self.phase 521 phase = self.phase
520 revs = [torev(node) for node in nodes] 522 revs = [torev(node) for node in nodes] + sorted(revs)
521 revs.sort() 523 revs.sort()
522 for rev in revs: 524 for rev in revs:
523 revphase = phase(repo, rev) 525 revphase = phase(repo, rev)
524 _trackphasechange(phasetracking, rev, None, revphase) 526 _trackphasechange(phasetracking, rev, None, revphase)
525 repo.invalidatevolatilesets() 527 repo.invalidatevolatilesets()
526 528
527 def advanceboundary(self, repo, tr, targetphase, nodes, dryrun=None): 529 def advanceboundary(
530 self, repo, tr, targetphase, nodes, revs=None, dryrun=None
531 ):
528 """Set all 'nodes' to phase 'targetphase' 532 """Set all 'nodes' to phase 'targetphase'
529 533
530 Nodes with a phase lower than 'targetphase' are not affected. 534 Nodes with a phase lower than 'targetphase' are not affected.
531 535
532 If dryrun is True, no actions will be performed 536 If dryrun is True, no actions will be performed
533 537
534 Returns a set of revs whose phase is changed or should be changed 538 Returns a set of revs whose phase is changed or should be changed
535 """ 539 """
536 # Be careful to preserve shallow-copied values: do not update 540 # Be careful to preserve shallow-copied values: do not update
537 # phaseroots values, replace them. 541 # phaseroots values, replace them.
542 if revs is None:
543 revs = []
538 if tr is None: 544 if tr is None:
539 phasetracking = None 545 phasetracking = None
540 else: 546 else:
541 phasetracking = tr.changes.get(b'phases') 547 phasetracking = tr.changes.get(b'phases')
542 548
543 repo = repo.unfiltered() 549 repo = repo.unfiltered()
550 revs = [repo[n].rev() for n in nodes] + [r for r in revs]
544 551
545 changes = set() # set of revisions to be changed 552 changes = set() # set of revisions to be changed
546 delroots = [] # set of root deleted by this path 553 delroots = [] # set of root deleted by this path
547 for phase in (phase for phase in allphases if phase > targetphase): 554 for phase in (phase for phase in allphases if phase > targetphase):
548 # filter nodes that are not in a compatible phase already 555 # filter nodes that are not in a compatible phase already
549 nodes = [ 556 revs = [rev for rev in revs if self.phase(repo, rev) >= phase]
550 n for n in nodes if self.phase(repo, repo[n].rev()) >= phase 557 if not revs:
551 ]
552 if not nodes:
553 break # no roots to move anymore 558 break # no roots to move anymore
554 559
555 olds = self.phaseroots[phase] 560 olds = self.phaseroots[phase]
556 561
557 affected = repo.revs(b'%ln::%ln', olds, nodes) 562 affected = repo.revs(b'%ln::%ld', olds, revs)
558 changes.update(affected) 563 changes.update(affected)
559 if dryrun: 564 if dryrun:
560 continue 565 continue
561 for r in affected: 566 for r in affected:
562 _trackphasechange( 567 _trackphasechange(
609 revs = affected 614 revs = affected
610 for r in sorted(revs): 615 for r in sorted(revs):
611 _trackphasechange(phasetracking, r, phase, targetphase) 616 _trackphasechange(phasetracking, r, phase, targetphase)
612 repo.invalidatevolatilesets() 617 repo.invalidatevolatilesets()
613 618
614 def _retractboundary(self, repo, tr, targetphase, nodes): 619 def _retractboundary(self, repo, tr, targetphase, nodes, revs=None):
615 # Be careful to preserve shallow-copied values: do not update 620 # Be careful to preserve shallow-copied values: do not update
616 # phaseroots values, replace them. 621 # phaseroots values, replace them.
622 if revs is None:
623 revs = []
617 if targetphase in (archived, internal) and not supportinternal(repo): 624 if targetphase in (archived, internal) and not supportinternal(repo):
618 name = phasenames[targetphase] 625 name = phasenames[targetphase]
619 msg = b'this repository does not support the %s phase' % name 626 msg = b'this repository does not support the %s phase' % name
620 raise error.ProgrammingError(msg) 627 raise error.ProgrammingError(msg)
621 628
622 repo = repo.unfiltered() 629 repo = repo.unfiltered()
623 torev = repo.changelog.rev 630 torev = repo.changelog.rev
624 tonode = repo.changelog.node 631 tonode = repo.changelog.node
625 currentroots = {torev(node) for node in self.phaseroots[targetphase]} 632 currentroots = {torev(node) for node in self.phaseroots[targetphase]}
626 finalroots = oldroots = set(currentroots) 633 finalroots = oldroots = set(currentroots)
627 newroots = [torev(node) for node in nodes] 634 newroots = [torev(node) for node in nodes] + [r for r in revs]
628 newroots = [ 635 newroots = [
629 rev for rev in newroots if self.phase(repo, rev) < targetphase 636 rev for rev in newroots if self.phase(repo, rev) < targetphase
630 ] 637 ]
631 638
632 if newroots: 639 if newroots:
677 # "destroyed" function to phasecache or a proper cache key mechanism 684 # "destroyed" function to phasecache or a proper cache key mechanism
678 # (see branchmap one) 685 # (see branchmap one)
679 self.invalidate() 686 self.invalidate()
680 687
681 688
682 def advanceboundary(repo, tr, targetphase, nodes, dryrun=None): 689 def advanceboundary(repo, tr, targetphase, nodes, revs=None, dryrun=None):
683 """Add nodes to a phase changing other nodes phases if necessary. 690 """Add nodes to a phase changing other nodes phases if necessary.
684 691
685 This function move boundary *forward* this means that all nodes 692 This function move boundary *forward* this means that all nodes
686 are set in the target phase or kept in a *lower* phase. 693 are set in the target phase or kept in a *lower* phase.
687 694
689 696
690 If dryrun is True, no actions will be performed 697 If dryrun is True, no actions will be performed
691 698
692 Returns a set of revs whose phase is changed or should be changed 699 Returns a set of revs whose phase is changed or should be changed
693 """ 700 """
701 if revs is None:
702 revs = []
694 phcache = repo._phasecache.copy() 703 phcache = repo._phasecache.copy()
695 changes = phcache.advanceboundary( 704 changes = phcache.advanceboundary(
696 repo, tr, targetphase, nodes, dryrun=dryrun 705 repo, tr, targetphase, nodes, revs=revs, dryrun=dryrun
697 ) 706 )
698 if not dryrun: 707 if not dryrun:
699 repo._phasecache.replace(phcache) 708 repo._phasecache.replace(phcache)
700 return changes 709 return changes
701 710
711 phcache = repo._phasecache.copy() 720 phcache = repo._phasecache.copy()
712 phcache.retractboundary(repo, tr, targetphase, nodes) 721 phcache.retractboundary(repo, tr, targetphase, nodes)
713 repo._phasecache.replace(phcache) 722 repo._phasecache.replace(phcache)
714 723
715 724
716 def registernew(repo, tr, targetphase, nodes): 725 def registernew(repo, tr, targetphase, nodes, revs=None):
717 """register a new revision and its phase 726 """register a new revision and its phase
718 727
719 Code adding revisions to the repository should use this function to 728 Code adding revisions to the repository should use this function to
720 set new changeset in their target phase (or higher). 729 set new changeset in their target phase (or higher).
721 """ 730 """
731 if revs is None:
732 revs = []
722 phcache = repo._phasecache.copy() 733 phcache = repo._phasecache.copy()
723 phcache.registernew(repo, tr, targetphase, nodes) 734 phcache.registernew(repo, tr, targetphase, nodes, revs=revs)
724 repo._phasecache.replace(phcache) 735 repo._phasecache.replace(phcache)
725 736
726 737
727 def listphases(repo): 738 def listphases(repo):
728 """List phases root for serialization over pushkey""" 739 """List phases root for serialization over pushkey"""