comparison mercurial/context.py @ 42456:87a34c767384

merge: fix race that could cause wrong size in dirstate The problem is that hg merge/update/etc work the following way: 1. figure out what files to update 2. apply the update to disk 3. apply the update to in-memory dirstate 4. write dirstate where step3 looks at the filesystem and assumes it sees the result of step2. If a file is changed between step2 and step3, step3 will record incorrect information in the dirstate. I avoid this by passing the size step3 needs directly from step2, for the common path (not implemented for change/delete conflicts for instance). I didn't fix the same race for the exec bit for now, because it's less likely to be problematic and I had trouble due to the fact that the dirstate stores the permissions differently from the manifest (st_mode vs '' 'l' 'x'), in combination with tests that pretend that symlinks are not supported. However, I moved the lstat from step3 to step2, which should tighten the race window markedly, both for the exec bit and for the mtime. Differential Revision: https://phab.mercurial-scm.org/D6475
author Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
date Mon, 27 May 2019 16:55:46 -0400
parents 602469a91550
children e079e001d536
comparison
equal deleted inserted replaced
42455:5ca136bbd3f6 42456:87a34c767384
1764 def copysource(self): 1764 def copysource(self):
1765 return self._repo.dirstate.copied(self._path) 1765 return self._repo.dirstate.copied(self._path)
1766 1766
1767 def size(self): 1767 def size(self):
1768 return self._repo.wvfs.lstat(self._path).st_size 1768 return self._repo.wvfs.lstat(self._path).st_size
1769 def lstat(self):
1770 return self._repo.wvfs.lstat(self._path)
1769 def date(self): 1771 def date(self):
1770 t, tz = self._changectx.date() 1772 t, tz = self._changectx.date()
1771 try: 1773 try:
1772 return (self._repo.wvfs.lstat(self._path)[stat.ST_MTIME], tz) 1774 return (self._repo.wvfs.lstat(self._path)[stat.ST_MTIME], tz)
1773 except OSError as err: 1775 except OSError as err:
1799 self._repo.wvfs.unlinkpath(self._path, ignoremissing=ignoremissing, 1801 self._repo.wvfs.unlinkpath(self._path, ignoremissing=ignoremissing,
1800 rmdir=rmdir) 1802 rmdir=rmdir)
1801 1803
1802 def write(self, data, flags, backgroundclose=False, **kwargs): 1804 def write(self, data, flags, backgroundclose=False, **kwargs):
1803 """wraps repo.wwrite""" 1805 """wraps repo.wwrite"""
1804 self._repo.wwrite(self._path, data, flags, 1806 return self._repo.wwrite(self._path, data, flags,
1805 backgroundclose=backgroundclose, 1807 backgroundclose=backgroundclose,
1806 **kwargs) 1808 **kwargs)
1807 1809
1808 def markcopied(self, src): 1810 def markcopied(self, src):
1809 """marks this file a copy of `src`""" 1811 """marks this file a copy of `src`"""
1810 self._repo.dirstate.copy(src, self._path) 1812 self._repo.dirstate.copy(src, self._path)
1811 1813