changeset 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 6dc3dc5e9636
children 991e6f728b50
files mercurial/context.py
diffstat 1 files changed, 22 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/context.py	Wed Nov 17 10:22:15 2021 +0100
+++ b/mercurial/context.py	Wed Nov 17 23:37:47 2021 +0100
@@ -46,6 +46,9 @@
     dateutil,
     stringutil,
 )
+from .dirstateutils import (
+    timestamp,
+)
 
 propertycache = util.propertycache
 
@@ -1814,7 +1817,21 @@
                 ):
                     modified.append(f)
                 else:
-                    fixup.append(f)
+                    # XXX note that we have a race windows here since we gather
+                    # the stats after we compared so the file might have
+                    # changed.
+                    #
+                    # However this have always been the case and the
+                    # refactoring moving the code here is improving the
+                    # situation by narrowing the race and moving the two steps
+                    # (comparison + stat) in the same location.
+                    #
+                    # Making this code "correct" is now possible.
+                    s = self[f].lstat()
+                    mode = s.st_mode
+                    size = s.st_size
+                    mtime = timestamp.mtime_of(s)
+                    fixup.append((f, (mode, size, mtime)))
             except (IOError, OSError):
                 # A file become inaccessible in between? Mark it as deleted,
                 # matching dirstate behavior (issue5584).
@@ -1842,13 +1859,13 @@
                     if dirstate.identity() == oldid:
                         if fixup:
                             if dirstate.pendingparentchange():
-                                normal = lambda f: dirstate.update_file(
+                                normal = lambda f, pfd: dirstate.update_file(
                                     f, p1_tracked=True, wc_tracked=True
                                 )
                             else:
                                 normal = dirstate.set_clean
-                            for f in fixup:
-                                normal(f)
+                            for f, pdf in fixup:
+                                normal(f, pdf)
                             # write changes out explicitly, because nesting
                             # wlock at runtime may prevent 'wlock.release()'
                             # after this block from doing so for subsequent
@@ -1890,7 +1907,7 @@
             s.deleted.extend(deleted2)
 
             if fixup and clean:
-                s.clean.extend(fixup)
+                s.clean.extend((f for f, _ in fixup))
 
         self._poststatusfixup(s, fixup)