transaction: clarify the "quick abort" scenario
Right now, the transaction has a code-pass to do a "quick abort" that skip most¹
(too much) of the logic when the right condition are detected²
We are about to improve this logic in multiple aspect. We clarify the code
first.
The conditional return in `_can_quick_abort` looks a bit weird because we are
about to make them more complex very soon.
[1] actually too much
[2] actually not often enough
--- a/mercurial/transaction.py Tue Feb 07 15:27:37 2023 +0100
+++ b/mercurial/transaction.py Tue Feb 14 18:59:04 2023 +0100
@@ -668,42 +668,60 @@
self._file.close()
self._backupsfile.close()
+ quick = self._can_quick_abort(entries)
try:
- if not entries and not self._backupentries:
- if self._backupjournal:
- self._opener.unlink(self._backupjournal)
- if self._journal:
- self._opener.unlink(self._journal)
- return
-
- self._report(_(b"transaction abort!\n"))
-
- try:
- for cat in sorted(self._abortcallback):
- self._abortcallback[cat](self)
- # Prevent double usage and help clear cycles.
- self._abortcallback = None
- _playback(
- self._journal,
- self._report,
- self._opener,
- self._vfsmap,
- entries,
- self._backupentries,
- False,
- checkambigfiles=self._checkambigfiles,
- )
- self._report(_(b"rollback completed\n"))
- except BaseException as exc:
- self._report(_(b"rollback failed - please run hg recover\n"))
- self._report(
- _(b"(failure reason: %s)\n") % stringutil.forcebytestr(exc)
- )
+ if quick:
+ self._do_quick_abort(entries)
+ else:
+ self._do_full_abort(entries)
finally:
self._journal = None
self._releasefn(self, False) # notify failure of transaction
self._releasefn = None # Help prevent cycles.
+ def _can_quick_abort(self, entries):
+ """False if any semantic content have been written on disk
+
+ True if nothing, except temporary files has been writen on disk."""
+ if entries:
+ return False
+ if self._backupentries:
+ return False
+ return True
+
+ def _do_quick_abort(self, entries):
+ """(Silently) do a quick cleanup (see _can_quick_abort)"""
+ assert self._can_quick_abort(entries)
+ if self._backupjournal:
+ self._opener.unlink(self._backupjournal)
+ if self._journal:
+ self._opener.unlink(self._journal)
+
+ def _do_full_abort(self, entries):
+ """(Noisily) rollback all the change introduced by the transaction"""
+ self._report(_(b"transaction abort!\n"))
+ try:
+ for cat in sorted(self._abortcallback):
+ self._abortcallback[cat](self)
+ # Prevent double usage and help clear cycles.
+ self._abortcallback = None
+ _playback(
+ self._journal,
+ self._report,
+ self._opener,
+ self._vfsmap,
+ entries,
+ self._backupentries,
+ False,
+ checkambigfiles=self._checkambigfiles,
+ )
+ self._report(_(b"rollback completed\n"))
+ except BaseException as exc:
+ self._report(_(b"rollback failed - please run hg recover\n"))
+ self._report(
+ _(b"(failure reason: %s)\n") % stringutil.forcebytestr(exc)
+ )
+
BAD_VERSION_MSG = _(
b"journal was created by a different version of Mercurial\n"