[PATCH v4] debug: automate the process of truncating a damaged obsstore (issue5265)

Yuya Nishihara yuya at tcha.org
Fri Jul 8 09:14:08 EDT 2016


On Thu, 7 Jul 2016 11:11:28 -0700, Simon Farnsworth wrote:
> # HG changeset patch
> # User Simon Farnsworth <simonfar at fb.com>
> # Date 1467914757 25200
> #      Thu Jul 07 11:05:57 2016 -0700
> # Node ID 7f643309cbaac46619fc001ebe9a84601e4741e9
> # Parent  fd93b15b5c30d16fd9c9eba61402d07fc4085db3
> debug: automate the process of truncating a damaged obsstore (issue5265)

> +def debugtruncatestore(ui, repo, **opts):
> +    """Fix up repository corruption by truncating damaged files
> +
> +    Most on-disk data structures are designed to be append-only. A failed write
> +    (e.g. due to an unexpected power failure) can leave the file corrupted.
> +
> +    This command attempts to recover from that situation by replacing the
> +    corrupted file with a version that only contains the valid records from the
> +    broken file. It is not guaranteed to remove all corrupt records - it will
> +    only remove corrupt records where normal use of the repo would result in a
> +    crash.
> +
> +    Corrupt files will be renamed with a .corrupt extension before the fixed
> +    version is written out, so that you can examine the corruption and/or undo
> +    this command.
> +
> +    You should normally use :hg:`recover` before resorting to this command.
> +    """
> +
> +    if 'obsolete' in opts:
> +        with repo.lock():
> +            data = repo.svfs.tryread('obsstore')
> +            if data:
> +                (corrupt, data) = obsolete.getvalidobsstore(data)
> +                if corrupt:
> +                    repo.svfs.rename('obsstore', 'obsstore.corrupt')
> +                    if len(data) > 0:
> +                        repo.svfs.write('obsstore', data)
> +                        ui.write(_('truncated damaged obsstore\n'))
> +                    else:
> +                        ui.write(_('deleted unreadable obsstore\n'))
> +                else:
> +                    ui.write(_('no damage to obsstore\n'))
> +            else:
> +                ui.write(_('no obsstore\n'))

The code looks good, but I guess indygreg would suggest you to move the whole
repair function to obsolete.py including reading/writing obsstore. Please
disregard it if I'm wrong.

BTW, I found deleteobsmarkers() in repair.py. Which is the better place to
put new repair function?

> --- a/tests/test-debugcommands.t
> +++ b/tests/test-debugcommands.t
> @@ -126,3 +126,45 @@
>     debugstacktrace.py:7 *in * (glob)
>     debugstacktrace.py:6 *in g (glob)
>     */util.py:* in debugstacktrace (glob)
> +
> +Test corruption-fixing debugtruncatestore command
> +
> +  $ hg init corrupt-obsstore
> +  $ cd corrupt-obsstore
> +  $ cat >> .hg/hgrc << EOF
> +  > [experimental]
> +  > evolution = all
> +  > [extensions]
> +  > evolve =
> +  > EOF
> +  $ echo a > file
> +  $ hg commit -qAm file-a -d 1/1/2001
> +  $ hg debugobsolete
> +
> +  $ echo corrupt > .hg/store/obsstore
> +  $ hg debugobsolete 2> /dev/null
> +  [255]
> +  $ hg debugtruncatestore --obsolete
> +  deleted unreadable obsstore
> +  $ hg debugobsolete
> +
> +  $ echo bee > file
> +  $ hg commit -qAm file-b -d 1/1/2001
> +  $ echo b > file
> +  $ hg commit -qAm file-b -d 1/1/2001
> +  $ hg fold -m file-b -r '.^::.' -d 1/1/2001

"hg fold" can't be used without evolve.py. The test failed.


More information about the Mercurial-devel mailing list