/// <summary> /// Wrap all IO operations on setting files with this function to avoid file-in-use errors /// </summary> private void ExecuteSynchronized(Action ioOperation) { var fileName = _fileSystem.GetFullPath(_fileName); // Global: ensure mutex is honored across TS sessions using (var mutex = new Mutex(false, "Global\\" + MutexNamingHelper.GenerateUniqueToken(fileName))) { var owner = false; try { // operations on NuGet.config should be very short lived owner = mutex.WaitOne(TimeSpan.FromMinutes(1)); // decision here is to proceed even if we were not able to get mutex ownership // and let the potential IO errors bubble up. Reasoning is that failure to get // ownership probably means faulty hardware and in this case it's better to report // back than hang ioOperation(); } finally { if (owner) { mutex.ReleaseMutex(); } } } }
/// <remarks> /// We use this method instead of the "safe" methods in FileSystem because it attempts to retry multiple times with delays. /// In our case, if we are unable to perform IO over the machine cache, we want to quit trying immediately. /// </remarks> private bool TryAct(Func <bool> action, string path) { try { // Global: machine cache is per user across TS sessions var mutexName = "Global\\" + MutexNamingHelper.GenerateUniqueToken(FileSystem.GetFullPath(path) ?? path); using (var mutex = new Mutex(false, mutexName)) { bool owner = false; try { try { owner = mutex.WaitOne(TimeSpan.FromMinutes(3)); // ideally we should throw an exception here if !owner such as // throw new TimeoutException(string.Format("Timeout waiting for Machine Cache mutex for {0}", fullPath)); // we decided against it: machine cache operations being "best effort" basis. // this may cause "File in use" exceptions for long lasting operations such as downloading a large package on // a slow network connection } catch (AbandonedMutexException) { // TODO: consider logging a warning; abandonning a mutex is an indication something wrong is going on owner = true; // now mine } return(action()); } finally { if (owner) { mutex.ReleaseMutex(); } } } } catch (IOException) { } catch (UnauthorizedAccessException) { // Do nothing if this fails. } return(false); }