scmutil: create directories in a race-safe way during update
authorBryan O'Sullivan <bryano@fb.com>
Mon, 11 Feb 2013 16:15:12 -0800
changeset 18668 4034b8d551b1
parent 18667 f12804d3ff80
child 18669 18242716a014
scmutil: create directories in a race-safe way during update With the new parallel update code, it is possible for multiple workers to try to create a hierarchy of directories at the same time. This is hard to trigger in general, but most likely during initial checkout. To deal with these races, we introduce a new ensuredirs function whose contract is to ensure that a directory hierarchy exists - it will ignore a failure that implies that the desired directory already exists.
mercurial/scmutil.py
mercurial/util.py
--- a/mercurial/scmutil.py	Mon Feb 11 14:50:54 2013 -0800
+++ b/mercurial/scmutil.py	Mon Feb 11 16:15:12 2013 -0800
@@ -307,7 +307,7 @@
             if basename:
                 if atomictemp:
                     if not os.path.isdir(dirname):
-                        util.makedirs(dirname, self.createmode)
+                        util.ensuredirs(dirname, self.createmode)
                     return util.atomictempfile(f, mode, self.createmode)
                 try:
                     if 'w' in mode:
@@ -326,7 +326,7 @@
                         raise
                     nlink = 0
                     if not os.path.isdir(dirname):
-                        util.makedirs(dirname, self.createmode)
+                        util.ensuredirs(dirname, self.createmode)
                 if nlink > 0:
                     if self._trustnlink is None:
                         self._trustnlink = nlink > 1 or util.checknlink(f)
@@ -347,7 +347,7 @@
 
         dirname = os.path.dirname(linkname)
         if not os.path.exists(dirname):
-            util.makedirs(dirname, self.createmode)
+            util.ensuredirs(dirname, self.createmode)
 
         if self._cansymlink:
             try:
--- a/mercurial/util.py	Mon Feb 11 14:50:54 2013 -0800
+++ b/mercurial/util.py	Mon Feb 11 16:15:12 2013 -0800
@@ -880,6 +880,16 @@
     if mode is not None:
         os.chmod(name, mode)
 
+def ensuredirs(name, mode=None):
+    """race-safe recursive directory creation"""
+    try:
+        makedirs(name, mode)
+    except OSError, err:
+        if err.errno == errno.EEXIST and os.path.isdir(name):
+            # someone else seems to have won a directory creation race
+            return
+        raise
+
 def readfile(path):
     fp = open(path, 'rb')
     try: