private async Task ValidateChecksumAsync( Checksum checksumFromRequest, Solution incrementalSolutionBuilt ) { var currentSolutionChecksum = await incrementalSolutionBuilt.State .GetChecksumAsync(CancellationToken.None) .ConfigureAwait(false); if (checksumFromRequest == currentSolutionChecksum) { return; } var(solutionInfo, options) = await _assetProvider .CreateSolutionInfoAndOptionsAsync(checksumFromRequest, _cancellationToken) .ConfigureAwait(false); var workspace = new TemporaryWorkspace( _hostServices, WorkspaceKind.RemoteTemporaryWorkspace, solutionInfo, options ); await TestUtils .AssertChecksumsAsync( _assetProvider, checksumFromRequest, workspace.CurrentSolution, incrementalSolutionBuilt ) .ConfigureAwait(false); }
private async Task ValidateChecksumAsync(Checksum checksumFromRequest, Solution incrementalSolutionBuilt) { #if DEBUG var currentSolutionChecksum = await incrementalSolutionBuilt.State.GetChecksumAsync(CancellationToken.None).ConfigureAwait(false); if (checksumFromRequest == currentSolutionChecksum) { return; } var solutionFromScratch = await CreateSolutionFromScratchAsync(checksumFromRequest).ConfigureAwait(false); await TestUtils.AssertChecksumsAsync(_assetProvider, checksumFromRequest, solutionFromScratch, incrementalSolutionBuilt).ConfigureAwait(false); async Task <Solution> CreateSolutionFromScratchAsync(Checksum checksum) { var(solutionInfo, options) = await _assetProvider.CreateSolutionInfoAndOptionsAsync(checksum, _cancellationToken).ConfigureAwait(false); var workspace = new TemporaryWorkspace(solutionInfo, options); return(workspace.CurrentSolution); } #else // have this to avoid error on async await Task.CompletedTask.ConfigureAwait(false); #endif }
/// <summary> /// The workspace is designed to be stateless. If someone asks for a solution (through solution checksum), /// it will create one and return the solution. The engine takes care of syncing required data and creating a solution /// corresponding to the given checksum. /// /// but doing that from scratch all the time will be expansive in terms of syncing data, compilation being cached, file being parsed /// and etc. so even if the service itself is stateless, internally it has several caches to improve perf of various parts. /// /// first, it holds onto last solution got built. this will take care of common cases where multiple services running off same solution. /// second, it uses assets cache to hold onto data just synched (within 3 min) so that if it requires to build new solution, /// it can save some time to re-sync data which might just used by other solution. /// third, it holds onto solution from primary branch from Host. and it will try to see whether it can build new solution off the /// primary solution it is holding onto. this will make many solution level cache to be re-used. /// /// the primary solution can be updated in 2 ways. /// first, host will keep track of primary solution changes in host, and call OOP to synch to latest time to time. /// second, engine keeps track of whether a certain request is for primary solution or not, and if it is, /// it let that request to update primary solution cache to latest. /// /// these 2 are complimentary to each other. #1 makes OOP's primary solution to be ready for next call (push), #2 makes OOP's primary /// solution be not stale as much as possible. (pull) /// </summary> private async Task <Solution> CreateSolution_NoLockAsync( AssetProvider assetProvider, Checksum solutionChecksum, bool fromPrimaryBranch, int workspaceVersion, Solution baseSolution, CancellationToken cancellationToken) { try { var updater = new SolutionCreator(Services.HostServices, assetProvider, baseSolution, cancellationToken); // check whether solution is update to the given base solution if (await updater.IsIncrementalUpdateAsync(solutionChecksum).ConfigureAwait(false)) { // create updated solution off the baseSolution var solution = await updater.CreateSolutionAsync(solutionChecksum).ConfigureAwait(false); if (fromPrimaryBranch) { // if the solutionChecksum is for primary branch, update primary workspace cache with the solution return(UpdateSolutionIfPossible(solution, workspaceVersion)); } // otherwise, just return the solution return(solution); } // we need new solution. bulk sync all asset for the solution first. await assetProvider.SynchronizeSolutionAssetsAsync(solutionChecksum, cancellationToken).ConfigureAwait(false); // get new solution info and options var(solutionInfo, options) = await assetProvider.CreateSolutionInfoAndOptionsAsync(solutionChecksum, cancellationToken).ConfigureAwait(false); if (fromPrimaryBranch) { // if the solutionChecksum is for primary branch, update primary workspace cache with new solution if (TrySetCurrentSolution(solutionInfo, workspaceVersion, options, out var solution)) { return(solution); } } // otherwise, just return new solution var workspace = new TemporaryWorkspace(Services.HostServices, WorkspaceKind.RemoteTemporaryWorkspace, solutionInfo, options); return(workspace.CurrentSolution); } catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } }
private async Task <Solution> CreateSolution_NoLockAsync(Checksum solutionChecksum, Solution baseSolution, CancellationToken cancellationToken) { var updater = new SolutionCreator(_assetService, baseSolution, cancellationToken); if (await updater.IsIncrementalUpdateAsync(solutionChecksum).ConfigureAwait(false)) { // solution has updated return(await updater.CreateSolutionAsync(solutionChecksum).ConfigureAwait(false)); } // new solution. bulk sync all asset for the solution await _assetService.SynchronizeSolutionAssetsAsync(solutionChecksum, cancellationToken).ConfigureAwait(false); var workspace = new TemporaryWorkspace(await updater.CreateSolutionInfoAsync(solutionChecksum).ConfigureAwait(false)); return(workspace.CurrentSolution); }
/// <summary> /// SolutionService is designed to be stateless. if someone asks a solution (through solution checksum), /// it will create one and return the solution. the engine takes care of synching required data and creating a solution /// correspoing to the given checksum. /// /// but doing that from scratch all the time wil be expansive in terms of synching data, compilation being cached, file being parsed /// and etc. so even if the service itself is stateless, internally it has several caches to improve perf of various parts. /// /// first, it holds onto last solution got built. this will take care of common cases where multiple services running off same solution. /// second, it uses assets cache to hold onto data just synched (within 3 min) so that if it requires to build new solution, /// it can save some time to re-sync data which might just used by other solution. /// third, it holds onto solution from primary branch from Host. and it will try to see whether it can build new solution off the /// primary solution it is holding onto. this will make many solution level cache to be re-used. /// /// the primary solution can be updated in 2 ways. /// first, host will keep track of primary solution changes in host, and call OOP to synch to latest time to time. /// second, engine keeps track of whether a certain request is for primary solution or not, and if it is, /// it let that request to update primary solution cache to latest. /// /// these 2 are complimentary to each other. #1 makes OOP's primary solution to be ready for next call (push), #2 makes OOP's primary /// solution be not stale as much as possible. (pull) /// </summary> private async Task <Solution> CreateSolution_NoLockAsync( Checksum solutionChecksum, bool fromPrimaryBranch, int workspaceVersion, Solution baseSolution, CancellationToken cancellationToken) { var updater = new SolutionCreator(_assetService, baseSolution, cancellationToken); // check whether solution is update to the given base solution if (await updater.IsIncrementalUpdateAsync(solutionChecksum).ConfigureAwait(false)) { // create updated solution off the baseSolution var solution = await updater.CreateSolutionAsync(solutionChecksum).ConfigureAwait(false); if (fromPrimaryBranch) { // if the solutionChecksum is for primary branch, update primary workspace cache with the solution return(PrimaryWorkspace.UpdateSolutionIfPossible(solution, workspaceVersion)); } // otherwise, just return the solution return(solution); } // we need new solution. bulk sync all asset for the solution first. await _assetService.SynchronizeSolutionAssetsAsync(solutionChecksum, cancellationToken).ConfigureAwait(false); // get new solution info and options var(solutionInfo, options) = await GetSolutionInfoAndOptionsAsync(solutionChecksum, cancellationToken).ConfigureAwait(false); if (fromPrimaryBranch) { // if the solutionChecksum is for primary branch, update primary workspace cache with new solution if (PrimaryWorkspace.TryAddSolutionIfPossible(solutionInfo, workspaceVersion, options, out var solution)) { return(solution); } } // otherwise, just return new solution var workspace = new TemporaryWorkspace(solutionInfo, options); return(workspace.CurrentSolution); }
public async Task<Solution> GetSolutionAsync(Checksum solutionChecksum, OptionSet optionSet, CancellationToken cancellationToken) { if (optionSet == null) { return await GetSolutionAsync(solutionChecksum, cancellationToken).ConfigureAwait(false); } // get solution var baseSolution = await GetSolutionAsync(solutionChecksum, cancellationToken).ConfigureAwait(false); // since options belong to workspace, we can't share solution // create temporary workspace var tempWorkspace = new TemporaryWorkspace(baseSolution); // set merged options tempWorkspace.Options = MergeOptions(tempWorkspace.Options, optionSet); // return new solution return tempWorkspace.CurrentSolution; }
public async Task <Solution> GetSolutionAsync(Checksum solutionChecksum, OptionSet optionSet, CancellationToken cancellationToken) { // get solution var baseSolution = await GetSolutionAsync(solutionChecksum, cancellationToken).ConfigureAwait(false); if (optionSet == null) { return(baseSolution); } // since options belong to workspace, we can't share solution // create temporary workspace var tempWorkspace = new TemporaryWorkspace(baseSolution); // set merged options tempWorkspace.Options = MergeOptions(tempWorkspace.Options, optionSet); // return new solution return(tempWorkspace.CurrentSolution); }
private async Task<Solution> CreateSolution_NoLockAsync(Checksum solutionChecksum, Solution baseSolution, CancellationToken cancellationToken) { var updater = new SolutionCreator(_assetService, baseSolution, cancellationToken); if (await updater.IsIncrementalUpdateAsync(solutionChecksum).ConfigureAwait(false)) { // solution has updated return await updater.CreateSolutionAsync(solutionChecksum).ConfigureAwait(false); } // new solution. bulk sync all asset for the solution await _assetService.SynchronizeSolutionAssetsAsync(solutionChecksum, cancellationToken).ConfigureAwait(false); var workspace = new TemporaryWorkspace(await updater.CreateSolutionInfoAsync(solutionChecksum).ConfigureAwait(false)); return workspace.CurrentSolution; }