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"