[PATCH 07 of 13 STABLE V4] icasefs: retry directory scan once for already invalidated cache

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Fri Dec 16 06:27:15 CST 2011


# HG changeset patch
# User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
# Date 1324037380 -32400
# Branch stable
# Node ID c7ba906160bde878957e030d01e9ed44213f3889
# Parent  748694149821b3356563a7e12b51f22b1dfdf269
icasefs: retry directory scan once for already invalidated cache

some hg operation (e.g.: qpush) create new files after first
dirstate.walk()-ing, and it invalidates _fspathcache for fspath().

then, fspath() will fail to look up specified name in _fspathcache.

this causes case preservation breaking, because parts of already
normcase()-ed path are used as result at that time.

in this case, file creation and writing out should be done before
fspath() invocation, so the second invocation of os.listdir() has not
so much impact on runtime performance.

diff -r 748694149821 -r c7ba906160bd mercurial/util.py
--- a/mercurial/util.py	Fri Dec 16 21:09:40 2011 +0900
+++ b/mercurial/util.py	Fri Dec 16 21:09:40 2011 +0900
@@ -629,6 +629,13 @@
     if not os.path.lexists(os.path.join(root, name)):
         return None
 
+    def find(p, contents):
+        lenp = len(p)
+        for n in contents:
+            if lenp == len(n) and normcase(n) == p:
+                return n
+        return None
+
     seps = os.sep
     if os.altsep:
         seps = seps + os.altsep
@@ -642,18 +649,19 @@
             result.append(sep)
             continue
 
-        if dir not in _fspathcache:
-            _fspathcache[dir] = os.listdir(dir)
-        contents = _fspathcache[dir]
+        contents = _fspathcache.get(dir, None)
+        if contents is None:
+            contents = os.listdir(dir)
+            _fspathcache[dir] = contents
 
-        lenp = len(part)
-        for n in contents:
-            if lenp == len(n) and normcase(n) == part:
-                result.append(n)
-                break
-        else:
-            # Cannot happen, as the file exists!
-            result.append(part)
+        found = find(part, contents)
+        if not found:
+            # retry once for the corner case: add files after dir walking
+            contents = os.listdir(dir)
+            _fspathcache[dir] = contents
+            found = find(part, contents)
+
+        result.append(found or part)
         dir = os.path.join(dir, part)
 
     return ''.join(result)


More information about the Mercurial-devel mailing list