Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/win32.py @ 20528:1a9ebc83a74c
win32: improve the performance of win32.unlink() over CIFS
Emulating POSIX unlink() behavior with os.rename() and os.unlink() is often slow
especially over CIFS from Windows clients due to its protocol overhead. This
patch changes win32.unlink() to try first an exclusive open with the Win32
delete-on-close flag, and if a sharing violation is detected, to fall back to
the original emulation.
This patch also removes a test with os.path.isdir() since we expect opening a
directory shall fail as os.unlink() would.
Example measurements (repeated 3-times after 1-time calibration):
(Without this patch: hg update from null to default)
127 files updated, 0 files merged, 0 files removed, 0 files unresolved
time: real 19.871 secs (user 0.328+0.000 sys 1.794+0.000)
time: real 19.622 secs (user 0.312+0.000 sys 2.044+0.000)
time: real 19.138 secs (user 0.250+0.000 sys 1.872+0.000)
(Without this patch: hg update from default to null)
0 files updated, 0 files merged, 127 files removed, 0 files unresolved
time: real 35.158 secs (user 0.156+0.000 sys 2.512+0.000)
time: real 35.272 secs (user 0.250+0.000 sys 2.512+0.000)
time: real 36.569 secs (user 0.203+0.000 sys 2.387+0.000)
(With this patch: hg update from null to default)
127 files updated, 0 files merged, 0 files removed, 0 files unresolved
time: real 17.893 secs (user 0.328+0.000 sys 1.700+0.000)
time: real 18.512 secs (user 0.265+0.000 sys 1.529+0.000)
time: real 20.238 secs (user 0.312+0.000 sys 1.685+0.000)
(With this patch: hg update from default to null)
0 files updated, 0 files merged, 127 files removed, 0 files unresolved
time: real 12.312 secs (user 0.250+0.000 sys 0.811+0.000)
time: real 12.471 secs (user 0.156+0.000 sys 0.889+0.000)
time: real 9.727 secs (user 0.125+0.000 sys 0.858+0.000)
author | Kaz Nishimura <kazssym@vx68k.org> |
---|---|
date | Thu, 17 Oct 2013 13:27:17 +0900 |
parents | ca6aa8362f33 |
children | 07f9825865de |
comparison
equal
deleted
inserted
replaced
20527:bde426f18e0a | 20528:1a9ebc83a74c |
---|---|
22 | 22 |
23 _INVALID_HANDLE_VALUE = _HANDLE(-1).value | 23 _INVALID_HANDLE_VALUE = _HANDLE(-1).value |
24 | 24 |
25 # GetLastError | 25 # GetLastError |
26 _ERROR_SUCCESS = 0 | 26 _ERROR_SUCCESS = 0 |
27 _ERROR_SHARING_VIOLATION = 32 | |
27 _ERROR_INVALID_PARAMETER = 87 | 28 _ERROR_INVALID_PARAMETER = 87 |
28 _ERROR_INSUFFICIENT_BUFFER = 122 | 29 _ERROR_INSUFFICIENT_BUFFER = 122 |
29 | 30 |
30 # WPARAM is defined as UINT_PTR (unsigned type) | 31 # WPARAM is defined as UINT_PTR (unsigned type) |
31 # LPARAM is defined as LONG_PTR (signed type) | 32 # LPARAM is defined as LONG_PTR (signed type) |
57 _FILE_SHARE_WRITE = 0x00000002 | 58 _FILE_SHARE_WRITE = 0x00000002 |
58 _FILE_SHARE_DELETE = 0x00000004 | 59 _FILE_SHARE_DELETE = 0x00000004 |
59 | 60 |
60 _OPEN_EXISTING = 3 | 61 _OPEN_EXISTING = 3 |
61 | 62 |
63 _FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000 | |
62 _FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 | 64 _FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 |
65 _FILE_FLAG_DELETE_ON_CLOSE = 0x04000000 | |
63 | 66 |
64 # SetFileAttributes | 67 # SetFileAttributes |
65 _FILE_ATTRIBUTE_NORMAL = 0x80 | 68 _FILE_ATTRIBUTE_NORMAL = 0x80 |
66 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000 | 69 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000 |
67 | 70 |
418 return _tochildpid(pi.dwProcessId) | 421 return _tochildpid(pi.dwProcessId) |
419 | 422 |
420 def unlink(f): | 423 def unlink(f): |
421 '''try to implement POSIX' unlink semantics on Windows''' | 424 '''try to implement POSIX' unlink semantics on Windows''' |
422 | 425 |
423 if os.path.isdir(f): | 426 # If we can open f exclusively, no other processes must have open handles |
424 # use EPERM because it is POSIX prescribed value, even though | 427 # for it and we can expect its name will be deleted immediately when we |
425 # unlink(2) on directories returns EISDIR on Linux | 428 # close the handle unless we have another in the same process. We also |
426 raise IOError(errno.EPERM, | 429 # expect we shall simply fail to open f if it is a directory. |
427 "Unlinking directory not permitted: '%s'" % f) | 430 fh = _kernel32.CreateFileA(f, 0, 0, None, _OPEN_EXISTING, |
431 _FILE_FLAG_OPEN_REPARSE_POINT | _FILE_FLAG_DELETE_ON_CLOSE, None) | |
432 if fh != _INVALID_HANDLE_VALUE: | |
433 _kernel32.CloseHandle(fh) | |
434 return | |
435 error = _kernel32.GetLastError() | |
436 if error != _ERROR_SHARING_VIOLATION: | |
437 raise ctypes.WinError(error) | |
428 | 438 |
429 # POSIX allows to unlink and rename open files. Windows has serious | 439 # POSIX allows to unlink and rename open files. Windows has serious |
430 # problems with doing that: | 440 # problems with doing that: |
431 # - Calling os.unlink (or os.rename) on a file f fails if f or any | 441 # - Calling os.unlink (or os.rename) on a file f fails if f or any |
432 # hardlinked copy of f has been opened with Python's open(). There is no | 442 # hardlinked copy of f has been opened with Python's open(). There is no |