[PATCH 1 of 9 V2] cmdutil: add the class to restore dirstate at unexpected failure easily

Yuya Nishihara yuya at tcha.org
Sun May 3 05:16:39 CDT 2015


On Sun, 03 May 2015 00:59:36 +0900, FUJIWARA Katsunori wrote:
> # HG changeset patch
> # User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
> # Date 1430582197 -32400
> #      Sun May 03 00:56:37 2015 +0900
> # Node ID fac0b879377d014c4081940040d092469635447a
> # Parent  e9edd53770fb77a9787a3e6592a3bf0a29c1bd80
> cmdutil: add the class to restore dirstate at unexpected failure easily
> 
> Before this patch, after "dirstate.write()" execution, there is no way
> to restore dirstate to the original status before "dirstate.write()".
> 
> In some code paths, "dirstate.invalidate()" is used as a kind of
> "restore .hg/dirstate to the original status". But it just avoids
> writing changes in memory out, and doesn't actually restore
> ".hg/dirstate" file. "dirstate.write()" prevents it from working as
> expected.
> 
> To fix the issue that recent (in memory) dirstate isn't visible to
> external process (e.g. "precommit" hooks), "dirstate.write()" should
> be invoked before invocation of external process. But at the same
> time, ".hg/dirstate" should be restored to the status before
> "dirstate.write()" at unexpected failure in some cases.
> 
> This patch adds the class "dirstateguard" to easily restore
> ".hg/dirstate" at unexpected failure. Typical usecase of it is:
> 
>     # (1) build dirstate up
>     ....
> 
>     # (2) write dirstate out, and backup ".hg/dirstate"
>     dsguard = dirstateguard(repo, 'scopename')
>     try:
>         # (3) execute somethig to do:
>         #     this may imply making some additional changes on dirstate
>         ....
> 
>         # (4) unlink backup-ed dirstate file at the end of dsguard scope
>         dsguard.close()
>     finally:
>         # (5) if execution is aborted before "dsguard.close()",
>         #     ".hg/dirstate" is restored from the backup
>         dsguard.release()
[...]
> +    def _abort(self):
> +        # this "invalidate()" prevents "wlock.release()" from writing
> +        # changes of dirstate out after restoring to original status
> +        self.repo.dirstate.invalidate()
> +
> +        self.repo.vfs.write('dirstate', self.repo.vfs.read(self.name))
> +        self.repo.vfs.unlink(self.name)
> +        self.active = False

Do you avoid atomic rename for some reason?
Another process could read 'dirstate' in the middle of vfs.write() even if
wlock was taken.


More information about the Mercurial-devel mailing list