localrepo: silently recover from abandoned transaction

Summary:
As we changed how Ctrl+C is handled, there would be more "abandoned
transaction"s, just silently cleaned them up.

Practically, we should never hit the "abandoned transaction found" case,
because the `journal` file only contains how to truncate files to recover. Only
legacy revlog uses file truncation and we don't use them in production.

There might be a `journal.backupfiles` that tracks what files to rename to
restore backup. Most of the key files like `bookmarks` are in metalog therefore
no need to use backupfiles to restore. The remaining ones also seem fine to not
restore in the old way:
- dirstate: we use atomic replace on transaction close so it seems unnecessary
  to backup
- fncache: not used by remotefilelog
- phaseroots: not used when narrow-heads is on
- commitcloudstate.<name>.<hash>: source of truth moved to metalog by D35232804 (3807e9662b).
- commitcloud/backedupheads.remote: used for "backed up" rendering in smartlog,
  not fatal if not restored.

We might clean them up later. For now, let's just silently recover without
printing the legacy messages.

Note D33482320 (e75c4ca2d8) is incorrect about `journal` being empty = no-op recover,
since `journal.backupfiles` could be non-empty and trigger side effects on
`recover`.

Reviewed By: muirdm

Differential Revision: D42912639

fbshipit-source-id: 8a576d2b73b2ffc053e4fc699f323a1f72498feb
This commit is contained in:
Jun Wu 2023-02-09 20:19:06 -08:00 committed by Facebook GitHub Bot
parent 58a05bb590
commit ee4cd1bb2b
2 changed files with 8 additions and 17 deletions

View File

@ -1698,15 +1698,7 @@ class localrepository(object):
# No existing transaction - this is the normal case.
pass
else:
if stat.st_size > 0:
# Non-empty transaction already exists - bail.
raise errormod.AbandonedTransactionFoundError(
_("abandoned transaction found"),
hint=_("run '@prog@ recover' to clean up transaction"),
)
else:
self.ui.status(_("cleaning up empty abandoned transaction\n"))
self.recover()
self.recover()
idbase = b"%.40f#%f" % (random.random(), time.time())
ha = hex(hashlib.sha1(idbase).digest())
@ -1959,7 +1951,7 @@ class localrepository(object):
def recover(self):
with self.lock():
if self.svfs.exists("journal"):
self.ui.status(_("rolling back interrupted transaction\n"))
self.ui.debug("rolling back interrupted transaction\n")
vfsmap = {
"": self.svfs,
"shared": self.sharedvfs,

View File

@ -10,20 +10,19 @@
$ newclientrepo foo test:repo_server book
$ cd ../repo
Journal is cleaned up automatically.
$ echo something > .hg/store/journal
$ echo foo > a
$ hg ci -Am0
abort: abandoned transaction found!
(run 'hg recover' to clean up transaction)
[255]
couldn't read journal entry 'something\n'!
$ hg recover
rolling back interrupted transaction
couldn't read journal entry 'something\n'!
no interrupted transaction available
[1]
Empty journal is cleaned up automatically.
$ touch .hg/store/journal
$ hg ci -Am0
cleaning up empty abandoned transaction
rolling back interrupted transaction
nothing changed
[1]