Mercurial > public > mercurial-scm > hg
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 |