public async Task<PinnedRemotableDataScope> CreatePinnedRemotableDataScopeAsync(Solution solution, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.SolutionSynchronizationServiceFactory_CreatePinnedRemotableDataScopeAsync, cancellationToken)) { var storage = _assetStorages.CreateStorage(solution.State); var checksum = await solution.State.GetChecksumAsync(cancellationToken).ConfigureAwait(false); var snapshot = new PinnedRemotableDataScope(_assetStorages, storage, checksum); return snapshot; } }
protected override async Task<Session> CreateServiceSessionAsync(string serviceName, PinnedRemotableDataScope snapshot, object callbackTarget, CancellationToken cancellationToken) { // get stream from service hub to communicate snapshot/asset related information // this is the back channel the system uses to move data between VS and remote host var snapshotStream = await RequestServiceAsync(_hubClient, WellKnownServiceHubServices.SnapshotService, _hostGroup, cancellationToken).ConfigureAwait(false); // get stream from service hub to communicate service specific information // this is what consumer actually use to communicate information var serviceStream = await RequestServiceAsync(_hubClient, serviceName, _hostGroup, cancellationToken).ConfigureAwait(false); return await JsonRpcSession.CreateAsync(snapshot, snapshotStream, callbackTarget, serviceStream, cancellationToken).ConfigureAwait(false); }
public RemotableData GetRemotableData(PinnedRemotableDataScope scope, Checksum checksum, CancellationToken cancellationToken) { if (checksum == Checksum.Null) { // check nil case return RemotableData.Null; } // search snapshots we have foreach (var storage in GetStorages(scope)) { var syncObject = storage.TryGetRemotableData(checksum, cancellationToken); if (syncObject != null) { return syncObject; } } // search global assets foreach (var kv in _globalAssets) { cancellationToken.ThrowIfCancellationRequested(); var asset = kv.Value; if (asset.Checksum == checksum) { return asset; } } // if it reached here, it means things get cancelled. due to involving 2 processes, // current design can make slightly staled requests to running even when things cancelled. // if it is other case, remote host side will throw and close connection which will cause // vs to crash. // this should be changed once I address this design issue cancellationToken.ThrowIfCancellationRequested(); return null; }
private IEnumerable<Storage> GetStorages(PinnedRemotableDataScope scope) { if (scope != null) { yield return _storages[scope]; yield break; } using (var solutionProcessed = Creator.CreateChecksumSet()) { foreach (var kv in _storages) { if (!solutionProcessed.Object.Add(kv.Key.SolutionChecksum)) { continue; } yield return kv.Value; } } }
public void UnregisterSnapshot(PinnedRemotableDataScope snapshot) { // calling it multiple times for same snapshot is not allowed. Storage dummy; Contract.ThrowIfFalse(_storages.TryRemove(snapshot, out dummy)); }
public void RegisterSnapshot(PinnedRemotableDataScope snapshot, AssetStorages.Storage storage) { // duplicates are not allowed, there can be multiple snapshots to same solution, so no ref counting. Contract.ThrowIfFalse(_storages.TryAdd(snapshot, storage)); }
public IReadOnlyDictionary<Checksum, RemotableData> GetRemotableData(PinnedRemotableDataScope scope, IEnumerable<Checksum> checksums, CancellationToken cancellationToken) { using (var searchingChecksumsLeft = Creator.CreateChecksumSet(checksums)) { var numberOfChecksumsToSearch = searchingChecksumsLeft.Object.Count; var result = new Dictionary<Checksum, RemotableData>(numberOfChecksumsToSearch); // check nil case if (searchingChecksumsLeft.Object.Remove(Checksum.Null)) { result[Checksum.Null] = RemotableData.Null; } // search checksum trees we have foreach (var storage in GetStorages(scope)) { storage.AppendRemotableData(searchingChecksumsLeft.Object, result, cancellationToken); if (result.Count == numberOfChecksumsToSearch) { // no checksum left to find Contract.Requires(searchingChecksumsLeft.Object.Count == 0); return result; } } // search global assets foreach (var kv in _globalAssets) { cancellationToken.ThrowIfCancellationRequested(); var asset = kv.Value; if (searchingChecksumsLeft.Object.Remove(asset.Checksum)) { result[asset.Checksum] = asset; if (result.Count == numberOfChecksumsToSearch) { // no checksum left to find Contract.Requires(searchingChecksumsLeft.Object.Count == 0); return result; } } } // if it reached here, it means things get cancelled. due to involving 2 processes, // current design can make slightly staled requests to running even when things cancelled. // if it is other case, remote host side will throw and close connection which will cause // vs to crash. // this should be changed once I address this design issue cancellationToken.ThrowIfCancellationRequested(); return result; } }
private async Task<Solution> GetSolutionAsync(ISolutionSynchronizationService service, PinnedRemotableDataScope syncScope) { var workspace = new AdhocWorkspace(); var solutionObject = await service.GetValueAsync<SolutionStateChecksums>(syncScope.SolutionChecksum); var solutionInfo = await service.GetValueAsync<SolutionInfo.SolutionAttributes>(solutionObject.Info).ConfigureAwait(false); var projects = new List<ProjectInfo>(); foreach (var projectObject in solutionObject.Projects.ToProjectObjects(service)) { var projectInfo = await service.GetValueAsync<ProjectInfo.ProjectAttributes>(projectObject.Info).ConfigureAwait(false); if (!workspace.Services.IsSupported(projectInfo.Language)) { continue; } var documents = new List<DocumentInfo>(); foreach (var documentObject in projectObject.Documents.ToDocumentObjects(service)) { var documentInfo = await service.GetValueAsync<DocumentInfo.DocumentAttributes>(documentObject.Info).ConfigureAwait(false); var text = await service.GetValueAsync<SourceText>(documentObject.Text).ConfigureAwait(false); // TODO: do we need version? documents.Add( DocumentInfo.Create( documentInfo.Id, documentInfo.Name, documentInfo.Folders, documentInfo.SourceCodeKind, TextLoader.From(TextAndVersion.Create(text, VersionStamp.Create())), documentInfo.FilePath, documentInfo.IsGenerated)); } var p2p = new List<ProjectReference>(); foreach (var checksum in projectObject.ProjectReferences) { var reference = await service.GetValueAsync<ProjectReference>(checksum).ConfigureAwait(false); p2p.Add(reference); } var metadata = new List<MetadataReference>(); foreach (var checksum in projectObject.MetadataReferences) { var reference = await service.GetValueAsync<MetadataReference>(checksum).ConfigureAwait(false); metadata.Add(reference); } var analyzers = new List<AnalyzerReference>(); foreach (var checksum in projectObject.AnalyzerReferences) { var reference = await service.GetValueAsync<AnalyzerReference>(checksum).ConfigureAwait(false); analyzers.Add(reference); } var additionals = new List<DocumentInfo>(); foreach (var documentObject in projectObject.AdditionalDocuments.ToDocumentObjects(service)) { var documentInfo = await service.GetValueAsync<DocumentInfo.DocumentAttributes>(documentObject.Info).ConfigureAwait(false); var text = await service.GetValueAsync<SourceText>(documentObject.Text).ConfigureAwait(false); // TODO: do we need version? additionals.Add( DocumentInfo.Create( documentInfo.Id, documentInfo.Name, documentInfo.Folders, documentInfo.SourceCodeKind, TextLoader.From(TextAndVersion.Create(text, VersionStamp.Create())), documentInfo.FilePath, documentInfo.IsGenerated)); } var compilationOptions = await service.GetValueAsync<CompilationOptions>(projectObject.CompilationOptions).ConfigureAwait(false); var parseOptions = await service.GetValueAsync<ParseOptions>(projectObject.ParseOptions).ConfigureAwait(false); projects.Add( ProjectInfo.Create( projectInfo.Id, projectInfo.Version, projectInfo.Name, projectInfo.AssemblyName, projectInfo.Language, projectInfo.FilePath, projectInfo.OutputFilePath, compilationOptions, parseOptions, documents, p2p, metadata, analyzers, additionals, projectInfo.IsSubmission)); } return workspace.AddSolution(SolutionInfo.Create(solutionInfo.Id, solutionInfo.Version, solutionInfo.FilePath, projects)); }
public void UnregisterSnapshot(PinnedRemotableDataScope snapshot) { // calling it multiple times for same snapshot is not allowed. Contract.ThrowIfFalse(_storages.TryRemove(snapshot, out var dummy)); }