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.
--- 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: