public AbsoluteDirectoryPath Acquire(AbsoluteDirectoryPath baseDirectory) { var buildLock = new Optional <BuildOutputDirLock>(); _fileSystem.MakeUnique(baseDirectory, createName: no => baseDirectory.Rename(MakePathUnique.CreateNumberName(baseDirectory.Name, no)), condition: p => { buildLock = new BuildOutputDirLock( p, () => { BuildOutputDirLock tmp; var tries = 5; while (!_lockedBuildDirectories.TryRemove(p, out tmp) && tries >= 0) { --tries; } }); var result = _lockedBuildDirectories.AddOrUpdate( p, buildLock.Value, (buildOut, oldLock) => oldLock); // If we did update an already lock - try to iterate over other possibilities. return(result != buildLock); }); buildLock.Do(bl => bl.Lock()); return(buildLock .OrThrow(new Exception("Failed to generate a build output directory.")) .BuildDir); }
/// <exception cref="FailedToCreateOutputDir"></exception> public OutputDirWithLock CreateOrReuseOutputDir(AbsoluteDirectoryPath baseDir) { try { const int fileInUse = 0x20; const int fileLocked = 0x21; LockFile lockFile = null; var path = _fileSystem.MakeUnique(baseDir, createName: no => baseDir.Rename(MakePathUnique.CreateNumberName(baseDir.Name, no)), condition: p => { try { if (!_fileSystem.Exists(p)) { _fileSystem.Create(p); } var lockFilePath = p / new FileName(".lock"); lockFile = new LockFile(lockFilePath); return(false); // If the file wasn't locked, break creating of unique directories. } catch (IOException e) { var win32ErrorCode = e.HResult & 0xFFFF; if (win32ErrorCode == fileLocked || win32ErrorCode == fileInUse) { return(true); // If the file was locked, continue creating unique directories. } throw; } }); return(new OutputDirWithLock(path, lockFile)); } catch (Exception e) { throw new FailedToCreateOutputDir(baseDir, e); } }