Mercurial > hg
comparison hgext/rebase.py @ 31514:2519994d25ca
rebase: use one dirstateguard for entire rebase
Recently we switched rebases to run the entire rebase inside a single
transaction, which dramatically improved the speed of rebases in repos with
large working copies. Let's also move the dirstate into a single dirstateguard
to get the same benefits. This let's us avoid serializing the dirstate after
each commit.
In a large repo, rebasing 27 commits is sped up by about 20%.
I believe the test changes are because us touching the dirstate gave the
transaction something to actually rollback.
author | Durham Goode <durham@fb.com> |
---|---|
date | Sun, 19 Mar 2017 11:54:15 -0700 |
parents | f255b1811f5e |
children | 13dc00c233b7 |
comparison
equal
deleted
inserted
replaced
31513:68474b72ea63 | 31514:2519994d25ca |
---|---|
473 self.state[rebased] > nullmerge: | 473 self.state[rebased] > nullmerge: |
474 commitmsg += '\n* %s' % repo[rebased].description() | 474 commitmsg += '\n* %s' % repo[rebased].description() |
475 editopt = True | 475 editopt = True |
476 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform) | 476 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform) |
477 revtoreuse = max(self.state) | 477 revtoreuse = max(self.state) |
478 newnode = concludenode(repo, revtoreuse, p1, self.external, | 478 dsguard = dirstateguard.dirstateguard(repo, 'rebase') |
479 commitmsg=commitmsg, | 479 try: |
480 extrafn=_makeextrafn(self.extrafns), | 480 newnode = concludenode(repo, revtoreuse, p1, self.external, |
481 editor=editor, | 481 commitmsg=commitmsg, |
482 keepbranches=self.keepbranchesf, | 482 extrafn=_makeextrafn(self.extrafns), |
483 date=self.date) | 483 editor=editor, |
484 keepbranches=self.keepbranchesf, | |
485 date=self.date) | |
486 dsguard.close() | |
487 release(dsguard) | |
488 except error.InterventionRequired: | |
489 dsguard.close() | |
490 release(dsguard) | |
491 raise | |
492 except Exception: | |
493 release(dsguard) | |
494 raise | |
495 | |
484 if newnode is None: | 496 if newnode is None: |
485 newrev = self.target | 497 newrev = self.target |
486 else: | 498 else: |
487 newrev = repo[newnode].rev() | 499 newrev = repo[newnode].rev() |
488 for oldrev in self.state.iterkeys(): | 500 for oldrev in self.state.iterkeys(): |
710 retcode = rbsrt._preparenewrebase(dest, rebaseset) | 722 retcode = rbsrt._preparenewrebase(dest, rebaseset) |
711 if retcode is not None: | 723 if retcode is not None: |
712 return retcode | 724 return retcode |
713 | 725 |
714 with repo.transaction('rebase') as tr: | 726 with repo.transaction('rebase') as tr: |
727 dsguard = dirstateguard.dirstateguard(repo, 'rebase') | |
715 try: | 728 try: |
716 rbsrt._performrebase(tr) | 729 rbsrt._performrebase(tr) |
730 dsguard.close() | |
731 release(dsguard) | |
717 except error.InterventionRequired: | 732 except error.InterventionRequired: |
733 dsguard.close() | |
734 release(dsguard) | |
718 tr.close() | 735 tr.close() |
736 raise | |
737 except Exception: | |
738 release(dsguard) | |
719 raise | 739 raise |
720 rbsrt._finishrebase() | 740 rbsrt._finishrebase() |
721 finally: | 741 finally: |
722 release(lock, wlock) | 742 release(lock, wlock) |
723 | 743 |
838 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None, | 858 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None, |
839 keepbranches=False, date=None): | 859 keepbranches=False, date=None): |
840 '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev | 860 '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev |
841 but also store useful information in extra. | 861 but also store useful information in extra. |
842 Return node of committed revision.''' | 862 Return node of committed revision.''' |
843 dsguard = dirstateguard.dirstateguard(repo, 'rebase') | 863 repo.setparents(repo[p1].node(), repo[p2].node()) |
844 try: | 864 ctx = repo[rev] |
845 repo.setparents(repo[p1].node(), repo[p2].node()) | 865 if commitmsg is None: |
846 ctx = repo[rev] | 866 commitmsg = ctx.description() |
847 if commitmsg is None: | 867 keepbranch = keepbranches and repo[p1].branch() != ctx.branch() |
848 commitmsg = ctx.description() | 868 extra = {'rebase_source': ctx.hex()} |
849 keepbranch = keepbranches and repo[p1].branch() != ctx.branch() | 869 if extrafn: |
850 extra = {'rebase_source': ctx.hex()} | 870 extrafn(ctx, extra) |
851 if extrafn: | 871 |
852 extrafn(ctx, extra) | 872 targetphase = max(ctx.phase(), phases.draft) |
853 | 873 overrides = {('phases', 'new-commit'): targetphase} |
854 targetphase = max(ctx.phase(), phases.draft) | 874 with repo.ui.configoverride(overrides, 'rebase'): |
855 overrides = {('phases', 'new-commit'): targetphase} | 875 if keepbranch: |
856 with repo.ui.configoverride(overrides, 'rebase'): | 876 repo.ui.setconfig('ui', 'allowemptycommit', True) |
857 if keepbranch: | 877 # Commit might fail if unresolved files exist |
858 repo.ui.setconfig('ui', 'allowemptycommit', True) | 878 if date is None: |
859 # Commit might fail if unresolved files exist | 879 date = ctx.date() |
860 if date is None: | 880 newnode = repo.commit(text=commitmsg, user=ctx.user(), |
861 date = ctx.date() | 881 date=date, extra=extra, editor=editor) |
862 newnode = repo.commit(text=commitmsg, user=ctx.user(), | 882 |
863 date=date, extra=extra, editor=editor) | 883 repo.dirstate.setbranch(repo[newnode].branch()) |
864 | 884 return newnode |
865 repo.dirstate.setbranch(repo[newnode].branch()) | |
866 dsguard.close() | |
867 return newnode | |
868 finally: | |
869 release(dsguard) | |
870 | 885 |
871 def rebasenode(repo, rev, p1, base, state, collapse, target): | 886 def rebasenode(repo, rev, p1, base, state, collapse, target): |
872 'Rebase a single revision rev on top of p1 using base as merge ancestor' | 887 'Rebase a single revision rev on top of p1 using base as merge ancestor' |
873 # Merge phase | 888 # Merge phase |
874 # Update to target and merge it with local | 889 # Update to target and merge it with local |