# HG changeset patch # User Bryan O'Sullivan # Date 1360628112 28800 # Node ID 4034b8d551b116b882920466e1d209e475a62721 # Parent f12804d3ff801b989cb2aab1aad93047a8db46f1 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. diff -r f12804d3ff80 -r 4034b8d551b1 mercurial/scmutil.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: diff -r f12804d3ff80 -r 4034b8d551b1 mercurial/util.py --- 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: