[prev in list] [next in list] [prev in thread] [next in thread] 

List:       mercurial-devel
Subject:    D588: win32: use fewer system calls for unlink()
From:       "indygreg (Gregory Szorc)" <phabricator () mercurial-scm ! org>
Date:       2017-08-31 22:32:43
Message-ID: differential-rev-PHID-DREV-7ml6wpgefgpmgndvxr4f-req () phab ! mercurial-scm ! org
[Download RAW message or body]

indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  unlink() on Windows is complicated by the fact that Windows doesn't
  support removing an open file. Our unlink wrapper currently goes
  through a dance where it generates a random filename, renames the
  file, then attempts to unlink.
  
  This is a lot of extra work for what is likely the special case of
  attempting to unlink a file that is open or can't be simply unlinked.
  
  In this commit, we refactor the code to use fewer system calls in
  the common cases of 1) unlink just works 2) file doesn't exist.
  
  For the file doesn't exist case (before)
  
  1. stat() to determine if path is directory
  2. generate random filename
  3. rename()
  
  after:
  
  1. stat() to get path info
  
  For the file not open case (before)
  
  1. stat() to determine if path is directory
  2. generate random filename
  3. rename()
  4. unlink()
  
  after:
  
  1. stat()
  2. unlink()
  
  For the file open case (before)
  
  1. stat() to determine if path is directory
  2. generate random filename
  3. rename()
  4. unlink()
  
  after:
  
  1. stat()
  2. unlink()
  3. generate random filename
  4. rename()
  5. unlink()
  
  There is also a scenario where the unlink fails due to the file being
  marked as read-only. In this case we also introduce an extra unlink()
  call. However, I reckon the common case is the file isn't marked as
  read-only and skipping the random generation and rename is worth it.
  
  I /think/ this change makes bulk file writing on Windows faster. This
  is because vfs.__call__ calls unlink() when a file is opened for
  writing. When writing a few hundred files files as part of a clone or
  working directory update, the extra system calls can matter.
  win32.unlink() did show up in performance profiles, which is what
  caused me to look at this code. But I/O performance is hard to measure
  and I'm not sure if the ~30s off of ~620s for a stream clone unbundle
  on the Firefox repo is indicative of real world performance. I do know
  the new code uses fewer system calls and shouldn't be slower.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D588

AFFECTED FILES
  mercurial/win32.py

CHANGE DETAILS

diff --git a/mercurial/win32.py b/mercurial/win32.py
--- a/mercurial/win32.py
+++ b/mercurial/win32.py
@@ -12,6 +12,7 @@
 import msvcrt
 import os
 import random
+import stat
 import subprocess
 
 from . import (
@@ -522,11 +523,26 @@
 def unlink(f):
     '''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 the path doesn't exist, raise that exception.
+    # If it is a directory, emulate POSIX behavior.
+    try:
+        st = os.stat(f)
+        if stat.S_ISDIR(st.st_mode):
+            # 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)
+    except OSError as e:
+        if e.errno == errno.ENOENT:
+            raise
+
+    # In the common case, a normal unlink will work. Try that first and fall
+    # back to more complexity if and only if we need to.
+    try:
+        os.unlink(f)
+        return
+    except (IOError, OSError) as e:
+        pass
 
     # POSIX allows to unlink and rename open files. Windows has serious
     # problems with doing that:



To: indygreg, #hg-reviewers
Cc: mercurial-devel
_______________________________________________
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic