[Differential] [Request, 97 lines] D63: rebase: use one dirstateguard for when using rebase.singletransaction
durham (Durham Goode)
phabricator at mercurial-scm.org
Wed Jul 12 17:56:14 UTC 2017
durham created this revision.
Herald added a subscriber: mercurial-devel.
REVISION SUMMARY
This was previously landed as https://phab.mercurial-scm.org/rHG2519994d25ca405edee20b816e70f2289fee553d but backed out in https://phab.mercurial-scm.org/rHGb63351f6a246cd8d444ed38641054fefc78bff93 because
it broke hooks mid-rebase and caused conflict resolution data loss in the event
of unexpected exceptions. This new version adds the behavior back but behind a
config flag, since the performance improvement is notable in large repositories.
The old commit message was:
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.
REPOSITORY
rHG Mercurial
REVISION DETAIL
https://phab.mercurial-scm.org/D63
AFFECTED FILES
hgext/rebase.py
mercurial/dirstateguard.py
tests/test-rebase-base.t
CHANGE DETAILS
Index: tests/test-rebase-base.t
===================================================================
--- tests/test-rebase-base.t
+++ tests/test-rebase-base.t
@@ -379,3 +379,40 @@
/
o 0: A
+Rebasing using a single transaction
+
+ $ hg init singletr && cd singletr
+ $ cat >> .hg/hgrc <<EOF
+ > [rebase]
+ > singletransaction=True
+ > EOF
+ $ hg debugdrawdag <<'EOF'
+ > Z
+ > |
+ > | D
+ > | |
+ > | C
+ > | |
+ > Y B
+ > |/
+ > A
+ > EOF
+- We should only see two status stored messages. One from the start, one from
+- the end.
+ $ hg rebase --debug -b D -d Z | grep 'status stored'
+ rebase status stored
+ rebase status stored
+ $ hg tglog
+ o 5: D
+ |
+ o 4: C
+ |
+ o 3: B
+ |
+ o 2: Z
+ |
+ o 1: Y
+ |
+ o 0: A
+
+ $ cd ..
Index: mercurial/dirstateguard.py
===================================================================
--- mercurial/dirstateguard.py
+++ mercurial/dirstateguard.py
@@ -43,6 +43,16 @@
# ``release(tr, ....)``.
self._abort()
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ try:
+ if exc_type is None:
+ self.close()
+ finally:
+ self.release()
+
def close(self):
if not self._active: # already inactivated
msg = (_("can't close already inactivated backup: dirstate%s")
Index: hgext/rebase.py
===================================================================
--- hgext/rebase.py
+++ hgext/rebase.py
@@ -479,12 +479,22 @@
editopt = True
editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
revtoreuse = max(self.state)
- newnode = concludenode(repo, revtoreuse, p1, self.external,
- commitmsg=commitmsg,
- extrafn=_makeextrafn(self.extrafns),
- editor=editor,
- keepbranches=self.keepbranchesf,
- date=self.date)
+
+ dsguard = util.nullcontextmanager()
+ if ui.configbool('rebase', 'singletransaction'):
+ dsguard = dirstateguard.dirstateguard(repo, 'rebase')
+ with dsguard:
+ try:
+ newnode = concludenode(repo, revtoreuse, p1, self.external,
+ commitmsg=commitmsg,
+ extrafn=_makeextrafn(self.extrafns),
+ editor=editor,
+ keepbranches=self.keepbranchesf,
+ date=self.date)
+ except error.InterventionRequired:
+ dsguard.close()
+ raise
+
if newnode is None:
newrev = self.dest
else:
@@ -709,17 +719,22 @@
if retcode is not None:
return retcode
+ tr = util.nullcontextmanager()
+ dsguard = util.nullcontextmanager()
+
singletr = ui.configbool('rebase', 'singletransaction')
if singletr:
tr = repo.transaction('rebase')
- else:
- tr = util.nullcontextmanager()
with tr:
- try:
- rbsrt._performrebase(tr if singletr else None)
- except error.InterventionRequired:
- tr.close()
- raise
+ if singletr:
+ dsguard = dirstateguard.dirstateguard(repo, 'rebase')
+ with dsguard:
+ try:
+ rbsrt._performrebase(tr if singletr else None)
+ except error.InterventionRequired:
+ dsguard.close()
+ tr.close()
+ raise
rbsrt._finishrebase()
@@ -846,8 +861,10 @@
'''Commit the wd changes with parents p1 and p2. Reuse commit info from rev
but also store useful information in extra.
Return node of committed revision.'''
- dsguard = dirstateguard.dirstateguard(repo, 'rebase')
- try:
+ dsguard = util.nullcontextmanager()
+ if not repo.ui.configbool('rebase', 'singletransaction'):
+ dsguard = dirstateguard.dirstateguard(repo, 'rebase')
+ with dsguard:
repo.setparents(repo[p1].node(), repo[p2].node())
ctx = repo[rev]
if commitmsg is None:
@@ -869,10 +886,7 @@
date=date, extra=extra, editor=editor)
repo.dirstate.setbranch(repo[newnode].branch())
- dsguard.close()
return newnode
- finally:
- release(dsguard)
def rebasenode(repo, rev, p1, base, state, collapse, dest):
'Rebase a single revision rev on top of p1 using base as merge ancestor'
EMAIL PREFERENCES
https://phab.mercurial-scm.org/settings/panel/emailpreferences/
To: durham
Cc: mercurial-devel, indygreg
More information about the Mercurial-devel
mailing list