public static void GenerateNupkgMetadataFile(string nupkgPath, string installPath, string hashPath, string nupkgMetadataPath) { ConcurrencyUtilities.ExecuteWithFileLocked(nupkgPath, action: () => { // make sure new hash file doesn't exists within File lock before actually creating it. if (!File.Exists(nupkgMetadataPath)) { var tempNupkgMetadataFilePath = Path.Combine(installPath, Path.GetRandomFileName()); using (var stream = File.Open(nupkgPath, FileMode.Open, FileAccess.Read, FileShare.Read)) using (var packageReader = new PackageArchiveReader(stream)) { // get hash of unsigned content of signed package var packageHash = packageReader.GetContentHashForSignedPackage(CancellationToken.None); // if null, then it's unsigned package so just read the existing sha512 file if (string.IsNullOrEmpty(packageHash)) { packageHash = File.ReadAllText(hashPath); } // write the new hash file var hashFile = new NupkgMetadataFile() { ContentHash = packageHash }; NupkgMetadataFileFormat.Write(tempNupkgMetadataFilePath, hashFile); File.Move(tempNupkgMetadataFilePath, nupkgMetadataPath); } } }); }
public async Task ConcurrencyUtilityBlocksOutOfProc() { // Arrange string fileId = Guid.NewGuid().ToString(); var timeout = new CancellationTokenSource(DefaultTimeOut); var tasks = new Task <int> [3]; // Act using (var sync = await Run(fileId, shouldAbandon: false, token: timeout.Token, shareProcessObject: true, debug: false)) { var result = sync.Result; await WaitForLockToEngage(sync); _value1 = 0; // We should now be blocked, so the value returned from here should not be returned until the process has terminated. tasks[0] = ConcurrencyUtilities.ExecuteWithFileLockedAsync(fileId, WaitForInt1, timeout.Token); _value1 = 1; tasks[1] = ConcurrencyUtilities.ExecuteWithFileLockedAsync(fileId, WaitForInt1, timeout.Token); Assert.False(result.Process.HasExited); await ReleaseLock(sync); using (result.Process) { if (!result.Process.WaitForExit(10000)) { throw new TimeoutException("Process timed out."); } } var fileIdReturned = result.Item2.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)[0]; Assert.Equal(fileId, fileIdReturned.Trim()); } await tasks[0]; // let the first tasks pass await tasks[1]; // let the second tasks pass _value1 = 2; tasks[2] = ConcurrencyUtilities.ExecuteWithFileLockedAsync(fileId, WaitForInt1, timeout.Token); await Task.WhenAll(tasks); Task.WaitAll(tasks); // Assert Assert.True(1 == tasks[0].Result, "task[0]"); Assert.True(1 == tasks[1].Result, "task[1]"); Assert.True(2 == tasks[2].Result, "task[2]"); Assert.False(timeout.IsCancellationRequested); }
private void CreateBreadcrumbFile(string fileName) { string fullFilePath = Path.Combine(_breadcrumbsFolder, fileName); // Execute with file locked because multiple processes can run at the same time ConcurrencyUtilities.ExecuteWithFileLocked(fullFilePath, action: _ => { try { if (!File.Exists(fullFilePath)) { File.Create(fullFilePath).Dispose(); Logger.TraceInformation( "[{0}] Wrote servicing breadcrumb for {1}", _logType, fileName); } } catch (UnauthorizedAccessException exception) { LogBreadcrumbsCreationFailure(fileName, exception); } catch (DirectoryNotFoundException exception) { LogBreadcrumbsCreationFailure(fileName, exception); } }); }
private void ExecuteSynchronized(Action ioOperation) { ConcurrencyUtilities.ExecuteWithFileLocked(filePath: ConfigFilePath, action: () => { try { ioOperation(); } catch (InvalidOperationException e) { throw new NuGetConfigurationException( string.Format(CultureInfo.CurrentCulture, Resources.ShowError_ConfigInvalidOperation, ConfigFilePath, e.Message), e); } catch (UnauthorizedAccessException e) { throw new NuGetConfigurationException( string.Format(CultureInfo.CurrentCulture, Resources.ShowError_ConfigUnauthorizedAccess, ConfigFilePath, e.Message), e); } catch (XmlException e) { throw new NuGetConfigurationException( string.Format(CultureInfo.CurrentCulture, Resources.ShowError_ConfigInvalidXml, ConfigFilePath, e.Message), e); } catch (Exception e) { throw new NuGetConfigurationException( string.Format(CultureInfo.CurrentCulture, Resources.Unknown_Config_Exception, ConfigFilePath, e.Message), e); } }); }
public async Task ConcurrencyUtilities_WaitAcquiresLock() { // Arrange var fileId = Guid.NewGuid().ToString(); var ctsA = new CancellationTokenSource(DefaultTimeOut); var ctsB = new CancellationTokenSource(TimeSpan.Zero); var expected = 3; // Act var actual = await ConcurrencyUtilities.ExecuteWithFileLockedAsync( fileId, async tA => { try { await ConcurrencyUtilities.ExecuteWithFileLockedAsync( fileId, tB => Task.FromResult(0), ctsB.Token); Assert.False(true, "Waiting with a timeout for a lock that has not been released should fail."); } catch (OperationCanceledException) { } return(expected); }, ctsA.Token); // Assert Assert.Equal(expected, actual); }
public async Task <Stream> OpenNupkgStreamAsync(PackageInfo package) { Task <NupkgEntry> task; lock (_cache2) { if (!_cache2.TryGetValue(package.ContentUri, out task)) { task = _cache2[package.ContentUri] = _OpenNupkgStreamAsync(package); } } var result = await task; if (result == null) { return(null); } // Acquire the lock on a file before we open it to prevent this process // from opening a file deleted by the logic in HttpSource.GetAsync() in another process return(await ConcurrencyUtilities.ExecuteWithFileLocked(result.TempFileName, _ => { return Task.FromResult( new FileStream(result.TempFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)); })); }
private async Task <Stream> OpenNupkgStreamAsync(PackageInfo package, CancellationToken cancellationToken) { Task <NupkgEntry> task; lock (_nupkgCache) { if (!_nupkgCache.TryGetValue(package.ContentUri, out task)) { task = _nupkgCache[package.ContentUri] = OpenNupkgStreamAsyncCore(package, cancellationToken); } } var result = await task; if (result == null) { return(null); } // Acquire the lock on a file before we open it to prevent this process // from opening a file deleted by the logic in HttpSource.GetAsync() in another process return(await ConcurrencyUtilities.ExecuteWithFileLockedAsync(result.TempFileName, action : token => { return Task.FromResult( new FileStream(result.TempFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)); }, token : cancellationToken)); }
private async Task <bool> ProcessCacheEntryAsync( CacheEntry cacheEntry, Func <Stream, Task> processStreamAsync, CancellationToken token) { if (cacheEntry.AlreadyProcessed) { return(true); } if (cacheEntry.CacheFile == null) { return(false); } // Acquire the lock on a file before we open it to prevent this process // from opening a file deleted by another HTTP request. using (var cacheStream = await ConcurrencyUtilities.ExecuteWithFileLockedAsync( cacheEntry.CacheFile, lockedToken => { return(Task.FromResult(new FileStream( cacheEntry.CacheFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete, StreamExtensions.BufferSize))); }, token)) { await processStreamAsync(cacheStream); return(true); } }
/// <summary> /// Creates a plugin from the discovered plugin. /// We firstly check the cache for the operation claims for the given request key. /// If there is a valid cache entry, and it does contain the requested operation claim, then we start the plugin, and if need be update the cache value itself. /// If there is a valid cache entry, and it does NOT contain the requested operation claim, then we return a null. /// If there is no valid cache entry or an invalid one, we start the plugin as normally, return an active plugin even if the requested claim is not available, and write a cache entry. /// </summary> /// <param name="result">plugin discovery result</param> /// <param name="requestedOperationClaim">The requested operation claim</param> /// <param name="requestKey">plugin request key</param> /// <param name="packageSourceRepository">package source repository</param> /// <param name="serviceIndex">service index</param> /// <param name="cancellationToken">cancellation token</param> /// <returns>A plugin creation result, null if the requested plugin cannot handle the given operation claim</returns> private async Task <Tuple <bool, PluginCreationResult> > TryCreatePluginAsync( PluginDiscoveryResult result, OperationClaim requestedOperationClaim, PluginRequestKey requestKey, string packageSourceRepository, JObject serviceIndex, CancellationToken cancellationToken) { PluginCreationResult pluginCreationResult = null; var cacheEntry = new PluginCacheEntry(_pluginsCacheDirectory.Value, result.PluginFile.Path, requestKey.PackageSourceRepository); return(await ConcurrencyUtilities.ExecuteWithFileLockedAsync( cacheEntry.CacheFileName, action : async lockedToken => { if (cacheEntry.OperationClaims == null || cacheEntry.OperationClaims.Contains(requestedOperationClaim)) { if (result.PluginFile.State.Value == PluginFileState.Valid) { var plugin = await _pluginFactory.GetOrCreateAsync( result.PluginFile.Path, PluginConstants.PluginArguments, new RequestHandlers(), _connectionOptions, cancellationToken); var utilities = await PerformOneTimePluginInitializationAsync(plugin, cancellationToken); // We still make the GetOperationClaims call even if we have the operation claims cached. This is a way to self-update the cache. var operationClaims = await _pluginOperationClaims.GetOrAdd( requestKey, key => new Lazy <Task <IReadOnlyList <OperationClaim> > >(() => GetPluginOperationClaimsAsync( plugin, packageSourceRepository, serviceIndex, cancellationToken))).Value; if (!EqualityUtility.SequenceEqualWithNullCheck(operationClaims, cacheEntry.OperationClaims)) { cacheEntry.OperationClaims = operationClaims; await cacheEntry.UpdateCacheFileAsync(); } pluginCreationResult = new PluginCreationResult( plugin, utilities.Value, operationClaims); } else { pluginCreationResult = new PluginCreationResult(result.Message); } } return new Tuple <bool, PluginCreationResult>(pluginCreationResult != null, pluginCreationResult); }, token : cancellationToken )); }
public async Task ConcurrencyUtilities_LockStress() { // Arrange using (var testDirectory = TestDirectory.Create()) { // This is the path that uniquely identifies the system-wide mutex. var path = Path.Combine(testDirectory, "ConcurrencyUtilities_LockStress_Verification"); // This is a semaphore use to verify the lock. var verificationSemaphore = new SemaphoreSlim(1); // Iterate a lot, to increase confidence. const int threads = 50; const int iterations = 10; // This is the action that is execute inside of the lock. Func <CancellationToken, Task <bool> > lockedActionAsync = async lockedToken => { var acquired = await verificationSemaphore.WaitAsync(0); if (!acquired) { return(false); } // Hold the lock for a little bit. await Task.Delay(TimeSpan.FromMilliseconds(1)); verificationSemaphore.Release(); return(true); }; // Loop the same action, over and over. Func <int, Task <List <bool> > > loopAsync = async thread => { var loopResults = new List <bool>(); foreach (var iteration in Enumerable.Range(0, iterations)) { var result = await ConcurrencyUtilities.ExecuteWithFileLockedAsync( path, lockedActionAsync, CancellationToken.None); loopResults.Add(result); } return(loopResults); }; // Act var tasks = Enumerable.Range(0, threads).Select(loopAsync); var results = (await Task.WhenAll(tasks)).SelectMany(r => r).ToArray(); // Assert Assert.Equal(threads * iterations, results.Length); Assert.DoesNotContain(false, results); } }
internal static async Task InstallFromStream(Stream stream, Library library, string packagesDirectory, SHA512 sha512) { var packagePathResolver = new DefaultPackagePathResolver(packagesDirectory); var targetPath = packagePathResolver.GetInstallPath(library.Name, library.Version); var targetNuspec = packagePathResolver.GetManifestFilePath(library.Name, library.Version); var targetNupkg = packagePathResolver.GetPackageFilePath(library.Name, library.Version); var hashPath = packagePathResolver.GetHashPath(library.Name, library.Version); // Acquire the lock on a nukpg before we extract it to prevent the race condition when multiple // processes are extracting to the same destination simultaneously await ConcurrencyUtilities.ExecuteWithFileLocked(targetNupkg, async createdNewLock => { // If this is the first process trying to install the target nupkg, go ahead // After this process successfully installs the package, all other processes // waiting on this lock don't need to install it again if (createdNewLock) { Directory.CreateDirectory(targetPath); using (var nupkgStream = new FileStream(targetNupkg, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete)) { await stream.CopyToAsync(nupkgStream); nupkgStream.Seek(0, SeekOrigin.Begin); ExtractPackage(targetPath, nupkgStream); } //// Fixup the casing of the nuspec on disk to match what we expect //var nuspecFile = Directory.EnumerateFiles(targetPath, "*" + Constants.ManifestExtension).Single(); //if (!string.Equals(nuspecFile, targetNuspec, StringComparison.Ordinal)) //{ // Manifest manifest = null; // using (var nuspecStream = File.OpenRead(nuspecFile)) // { // manifest = Manifest.ReadFrom(nuspecStream, validateSchema: false); // manifest.Metadata.Id = library.Name; // } // // Delete the previous nuspec file // File.Delete(nuspecFile); // // Write the new manifest // using (var targetNuspecStream = File.OpenWrite(targetNuspec)) // { // manifest.Save(targetNuspecStream); // } //} stream.Seek(0, SeekOrigin.Begin); var nupkgSHA = Convert.ToBase64String(sha512.ComputeHash(stream)); File.WriteAllText(hashPath, nupkgSHA); } return(0); }); }
public async Task ConcurrencyUtilities_LockStressSynchronous() { // Arrange using (var testDirectory = TestDirectory.Create()) { // This is the path that uniquely identifies the system-wide mutex. var path = Path.Combine(testDirectory, "ConcurrencyUtilities_LockStress_Verification_Synchronous"); // This is a semaphore use to verify the lock. var verificationSemaphore = new SemaphoreSlim(1); // Iterate a lot, to increase confidence. const int threads = 50; const int iterations = 10; // This is the action that is execute inside of the lock. Action lockedActionSync = () => { var acquired = verificationSemaphore.Wait(0); Assert.True(acquired, "Unable to acquire the lock on the semaphore within the file lock"); // Hold the lock for a little bit. Thread.Sleep(TimeSpan.FromMilliseconds(1)); verificationSemaphore.Release(); }; // Loop the same action, over and over. Func <int, Task <List <bool> > > loopAsync = async thread => { var loopResults = new List <bool>(); await Task.Run(() => { foreach (var iteration in Enumerable.Range(0, iterations)) { ConcurrencyUtilities.ExecuteWithFileLocked( path, lockedActionSync); loopResults.Add(true); } }); return(loopResults); }; // Act var tasks = Enumerable.Range(0, threads).Select(loopAsync); var results = (await Task.WhenAll(tasks)).SelectMany(r => r).ToArray(); // Assert Assert.Equal(threads * iterations, results.Length); } }
public static void Do(DirectoryInfo directory, Action <ExclusiveFolderAccess> action) { Task.Run(async() => await ConcurrencyUtilities.ExecuteWithFileLockedAsync <object>( directory.FullName, lockedToken => { action(new ExclusiveFolderAccess(directory)); return(Task.FromResult(new Object())); }, CancellationToken.None)).Wait(); }
private static async Task CommitAsync( LockFileFormat lockFileFormat, IRestoreResult result, ILogger log, bool forceWrite, bool toolCommit, CancellationToken token) { // Don't write the lock file if it is Locked AND we're not re-locking the file if (!result.LockFile.IsLocked || result.RelockFile || toolCommit) { // Avoid writing out the lock file if it is the same to avoid triggering an intellisense // update on a restore with no actual changes. if (forceWrite || result.PreviousLockFile == null || !result.PreviousLockFile.Equals(result.LockFile)) { if (toolCommit) { log.LogDebug($"Writing tool lock file to disk. Path: {result.LockFilePath}"); await ConcurrencyUtilities.ExecuteWithFileLockedAsync( result.LockFilePath, lockedToken => { var lockFileDirectory = Path.GetDirectoryName(result.LockFilePath); Directory.CreateDirectory(lockFileDirectory); lockFileFormat.Write(result.LockFilePath, result.LockFile); return(Task.FromResult(0)); }, token); } else { log.LogMinimal($"Writing lock file to disk. Path: {result.LockFilePath}"); lockFileFormat.Write(result.LockFilePath, result.LockFile); } } else { if (toolCommit) { log.LogDebug($"Tool lock file has not changed. Skipping lock file write. Path: {result.LockFilePath}"); } else { log.LogMinimal($"Lock file has not changed. Skipping lock file write. Path: {result.LockFilePath}"); } } } }
public static async Task <LockFile> ReadWithLock(this LockFileFormat subject, string path) { return(await ConcurrencyUtilities.ExecuteWithFileLockedAsync( path, lockedToken => { var lockFile = FileAccessRetrier.RetryOnFileAccessFailure(() => subject.Read(path)); return lockFile; }, CancellationToken.None)); }
private async Task <HttpSourceResult> TryCache(string uri, string cacheKey, TimeSpan cacheAgeLimit) { var baseFolderName = RemoveInvalidFileNameChars(ComputeHash(_baseUri)); var baseFileName = RemoveInvalidFileNameChars(cacheKey) + ".dat"; #if DNX451 var localAppDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); #else var localAppDataFolder = Environment.GetEnvironmentVariable("LocalAppData"); #endif var cacheFolder = Path.Combine(localAppDataFolder, "kpm", "cache", baseFolderName); var cacheFile = Path.Combine(cacheFolder, baseFileName); if (!Directory.Exists(cacheFolder) && !cacheAgeLimit.Equals(TimeSpan.Zero)) { Directory.CreateDirectory(cacheFolder); } // Acquire the lock on a file before we open it to prevent this process // from opening a file deleted by the logic in HttpSource.GetAsync() in another process return(await ConcurrencyUtilities.ExecuteWithFileLocked(cacheFile, _ => { if (File.Exists(cacheFile)) { var fileInfo = new FileInfo(cacheFile); #if DNX451 var age = DateTime.UtcNow.Subtract(fileInfo.LastWriteTimeUtc); #else var age = DateTime.Now.Subtract(fileInfo.LastWriteTime); #endif if (age < cacheAgeLimit) { var stream = CreateAsyncFileStream( cacheFile, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete); return Task.FromResult(new HttpSourceResult { CacheFileName = cacheFile, Stream = stream, }); } } return Task.FromResult(new HttpSourceResult { CacheFileName = cacheFile, }); })); }
public async Task ConcurrencyUtilities_NormalizePaths() { // Arrange var token = CancellationToken.None; var path1 = "/tmp/packageA/1.0.0"; var path2 = "/tmp/sub/../packageA/1.0.0"; var action1HitSem = new ManualResetEventSlim(); var action1Sem = new ManualResetEventSlim(); var action2Sem = new ManualResetEventSlim(); Func <CancellationToken, Task <bool> > action1 = (ct) => { action1HitSem.Set(); action1Sem.Wait(); return(Task.FromResult(true)); }; Func <CancellationToken, Task <bool> > action2 = (ct) => { action2Sem.Set(); return(Task.FromResult(true)); }; // Act var task1 = Task.Run(async() => await ConcurrencyUtilities.ExecuteWithFileLockedAsync <bool>( path1, action1, token)); var task2Started = action1HitSem.Wait(60 * 1000 * 5, token); Assert.True(task2Started); var task2 = Task.Run(async() => await ConcurrencyUtilities.ExecuteWithFileLockedAsync <bool>( path2, action2, token)); // Wait 1s to verify that task2 has not started await Task.Delay(1000); var task2blocked = !action2Sem.IsSet; action1Sem.Set(); await task1; var result = await task2; // Assert Assert.True(task2blocked); Assert.True(result); }
private IEnumerable <FileInfo> GetInventory( FileInfo file, Func <IEnumerable <FileInfo> > beforeAction, Action action) { var inventory = Enumerable.Empty <FileInfo>(); if (file.Exists) { inventory = LoadInventory(file); } if (inventory.Any()) { return(inventory); } IEnumerable <FileInfo> preInventory; if (beforeAction == null) { preInventory = new List <FileInfo>(); } else { preInventory = beforeAction(); } Task.Run(async() => await ConcurrencyUtilities.ExecuteWithFileLockedAsync <object>( _dataDirectory.FullName, lockedToken => { if (file.Exists) { inventory = LoadInventory(file); } else { action(); inventory = GetFileList().Where(i => !preInventory.Select(p => p.FullName).Contains(i.FullName)); SaveInventory(file, inventory); } return(Task.FromResult(new Object())); }, CancellationToken.None)).Wait(); return(inventory); }
public FileInfoNuGetLock(FileInfo fileInfo) { _cancellationTokenSource = new CancellationTokenSource(); _task = ConcurrencyUtilities.ExecuteWithFileLockedAsync <int>( fileInfo.FullName, lockedToken => { Task.Delay(60000, _cancellationTokenSource.Token).Wait(); return(Task.FromResult(0)); }, _cancellationTokenSource.Token); }
public async Task ConcurrencyUtilities_ZeroTimeoutStillGetsLock() { // Arrange var fileId = Guid.NewGuid().ToString(); var cts = new CancellationTokenSource(TimeSpan.Zero); var expected = 3; // Act var actual = await ConcurrencyUtilities.ExecuteWithFileLockedAsync( fileId, token => Task.FromResult(expected), cts.Token); // Assert Assert.Equal(actual, expected); }
public async Task ConcurrencyUtilityDoesntBlocksInProc() { // Arrange var fileId = nameof(ConcurrencyUtilityDoesntBlocksInProc); var timeout = new CancellationTokenSource(DefaultTimeOut * 2); var cts = new CancellationTokenSource(DefaultTimeOut); var tasks = new Task <int> [4]; // Act tasks[0] = ConcurrencyUtilities.ExecuteWithFileLockedAsync("x" + fileId, WaitForever, cts.Token); _value2 = 0; // We should now be blocked, so the value returned from here should not be // returned until the token is cancelled. tasks[1] = ConcurrencyUtilities.ExecuteWithFileLockedAsync(fileId, WaitForInt2, timeout.Token); await tasks[1]; _value2 = 1; tasks[2] = ConcurrencyUtilities.ExecuteWithFileLockedAsync(fileId, WaitForInt2, timeout.Token); await tasks[2]; // let the first tasks pass we get a deadlock if there is a lock applied by the first task Assert.False(cts.IsCancellationRequested); cts.Cancel(); _value2 = 2; tasks[3] = ConcurrencyUtilities.ExecuteWithFileLockedAsync(fileId, WaitForInt2, timeout.Token); await tasks[3]; await tasks[0]; await Task.WhenAll(tasks); // Assert Assert.Equal(0, tasks[1].Result); Assert.Equal(1, tasks[2].Result); Assert.Equal(2, tasks[3].Result); Assert.False(timeout.IsCancellationRequested); }
public static int Main(string[] args) { if (args.Length == 0) { throw new InvalidOperationException($"usage: [{DebugSwitch}] filename port [{AbandonSwitch}]"); } if (args[0].Equals(DebugSwitch, StringComparison.Ordinal)) { args = args.Skip(1).ToArray(); Debugger.Launch(); Debugger.Break(); } var filename = args[0]; if (string.IsNullOrEmpty(filename)) { throw new InvalidOperationException("Pass a filename"); } _port = int.Parse(args[1]); _abandonLock = args.Length > 2 && args[2].Equals(AbandonSwitch, StringComparison.Ordinal); _reportStarted = !_abandonLock; _client = new TcpClient(); var lockedTask = ConcurrencyUtilities.ExecuteWithFileLockedAsync(filename, WaitInALock, CancellationToken.None); try { lockedTask.Wait(); } catch (AggregateException) { return(2); } Console.WriteLine(filename); return(0); }
public async Task ConcurrencyUtilityBlocksInProc() { // Arrange var fileId = nameof(ConcurrencyUtilityBlocksInProc); var timeout = new CancellationTokenSource(DefaultTimeOut * 2); var cts = new CancellationTokenSource(DefaultTimeOut); var tasks = new Task <int> [4]; // Act tasks[0] = ConcurrencyUtilities.ExecuteWithFileLockedAsync(fileId, WaitForever1, cts.Token); await _waitForEverStarted.WaitAsync(); // We should now be blocked, so the value returned from here should not be returned until the token is cancelled. tasks[1] = ConcurrencyUtilities.ExecuteWithFileLockedAsync(fileId, WaitForInt1, timeout.Token); Assert.False(tasks[0].IsCompleted, $"task status: {tasks[0].Status}"); _value1 = 1; tasks[2] = ConcurrencyUtilities.ExecuteWithFileLockedAsync(fileId, WaitForInt1, timeout.Token); Assert.False(cts.Token.IsCancellationRequested); cts.Cancel(); await tasks[1]; // let the first tasks pass await tasks[2]; // let the first tasks pass _value1 = 2; tasks[3] = ConcurrencyUtilities.ExecuteWithFileLockedAsync(fileId, WaitForInt1, timeout.Token); await tasks[3]; // Assert Assert.Equal(TaskStatus.Canceled, tasks[0].Status); Assert.Equal(1, tasks[1].Result); Assert.Equal(1, tasks[2].Result); Assert.Equal(2, tasks[3].Result); Assert.False(timeout.IsCancellationRequested); }
private static async Task <NuGetExe> DownloadNuGetExeAsync( string requestUri, string fileName, bool supportsIsolatedHttpCache) { var temp = NuGetEnvironment.GetFolderPath(NuGetFolderPath.Temp); var path = Path.Combine(temp, fileName); var verifiedPath = await _verifiedPaths.GetOrAdd( path, thisPath => ConcurrencyUtilities.ExecuteWithFileLockedAsync( thisPath, async token => { if (File.Exists(thisPath)) { // Make sure we can run the executable. var helpResult = CommandRunner.Run( thisPath, ".", "help", waitForExit: true); if (helpResult.ExitCode == 0) { return(thisPath); } } // Download the executable. using (var httpClient = new System.Net.Http.HttpClient()) using (var stream = await httpClient.GetStreamAsync(requestUri)) using (var fileStream = new FileStream(thisPath, FileMode.Create)) { await stream.CopyToAsync(fileStream); } return(thisPath); }, CancellationToken.None)); return(new NuGetExe(verifiedPath, supportsIsolatedHttpCache)); }
public FileInfoNuGetLock(FileInfo fileInfo) { var taskCompletionSource = new TaskCompletionSource <string>(); _cancellationTokenSource = new CancellationTokenSource(); _task = Task.Run(async() => await ConcurrencyUtilities.ExecuteWithFileLockedAsync <int>( fileInfo.FullName, cancellationToken => { taskCompletionSource.SetResult("Lock is taken so test can continue"); Task.Delay(60000, cancellationToken).Wait(); return(Task.FromResult(0)); }, _cancellationTokenSource.Token)); taskCompletionSource.Task.Wait(); }
public static async Task <LockFile> ReadWithLock(this LockFileFormat subject, string path) { if (!File.Exists(path)) { throw new GracefulException(string.Join( Environment.NewLine, string.Format(LocalizableStrings.FileNotFound, path), LocalizableStrings.ProjectNotRestoredOrRestoreFailed)); } return(await ConcurrencyUtilities.ExecuteWithFileLockedAsync( path, lockedToken => { var lockFile = FileAccessRetrier.RetryOnFileAccessFailure(() => subject.Read(path)); return lockFile; }, CancellationToken.None)); }
public static async Task <LockFile> ReadWithLock(this LockFileFormat subject, string path) { if (!File.Exists(path)) { throw new GracefulException(string.Join( Environment.NewLine, $"File not found `{path}`.", "The project may not have been restored or restore failed - run `dotnet restore`")); } return(await ConcurrencyUtilities.ExecuteWithFileLockedAsync( path, lockedToken => { var lockFile = FileAccessRetrier.RetryOnFileAccessFailure(() => subject.Read(path)); return lockFile; }, CancellationToken.None)); }
public static async Task <LockFile> ReadWithLock(this LockFileFormat subject, string path) { return(await ConcurrencyUtilities.ExecuteWithFileLockedAsync( path, lockedToken => { if (!File.Exists(path)) { throw new GracefulException(string.Join( Environment.NewLine, string.Format(Resources.GetString("FileNotFound"), path), Resources.GetString("ProjectNotRestoredOrRestoreFailed"))); } var lockFile = FileAccessRetrier.RetryOnFileAccessFailure(() => subject.Read(path), Resources.GetString("CouldNotAccessAssetsFile")); return lockFile; }, CancellationToken.None)); }
public async Task <T> ExecuteAsync <T>( Func <int, CancellationToken, Task <T> > action, CancellationToken token) { int port = _basePort - 1; while (true) { token.ThrowIfCancellationRequested(); port++; if (port > 65535) { throw new InvalidOperationException("Exceeded port range"); } // ListUsedTCPPort prevents port contention with other apps. if (!IsTcpPortAvailable(port)) { continue; } // WaitForLockAsync prevents port contention with this app. string portLockName = $"NuGet-Port-{port}"; var tryOnceCts = new CancellationTokenSource(TimeSpan.Zero); try { var attemptedPort = port; return(await ConcurrencyUtilities.ExecuteWithFileLockedAsync <T>( portLockName, t => action(attemptedPort, token), tryOnceCts.Token)); } catch (OperationCanceledException) { } } }
/// <summary> /// Caching Get request. /// </summary> public async Task <T> GetAsync <T>( HttpSourceCachedRequest request, Func <HttpSourceResult, Task <T> > processAsync, ILogger log, CancellationToken token) { var cacheResult = HttpCacheUtility.InitializeHttpCacheResult( HttpCacheDirectory, _sourceUri, request.CacheKey, request.CacheContext); return(await ConcurrencyUtilities.ExecuteWithFileLockedAsync( cacheResult.CacheFile, action : async lockedToken => { cacheResult.Stream = TryReadCacheFile(request.Uri, cacheResult.MaxAge, cacheResult.CacheFile); if (cacheResult.Stream != null) { log.LogInformation(string.Format(CultureInfo.InvariantCulture, " " + Strings.Http_RequestLog, "CACHE", request.Uri)); // Validate the content fetched from the cache. try { request.EnsureValidContents?.Invoke(cacheResult.Stream); cacheResult.Stream.Seek(0, SeekOrigin.Begin); var httpSourceResult = new HttpSourceResult( HttpSourceResultStatus.OpenedFromDisk, cacheResult.CacheFile, cacheResult.Stream); return await processAsync(httpSourceResult); } catch (Exception e) { cacheResult.Stream.Dispose(); cacheResult.Stream = null; string message = string.Format(CultureInfo.CurrentCulture, Strings.Log_InvalidCacheEntry, request.Uri) + Environment.NewLine + ExceptionUtilities.DisplayMessage(e); log.LogWarning(message); } } Func <HttpRequestMessage> requestFactory = () => { var requestMessage = HttpRequestMessageFactory.Create(HttpMethod.Get, request.Uri, log); foreach (var acceptHeaderValue in request.AcceptHeaderValues) { requestMessage.Headers.Accept.Add(acceptHeaderValue); } return requestMessage; }; Func <Task <ThrottledResponse> > throttledResponseFactory = () => GetThrottledResponse( requestFactory, request.RequestTimeout, request.DownloadTimeout, request.MaxTries, log, lockedToken); using (var throttledResponse = await throttledResponseFactory()) { if (request.IgnoreNotFounds && throttledResponse.Response.StatusCode == HttpStatusCode.NotFound) { var httpSourceResult = new HttpSourceResult(HttpSourceResultStatus.NotFound); return await processAsync(httpSourceResult); } if (throttledResponse.Response.StatusCode == HttpStatusCode.NoContent) { // Ignore reading and caching the empty stream. var httpSourceResult = new HttpSourceResult(HttpSourceResultStatus.NoContent); return await processAsync(httpSourceResult); } throttledResponse.Response.EnsureSuccessStatusCode(); if (!request.CacheContext.DirectDownload) { await HttpCacheUtility.CreateCacheFileAsync( cacheResult, throttledResponse.Response, request.EnsureValidContents, lockedToken); using (var httpSourceResult = new HttpSourceResult( HttpSourceResultStatus.OpenedFromDisk, cacheResult.CacheFile, cacheResult.Stream)) { return await processAsync(httpSourceResult); } } else { // Note that we do not execute the content validator on the response stream when skipping // the cache. We cannot seek on the network stream and it is not valuable to download the // content twice just to validate the first time (considering that the second download could // be different from the first thus rendering the first validation meaningless). using (var stream = await throttledResponse.Response.Content.ReadAsStreamAsync()) using (var httpSourceResult = new HttpSourceResult( HttpSourceResultStatus.OpenedFromNetwork, cacheFileName: null, stream: stream)) { return await processAsync(httpSourceResult); } } } }, token : token)); }