[PATCH 2 of 5] util: make atomictempfile avoid ambiguity of file stat if needed

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Tue May 24 12:52:16 EDT 2016


At Tue, 24 May 2016 22:39:26 +0900,
Yuya Nishihara wrote:
> 
> On Thu, 19 May 2016 00:26:28 +0900, FUJIWARA Katsunori wrote:
> > # HG changeset patch
> > # User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
> > # Date 1463584838 -32400
> > #      Thu May 19 00:20:38 2016 +0900
> > # Node ID 561ed91a420adfee1e1386e6dd20fea5ad8c1db5
> > # Parent  dc731ebd60613cf3f08799a8d8dc48435798665b
> > util: make atomictempfile avoid ambiguity of file stat if needed
> > 
> > Ambiguity check is executed at close(), only if:
> > 
> >   - atomictempfile is created with checkambig=True, and
> >   - target file exists before renaming
> > 
> > This restriction avoids performance decrement by needless examination
> > of file stat (for example, filelog doesn't need exact cache
> > validation, even though it uses atomictempfile to write changes out).
> > 
> > See description of filestat class for detail about why the logic in
> > this patch works as expected.
> > 
> > This patch is a part of preparation for "Exact Cache Validation Plan":
> > 
> >     https://www.mercurial-scm.org/wiki/ExactCacheValidationPlan
> > 
> > diff --git a/mercurial/util.py b/mercurial/util.py
> > --- a/mercurial/util.py
> > +++ b/mercurial/util.py
> > @@ -1453,11 +1453,12 @@ class atomictempfile(object):
> >      visible. If the object is destroyed without being closed, all your
> >      writes are discarded.
> >      '''
> > -    def __init__(self, name, mode='w+b', createmode=None):
> > +    def __init__(self, name, mode='w+b', createmode=None, checkambig=False):
> >          self.__name = name      # permanent name
> >          self._tempname = mktempcopy(name, emptyok=('w' in mode),
> >                                      createmode=createmode)
> >          self._fp = posixfile(self._tempname, mode)
> > +        self._checkambig = checkambig
> >  
> >          # delegated methods
> >          self.write = self._fp.write
> > @@ -1468,7 +1469,17 @@ class atomictempfile(object):
> >      def close(self):
> >          if not self._fp.closed:
> >              self._fp.close()
> > -            rename(self._tempname, localpath(self.__name))
> > +            filename = localpath(self.__name)
> > +            oldstat = self._checkambig and filestat(filename)
> > +            if oldstat and oldstat.stat:
> > +                rename(self._tempname, filename)
> > +                newstat = filestat(filename)
> > +                if newstat.isambig(oldstat):
> > +                    # stat of changed file is ambiguous to original one
> > +                    advanced = (oldstat.stat.st_mtime + 1) & 0x7fffffff
> > +                    os.utime(filename, (advanced, advanced))
> 
> There might be a race if two writers do stat-rename-utime, but we don't care
> because that would be unavoidable and wouldn't normally happen thanks to
> wlock/lock. Is that correct?

Yes, this code path is used only for files guarded by wlock/(s)lock,
and such kind of race should be avoided.

Should it be described in filestat (or clients of it) ?

----------------------------------------------------------------------
[FUJIWARA Katsunori]                             foozy at lares.dti.ne.jp


More information about the Mercurial-devel mailing list