[PATCH] Improve performance of win32.unlink() over CIFS/SMB

Kaz Nishimura kazssym at vx68k.org
Mon Jan 27 00:45:24 CST 2014


I wrote a patch that could improve performance of win32.unlink() over
CIFS/SMB but I want to confirm that it break nothing.  Could you test this
patch if you are using Mercurial on Windows, etiher over CIFS/SMB or on
local disks?  Because I am new to make a patch for Mercurial, please let me
know if I must change the patch further.

FYI, on my environment, I got the following timing results (both are from
the second runs):

Without the patch:

Z:\tmp\xllmnrd>e:hg update --time -r null
0 files updated, 0 files merged, 36 files removed, 0 files unresolved
time: real 9.378 secs (user 0.281+0.000 sys 1.123+0.000)

Z:\tmp\xllmnrd>e:hg update --time -r default
36 files updated, 0 files merged, 0 files removed, 0 files unresolved
time: real 5.432 secs (user 0.265+0.000 sys 0.749+0.000)

With the patch:

Z:\tmp\xllmnrd>e:hg update --time -r null
0 files updated, 0 files merged, 36 files removed, 0 files unresolved
time: real 4.427 secs (user 0.281+0.000 sys 0.749+0.000)

Z:\tmp\xllmnrd>e:hg update --time -r default
36 files updated, 0 files merged, 0 files removed, 0 files unresolved
time: real 4.418 secs (user 0.140+0.000 sys 0.593+0.000)



# HG changeset patch
# User Kaz Nishimura <kazssym at vx68k.org>
# Date 1381984037 -32400
#      Thu Oct 17 13:27:17 2013 +0900
# Branch stable
# Node ID d854b82381330cee14c01742243ad87af8677795
# Parent  dbf305f499613e6b833847b72f1eb5424f9331cc
win32: try to unlink files without renaming if possible

Unlinking a file with os.rename() and os.unlink() could be slow over CIFS
from
Windows clients due to its protocol overhead.  This patch changes
win32.unlink()
to try an exclusive open with the delete-on-close flag first and if a
sharing
violation is detected, to fall back to the original method.

diff -r dbf305f49961 -r d854b8238133 mercurial/win32.py
--- a/mercurial/win32.py
+++ b/mercurial/win32.py
@@ -25,4 +25,5 @@
 # GetLastError
 _ERROR_SUCCESS = 0
+_ERROR_SHARING_VIOLATION = 32
 _ERROR_INVALID_PARAMETER = 87
 _ERROR_INSUFFICIENT_BUFFER = 122
@@ -60,5 +61,7 @@
 _OPEN_EXISTING = 3

+_FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000
 _FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
+_FILE_FLAG_DELETE_ON_CLOSE = 0x04000000

 # SetFileAttributes
@@ -345,9 +348,16 @@
     '''try to implement POSIX' unlink semantics on Windows'''

-    if os.path.isdir(f):
-        # use EPERM because it is POSIX prescribed value, even though
-        # unlink(2) on directories returns EISDIR on Linux
-        raise IOError(errno.EPERM,
-                      "Unlinking directory not permitted: '%s'" % f)
+    # If we could open f in this way, there must be no other open handles
and
+    # we could expect its name would be deleted immediately when we close
it.
+    # We also expect we will fail to open a directory.
+    fh = _kernel32.CreateFileA(f, 0, 0, None, _OPEN_EXISTING,
+        _FILE_FLAG_OPEN_REPARSE_POINT | _FILE_FLAG_DELETE_ON_CLOSE, None)
+    if fh != _INVALID_HANDLE_VALUE:
+        _kernel32.CloseHandle(fh)
+        return
+    else:
+        e = ctypes.WinError()
+        if e.winerror != _ERROR_SHARING_VIOLATION:
+            raise e

     # POSIX allows to unlink and rename open files. Windows has serious
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://selenic.com/pipermail/mercurial-devel/attachments/20140127/0273b848/attachment.html>


More information about the Mercurial-devel mailing list