comparison mercurial/context.py @ 48429:41f40f35278a

status: gather fixup info at comparison time This is still racy, but on a much small windows. In addition, the API now make it possible for it to not be racy. This also unlock other cleanups that we are about to do regarding mtime ambiguity at gathering time. Differential Revision: https://phab.mercurial-scm.org/D11785
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Wed, 17 Nov 2021 23:37:47 +0100
parents 20d0149b8a0a
children 322525db4c98
comparison
equal deleted inserted replaced
48428:6dc3dc5e9636 48429:41f40f35278a
43 util, 43 util,
44 ) 44 )
45 from .utils import ( 45 from .utils import (
46 dateutil, 46 dateutil,
47 stringutil, 47 stringutil,
48 )
49 from .dirstateutils import (
50 timestamp,
48 ) 51 )
49 52
50 propertycache = util.propertycache 53 propertycache = util.propertycache
51 54
52 55
1812 or self.flags(f) != pctx.flags(f) 1815 or self.flags(f) != pctx.flags(f)
1813 or pctx[f].cmp(self[f]) 1816 or pctx[f].cmp(self[f])
1814 ): 1817 ):
1815 modified.append(f) 1818 modified.append(f)
1816 else: 1819 else:
1817 fixup.append(f) 1820 # XXX note that we have a race windows here since we gather
1821 # the stats after we compared so the file might have
1822 # changed.
1823 #
1824 # However this have always been the case and the
1825 # refactoring moving the code here is improving the
1826 # situation by narrowing the race and moving the two steps
1827 # (comparison + stat) in the same location.
1828 #
1829 # Making this code "correct" is now possible.
1830 s = self[f].lstat()
1831 mode = s.st_mode
1832 size = s.st_size
1833 mtime = timestamp.mtime_of(s)
1834 fixup.append((f, (mode, size, mtime)))
1818 except (IOError, OSError): 1835 except (IOError, OSError):
1819 # A file become inaccessible in between? Mark it as deleted, 1836 # A file become inaccessible in between? Mark it as deleted,
1820 # matching dirstate behavior (issue5584). 1837 # matching dirstate behavior (issue5584).
1821 # The dirstate has more complex behavior around whether a 1838 # The dirstate has more complex behavior around whether a
1822 # missing file matches a directory, etc, but we don't need to 1839 # missing file matches a directory, etc, but we don't need to
1840 with self._repo.wlock(False): 1857 with self._repo.wlock(False):
1841 dirstate = self._repo.dirstate 1858 dirstate = self._repo.dirstate
1842 if dirstate.identity() == oldid: 1859 if dirstate.identity() == oldid:
1843 if fixup: 1860 if fixup:
1844 if dirstate.pendingparentchange(): 1861 if dirstate.pendingparentchange():
1845 normal = lambda f: dirstate.update_file( 1862 normal = lambda f, pfd: dirstate.update_file(
1846 f, p1_tracked=True, wc_tracked=True 1863 f, p1_tracked=True, wc_tracked=True
1847 ) 1864 )
1848 else: 1865 else:
1849 normal = dirstate.set_clean 1866 normal = dirstate.set_clean
1850 for f in fixup: 1867 for f, pdf in fixup:
1851 normal(f) 1868 normal(f, pdf)
1852 # write changes out explicitly, because nesting 1869 # write changes out explicitly, because nesting
1853 # wlock at runtime may prevent 'wlock.release()' 1870 # wlock at runtime may prevent 'wlock.release()'
1854 # after this block from doing so for subsequent 1871 # after this block from doing so for subsequent
1855 # changing files 1872 # changing files
1856 tr = self._repo.currenttransaction() 1873 tr = self._repo.currenttransaction()
1888 modified2, deleted2, fixup = self._checklookup(cmp) 1905 modified2, deleted2, fixup = self._checklookup(cmp)
1889 s.modified.extend(modified2) 1906 s.modified.extend(modified2)
1890 s.deleted.extend(deleted2) 1907 s.deleted.extend(deleted2)
1891 1908
1892 if fixup and clean: 1909 if fixup and clean:
1893 s.clean.extend(fixup) 1910 s.clean.extend((f for f, _ in fixup))
1894 1911
1895 self._poststatusfixup(s, fixup) 1912 self._poststatusfixup(s, fixup)
1896 1913
1897 if match.always(): 1914 if match.always():
1898 # cache for performance 1915 # cache for performance