[PATCH 3 of 3] histedit: add histedit.singletransaction config option
Durham Goode
durham at fb.com
Wed Mar 8 19:38:19 EST 2017
On 3/8/17 4:33 PM, Durham Goode wrote:
> # HG changeset patch
> # User Durham Goode <durham at fb.com>
> # Date 1489019264 28800
> # Wed Mar 08 16:27:44 2017 -0800
> # Node ID 92225c3757e833d117c91d063cb8d42f6f355eef
> # Parent 265484e77411893d910f2eff4efe02cfe6abd5b7
> histedit: add histedit.singletransaction config option
>
> This adds an option (which defaults to False) to run entire histedits in a
> single transaction. This results in 20-25% faster histedits in large repos where
> transaction startup cost is expensive.
>
> I didn't want to enable this by default because it has some unfortunate side
> effects. For instance, if a pretxncommit hook throws midway through the
> histedit, it will rollback the entire histedit and lose any progress the user
> had made. Same if the user aborts editting a commit message. It's still worth
> turning this on for large repos, but probably not for normal sized repos.
>
> Long term, once we have inmemory merging, we could do the entire histedit in
> memory, without a transaction, then we could selectively rollback just parts of
> it in the event of an exception.
>
> Tested it by running the tests with
> `--extra-config-opt=histedit.singletransaction=True`. The only failure was
> related to the hook rollback issue I mention above.
>
> diff --git a/hgext/histedit.py b/hgext/histedit.py
> --- a/hgext/histedit.py
> +++ b/hgext/histedit.py
> @@ -168,6 +168,13 @@ the drop to be implicit for missing comm
> [histedit]
> dropmissing = True
>
> +By default, histedit will close the transaction after each action, so if there
> +are any errors the latest work is preserved. For performance purposes, you can
> +configure histedit to use a single transaction across the entire histedit::
> +
> + [histedit]
> + singletransaction = True
> +
> """
>
> from __future__ import absolute_import
> @@ -269,6 +276,7 @@ class histeditstate(object):
> self.lock = lock
> self.wlock = wlock
> self.backupfile = None
> + self.tr = None
> if replacements is None:
> self.replacements = []
> else:
The bottom half of this patch is easier to read with diff -w below (but
thunderbird tried to word wrap, so I've truncated some of the long lines
for this paste):
@@ -1105,8 +1113,23 @@ def _continuehistedit(ui, repo, state):
total = len(state.actions)
pos = 0
+ state.tr = None
+
+ # Force an initial state file write, so the user can run
+ # even if there's an exception before the first transaction
+ state.write()
+ try:
+ # Don't use singletransaction by default since it rolls the
+ # transaction back if an unexpected exception happens (like a
+ # pretxncommit hook throws, or the user aborts the commit msg
+ if ui.configbool("histedit", "singletransaction", False):
+ # Don't use a 'with' for the transaction, since actions
+ # and reopen a transaction. For example, if the action +
# external process it may choose to commit the transaction
+ state.tr = repo.transaction('histedit')
+
while state.actions:
- state.write()
+ state.write(tr=state.tr)
actobj = state.actions[0]
pos += 1
ui.progress(_("editing"), pos, actobj.torule(),
@@ -1117,6 +1140,18 @@ def _continuehistedit(ui, repo, state):
state.parentctxnode = parentctx.node()
state.replacements.extend(replacement_)
state.actions.pop(0)
+
+ if state.tr is not None:
+ state.tr.close()
+ except error.InterventionRequired:
+ if state.tr is not None:
+ state.tr.close()
+ raise
+ except Exception:
+ if state.tr is not None:
+ state.tr.abort()
+ raise
+
state.write()
ui.progress(_("editing"), None)
More information about the Mercurial-devel
mailing list