diff --git a/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs b/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs index 0e186f10d901a..3164ed53107c4 100644 --- a/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs +++ b/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs @@ -11,9 +11,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Serialization; -using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; @@ -78,9 +76,16 @@ public SerializationValidator(HostWorkspaceServices services) Services = services; } - public async Task GetValueAsync(Checksum checksum) + private async Task GetRequiredAssetAsync(Checksum checksum) { var data = await AssetStorage.GetTestAccessor().GetRequiredAssetAsync(checksum, CancellationToken.None).ConfigureAwait(false); + Contract.ThrowIfNull(data); + return new(checksum, data); + } + + public async Task GetValueAsync(Checksum checksum) + { + var data = await GetRequiredAssetAsync(checksum).ConfigureAwait(false); Contract.ThrowIfNull(data.Value); using var context = new SolutionReplicationContext(); @@ -197,7 +202,7 @@ internal async Task VerifyAssetSerializationAsync( Func assetGetter) { // re-create asset from object - var syncObject = await AssetStorage.GetTestAccessor().GetRequiredAssetAsync(checksum, CancellationToken.None).ConfigureAwait(false); + var syncObject = await GetRequiredAssetAsync(checksum).ConfigureAwait(false); var recoveredValue = await GetValueAsync(checksum).ConfigureAwait(false); var recreatedSyncObject = assetGetter(recoveredValue, kind, Serializer); @@ -339,7 +344,7 @@ internal async Task VerifySynchronizationObjectInServiceAsync(ChecksumObjectC internal async Task VerifyChecksumInServiceAsync(Checksum checksum, WellKnownSynchronizationKind kind) { Assert.NotNull(checksum); - var otherObject = await AssetStorage.GetTestAccessor().GetRequiredAssetAsync(checksum, CancellationToken.None).ConfigureAwait(false); + var otherObject = await GetRequiredAssetAsync(checksum).ConfigureAwait(false); ChecksumEqual(checksum, kind, otherObject.Checksum, otherObject.Kind); } diff --git a/src/VisualStudio/Core/Test.Next/Remote/SnapshotSerializationTests.cs b/src/VisualStudio/Core/Test.Next/Remote/SnapshotSerializationTests.cs index accb89f504834..b9a86dc26ad58 100644 --- a/src/VisualStudio/Core/Test.Next/Remote/SnapshotSerializationTests.cs +++ b/src/VisualStudio/Core/Test.Next/Remote/SnapshotSerializationTests.cs @@ -73,6 +73,13 @@ internal static Solution CreateFullSolution(Workspace workspace) loader: TextLoader.From(TextAndVersion.Create(SourceText.From("root = true"), VersionStamp.Create()))))); } + private static async Task GetRequiredAssetAsync(SolutionAssetStorage.Scope scope, Checksum checksum) + { + var data = await scope.GetTestAccessor().GetAssetAsync(checksum, CancellationToken.None).ConfigureAwait(false); + Contract.ThrowIfNull(data); + return new(checksum, data); + } + [Fact] public async Task CreateSolutionSnapshotId_Empty() { @@ -83,16 +90,13 @@ public async Task CreateSolutionSnapshotId_Empty() using var scope = await validator.AssetStorage.StoreAssetsAsync(solution, CancellationToken.None).ConfigureAwait(false); var checksum = scope.SolutionChecksum; - var solutionSyncObject = await scope.GetTestAccessor().GetAssetAsync(checksum, CancellationToken.None).ConfigureAwait(false); + var solutionSyncObject = await GetRequiredAssetAsync(scope, checksum).ConfigureAwait(false); await validator.VerifySynchronizationObjectInServiceAsync(solutionSyncObject).ConfigureAwait(false); var solutionObject = await validator.GetValueAsync(checksum).ConfigureAwait(false); await validator.VerifyChecksumInServiceAsync(solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes).ConfigureAwait(false); - var projectsSyncObject = await scope.GetTestAccessor().GetAssetAsync(solutionObject.Projects.Checksum, CancellationToken.None).ConfigureAwait(false); - await validator.VerifySynchronizationObjectInServiceAsync(projectsSyncObject).ConfigureAwait(false); - Assert.Equal(0, solutionObject.Projects.Count); } @@ -118,7 +122,7 @@ public async Task CreateSolutionSnapshotId_Project() using var scope = await validator.AssetStorage.StoreAssetsAsync(project.Solution, CancellationToken.None).ConfigureAwait(false); var checksum = scope.SolutionChecksum; - var solutionSyncObject = await scope.GetTestAccessor().GetAssetAsync(checksum, CancellationToken.None).ConfigureAwait(false); + var solutionSyncObject = await GetRequiredAssetAsync(scope, checksum).ConfigureAwait(false); await validator.VerifySynchronizationObjectInServiceAsync(solutionSyncObject).ConfigureAwait(false); @@ -126,11 +130,7 @@ public async Task CreateSolutionSnapshotId_Project() await validator.VerifyChecksumInServiceAsync(solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes); - var projectSyncObject = await scope.GetTestAccessor().GetAssetAsync(solutionObject.Projects.Checksum, CancellationToken.None).ConfigureAwait(false); - await validator.VerifySynchronizationObjectInServiceAsync(projectSyncObject).ConfigureAwait(false); - Assert.Equal(1, solutionObject.Projects.Count); - await validator.VerifySnapshotInServiceAsync(validator.ToProjectObjects(solutionObject.Projects)[0], 0, 0, 0, 0, 0).ConfigureAwait(false); } [Fact] @@ -156,15 +156,11 @@ public async Task CreateSolutionSnapshotId() var validator = new SerializationValidator(workspace.Services); using var scope = await validator.AssetStorage.StoreAssetsAsync(document.Project.Solution, CancellationToken.None).ConfigureAwait(false); - var syncObject = await scope.GetTestAccessor().GetAssetAsync(scope.SolutionChecksum, CancellationToken.None).ConfigureAwait(false); + var syncObject = await GetRequiredAssetAsync(scope, scope.SolutionChecksum).ConfigureAwait(false); var solutionObject = await validator.GetValueAsync(syncObject.Checksum).ConfigureAwait(false); await validator.VerifySynchronizationObjectInServiceAsync(syncObject).ConfigureAwait(false); await validator.VerifyChecksumInServiceAsync(solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes).ConfigureAwait(false); - await validator.VerifyChecksumInServiceAsync(solutionObject.Projects.Checksum, WellKnownSynchronizationKind.ChecksumCollection).ConfigureAwait(false); - - Assert.Equal(1, solutionObject.Projects.Count); - await validator.VerifySnapshotInServiceAsync(validator.ToProjectObjects(solutionObject.Projects)[0], 1, 0, 0, 0, 0).ConfigureAwait(false); } [Fact] @@ -194,18 +190,13 @@ public async Task CreateSolutionSnapshotId_Full() var validator = new SerializationValidator(workspace.Services); using var scope = await validator.AssetStorage.StoreAssetsAsync(solution, CancellationToken.None).ConfigureAwait(false); - var syncObject = await scope.GetTestAccessor().GetAssetAsync(scope.SolutionChecksum, CancellationToken.None).ConfigureAwait(false); + var syncObject = await GetRequiredAssetAsync(scope, scope.SolutionChecksum).ConfigureAwait(false); var solutionObject = await validator.GetValueAsync(syncObject.Checksum).ConfigureAwait(false); await validator.VerifySynchronizationObjectInServiceAsync(syncObject).ConfigureAwait(false); await validator.VerifyChecksumInServiceAsync(solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes).ConfigureAwait(false); - await validator.VerifyChecksumInServiceAsync(solutionObject.Projects.Checksum, WellKnownSynchronizationKind.ChecksumCollection).ConfigureAwait(false); Assert.Equal(2, solutionObject.Projects.Count); - - var projects = validator.ToProjectObjects(solutionObject.Projects); - await validator.VerifySnapshotInServiceAsync(projects.Where(p => p.Checksum == firstProjectChecksum).First(), 1, 1, 1, 1, 1).ConfigureAwait(false); - await validator.VerifySnapshotInServiceAsync(projects.Where(p => p.Checksum == secondProjectChecksum).First(), 1, 0, 0, 0, 0).ConfigureAwait(false); } [Fact] diff --git a/src/VisualStudio/Core/Test.Next/Remote/SolutionAsset.cs b/src/VisualStudio/Core/Test.Next/Remote/SolutionAsset.cs new file mode 100644 index 0000000000000..379411f01b4d2 --- /dev/null +++ b/src/VisualStudio/Core/Test.Next/Remote/SolutionAsset.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Serialization; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Remote; + +/// +/// Represents a part of solution snapshot along with its checksum. +/// +internal readonly struct SolutionAsset +{ + /// + /// Indicates what kind of object it. + /// + /// Used in transportation framework and deserialization service to hand shake how to send over data and + /// deserialize serialized data. + /// + public readonly WellKnownSynchronizationKind Kind; + + /// + /// Checksum of . + /// + public readonly Checksum Checksum; + + public readonly object? Value; + + public SolutionAsset(Checksum checksum, object value) + { + var kind = value.GetWellKnownSynchronizationKind(); + // SolutionAsset is not allowed to hold strong references to SourceText. SerializableSourceText is used + // instead to allow data to be released from process address space when it is also held in temporary + // storage. + // https://github.com/dotnet/roslyn/issues/43802 + Contract.ThrowIfTrue(kind is WellKnownSynchronizationKind.SourceText); + + Checksum = checksum; + Kind = kind; + Value = value; + } +} diff --git a/src/Workspaces/Core/Portable/Remote/WellKnownSynchronizationKind.cs b/src/Workspaces/Core/Portable/Remote/WellKnownSynchronizationKind.cs index 5ccb06c14d357..56e7a182e4d6a 100644 --- a/src/Workspaces/Core/Portable/Remote/WellKnownSynchronizationKind.cs +++ b/src/Workspaces/Core/Portable/Remote/WellKnownSynchronizationKind.cs @@ -2,16 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - namespace Microsoft.CodeAnalysis.Serialization { - // TODO: Kind might not actually needed. see whether we can get rid of this internal enum WellKnownSynchronizationKind { - Null, + // Start at a different value from 0 so that if we ever get 0 we know it's a bug. - SolutionState, + SolutionState = 1, ProjectState, DocumentState, diff --git a/src/Workspaces/Core/Portable/Serialization/PooledList.cs b/src/Workspaces/Core/Portable/Serialization/PooledList.cs index e9f5e8424be82..8ee5c6988d8c5 100644 --- a/src/Workspaces/Core/Portable/Serialization/PooledList.cs +++ b/src/Workspaces/Core/Portable/Serialization/PooledList.cs @@ -36,7 +36,11 @@ public static PooledObject> CreateChecksumSet(Checksum checksu public static PooledObject> CreateList() => SharedPools.Default>().GetPooledObject(); - public static PooledObject> CreateResultSet() - => SharedPools.Default>().GetPooledObject(); + public static PooledObject> CreateResultMap(out Dictionary result) + { + var pooled = SharedPools.Default>().GetPooledObject(); + result = pooled.Object; + return pooled; + } } } diff --git a/src/Workspaces/Core/Portable/Serialization/SerializationExtensions.cs b/src/Workspaces/Core/Portable/Serialization/SerializationExtensions.cs index 1cf58a27ba643..81c63a798420b 100644 --- a/src/Workspaces/Core/Portable/Serialization/SerializationExtensions.cs +++ b/src/Workspaces/Core/Portable/Serialization/SerializationExtensions.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; diff --git a/src/Workspaces/Core/Portable/Serialization/SerializerService.cs b/src/Workspaces/Core/Portable/Serialization/SerializerService.cs index 74aec50a9fcf4..315653b19edb9 100644 --- a/src/Workspaces/Core/Portable/Serialization/SerializerService.cs +++ b/src/Workspaces/Core/Portable/Serialization/SerializerService.cs @@ -71,9 +71,6 @@ public Checksum CreateChecksum(object value, CancellationToken cancellationToken switch (kind) { - case WellKnownSynchronizationKind.Null: - return Checksum.Null; - case WellKnownSynchronizationKind.CompilationOptions: case WellKnownSynchronizationKind.ParseOptions: case WellKnownSynchronizationKind.ProjectReference: @@ -110,10 +107,6 @@ public void Serialize(object value, ObjectWriter writer, SolutionReplicationCont switch (kind) { - case WellKnownSynchronizationKind.Null: - // do nothing - return; - case WellKnownSynchronizationKind.SolutionAttributes: case WellKnownSynchronizationKind.ProjectAttributes: case WellKnownSynchronizationKind.DocumentAttributes: @@ -174,7 +167,7 @@ public void Serialize(object value, ObjectWriter writer, SolutionReplicationCont } } - public T? Deserialize(WellKnownSynchronizationKind kind, ObjectReader reader, CancellationToken cancellationToken) + public T Deserialize(WellKnownSynchronizationKind kind, ObjectReader reader, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Serializer_Deserialize, s_logKind, kind, cancellationToken)) { @@ -182,9 +175,6 @@ public void Serialize(object value, ObjectWriter writer, SolutionReplicationCont switch (kind) { - case WellKnownSynchronizationKind.Null: - return default; - case WellKnownSynchronizationKind.SolutionState: return (T)(object)SolutionStateChecksums.Deserialize(reader); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumCollection.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumCollection.cs index 6a9f618673160..548bed42b60e2 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumCollection.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumCollection.cs @@ -39,7 +39,6 @@ IEnumerator IEnumerable.GetEnumerator() public void AddAllTo(HashSet checksums) { - checksums.AddIfNotNullChecksum(this.Checksum); foreach (var checksum in this) checksums.AddIfNotNullChecksum(checksum); } @@ -48,7 +47,7 @@ public void AddAllTo(HashSet checksums) internal static async Task FindAsync( TextDocumentStates documentStates, HashSet searchingChecksumsLeft, - Dictionary result, + Dictionary result, CancellationToken cancellationToken) where TState : TextDocumentState { foreach (var (_, state) in documentStates.States) @@ -67,8 +66,8 @@ internal static void Find( IReadOnlyList values, ChecksumCollection checksums, HashSet searchingChecksumsLeft, - Dictionary result, - CancellationToken cancellationToken) + Dictionary result, + CancellationToken cancellationToken) where T : class { Contract.ThrowIfFalse(values.Count == checksums.Children.Length); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs b/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs index a94175f485250..ea24a05aa446f 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs @@ -72,7 +72,7 @@ public static SolutionStateChecksums Deserialize(ObjectReader reader) public async Task FindAsync( SolutionState state, HashSet searchingChecksumsLeft, - Dictionary result, + Dictionary result, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -98,16 +98,6 @@ public async Task FindAsync( result[FrozenSourceGeneratedDocumentText] = await SerializableSourceText.FromTextDocumentStateAsync(state.FrozenSourceGeneratedDocumentState, cancellationToken).ConfigureAwait(false); } - if (searchingChecksumsLeft.Remove(Projects.Checksum)) - { - result[Projects.Checksum] = Projects; - } - - if (searchingChecksumsLeft.Remove(AnalyzerReferences.Checksum)) - { - result[AnalyzerReferences.Checksum] = AnalyzerReferences; - } - foreach (var (_, projectState) in state.ProjectStates) { if (searchingChecksumsLeft.Count == 0) @@ -209,7 +199,7 @@ public static ProjectStateChecksums Deserialize(ObjectReader reader) public async Task FindAsync( ProjectState state, HashSet searchingChecksumsLeft, - Dictionary result, + Dictionary result, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -242,36 +232,6 @@ public async Task FindAsync( result[ParseOptions] = state.ParseOptions; } - if (searchingChecksumsLeft.Remove(Documents.Checksum)) - { - result[Documents.Checksum] = Documents; - } - - if (searchingChecksumsLeft.Remove(ProjectReferences.Checksum)) - { - result[ProjectReferences.Checksum] = ProjectReferences; - } - - if (searchingChecksumsLeft.Remove(MetadataReferences.Checksum)) - { - result[MetadataReferences.Checksum] = MetadataReferences; - } - - if (searchingChecksumsLeft.Remove(AnalyzerReferences.Checksum)) - { - result[AnalyzerReferences.Checksum] = AnalyzerReferences; - } - - if (searchingChecksumsLeft.Remove(AdditionalDocuments.Checksum)) - { - result[AdditionalDocuments.Checksum] = AdditionalDocuments; - } - - if (searchingChecksumsLeft.Remove(AnalyzerConfigDocuments.Checksum)) - { - result[AnalyzerConfigDocuments.Checksum] = AnalyzerConfigDocuments; - } - ChecksumCollection.Find(state.ProjectReferences, ProjectReferences, searchingChecksumsLeft, result, cancellationToken); ChecksumCollection.Find(state.MetadataReferences, MetadataReferences, searchingChecksumsLeft, result, cancellationToken); ChecksumCollection.Find(state.AnalyzerReferences, AnalyzerReferences, searchingChecksumsLeft, result, cancellationToken); @@ -313,7 +273,7 @@ public static DocumentStateChecksums Deserialize(ObjectReader reader) public async Task FindAsync( TextDocumentState state, HashSet searchingChecksumsLeft, - Dictionary result, + Dictionary result, CancellationToken cancellationToken) { Debug.Assert(state.TryGetStateChecksums(out var stateChecksum) && this == stateChecksum); diff --git a/src/Workspaces/CoreTestUtilities/Fakes/SimpleAssetSource.cs b/src/Workspaces/CoreTestUtilities/Fakes/SimpleAssetSource.cs index df03e9cecb5e5..87d9e31bb9b65 100644 --- a/src/Workspaces/CoreTestUtilities/Fakes/SimpleAssetSource.cs +++ b/src/Workspaces/CoreTestUtilities/Fakes/SimpleAssetSource.cs @@ -37,7 +37,7 @@ public ValueTask> GetAssetsAsync( stream.Position = 0; using var reader = ObjectReader.GetReader(stream, leaveOpen: true, cancellationToken); var asset = deserializerService.Deserialize(data.GetWellKnownSynchronizationKind(), reader, cancellationToken); - Contract.ThrowIfTrue(asset is null); + Contract.ThrowIfNull(asset); results.Add(asset); } else diff --git a/src/Workspaces/Remote/Core/RemoteHostAssetSerialization.cs b/src/Workspaces/Remote/Core/RemoteHostAssetSerialization.cs index 37a673d75add1..2bd56d23a98ba 100644 --- a/src/Workspaces/Remote/Core/RemoteHostAssetSerialization.cs +++ b/src/Workspaces/Remote/Core/RemoteHostAssetSerialization.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -21,7 +20,7 @@ internal static class RemoteHostAssetSerialization { public static async ValueTask WriteDataAsync( Stream stream, - Dictionary assetMap, + Dictionary assetMap, ISerializerService serializer, SolutionReplicationContext context, Checksum solutionChecksum, @@ -55,14 +54,13 @@ public static async ValueTask WriteDataAsync( return; - static void WriteAsset(ObjectWriter writer, ISerializerService serializer, SolutionReplicationContext context, SolutionAsset asset, CancellationToken cancellationToken) + static void WriteAsset(ObjectWriter writer, ISerializerService serializer, SolutionReplicationContext context, object asset, CancellationToken cancellationToken) { - Debug.Assert(asset.Kind != WellKnownSynchronizationKind.Null, "We should not be sending null assets"); - writer.WriteInt32((int)asset.Kind); + Contract.ThrowIfNull(asset); + var kind = asset.GetWellKnownSynchronizationKind(); + writer.WriteInt32((int)kind); - // null is already indicated by checksum and kind above: - if (asset.Value is not null) - serializer.Serialize(asset.Value, writer, context, cancellationToken); + serializer.Serialize(asset, writer, context, cancellationToken); } } @@ -90,9 +88,7 @@ public static ImmutableArray ReadData(Stream stream, Checksum solutionCh // in service hub, cancellation means simply closed stream var result = serializerService.Deserialize(kind, reader, cancellationToken); - - Debug.Assert(result != null, "We should not be requesting null assets"); - + Contract.ThrowIfNull(result); results.Add(result); } diff --git a/src/Workspaces/Remote/Core/SolutionAsset.cs b/src/Workspaces/Remote/Core/SolutionAsset.cs deleted file mode 100644 index 1d77b868d5d2b..0000000000000 --- a/src/Workspaces/Remote/Core/SolutionAsset.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.CodeAnalysis.Serialization; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Remote -{ - /// - /// Represents a part of solution snapshot along with its checksum. - /// - internal readonly struct SolutionAsset - { - public static readonly SolutionAsset Null = new(value: null, Checksum.Null, WellKnownSynchronizationKind.Null); - - /// - /// Indicates what kind of object it. - /// - /// Used in transportation framework and deserialization service to hand shake how to send over data and - /// deserialize serialized data. - /// - public readonly WellKnownSynchronizationKind Kind; - - /// - /// Checksum of . - /// - public readonly Checksum Checksum; - - public readonly object? Value; - - public SolutionAsset(object? value, Checksum checksum, WellKnownSynchronizationKind kind) - { - // SolutionAsset is not allowed to hold strong references to SourceText. SerializableSourceText is used - // instead to allow data to be released from process address space when it is also held in temporary - // storage. - // https://github.com/dotnet/roslyn/issues/43802 - Contract.ThrowIfTrue(kind is WellKnownSynchronizationKind.SourceText); - - Checksum = checksum; - Kind = kind; - Value = value; - } - - public SolutionAsset(Checksum checksum, object value) - : this(value, checksum, value.GetWellKnownSynchronizationKind()) - { - } - } -} diff --git a/src/Workspaces/Remote/Core/SolutionAssetProvider.cs b/src/Workspaces/Remote/Core/SolutionAssetProvider.cs index a27cb644fc29b..c02a124b3d3ba 100644 --- a/src/Workspaces/Remote/Core/SolutionAssetProvider.cs +++ b/src/Workspaces/Remote/Core/SolutionAssetProvider.cs @@ -58,15 +58,15 @@ private async ValueTask WriteAssetsWorkerAsync(PipeWriter pipeWriter, Checksum s var serializer = _services.GetRequiredService(); var scope = assetStorage.GetScope(solutionChecksum); - using var _ = PooledDictionary.GetInstance(out var assetMap); + using var _ = Creator.CreateResultMap(out var resultMap); - await scope.AddAssetsAsync(checksums, assetMap, cancellationToken).ConfigureAwait(false); + await scope.AddAssetsAsync(checksums, resultMap, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); using var stream = new PipeWriterStream(pipeWriter); await RemoteHostAssetSerialization.WriteDataAsync( - stream, assetMap, serializer, scope.ReplicationContext, + stream, resultMap, serializer, scope.ReplicationContext, solutionChecksum, checksums, cancellationToken).ConfigureAwait(false); } diff --git a/src/Workspaces/Remote/Core/SolutionAssetStorage.Scope.cs b/src/Workspaces/Remote/Core/SolutionAssetStorage.Scope.cs index e4f975a470aad..a5ab26a8b3d1b 100644 --- a/src/Workspaces/Remote/Core/SolutionAssetStorage.Scope.cs +++ b/src/Workspaces/Remote/Core/SolutionAssetStorage.Scope.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -53,43 +52,24 @@ public void Dispose() /// public async Task AddAssetsAsync( ImmutableArray checksums, - Dictionary assetMap, + Dictionary assetMap, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - using var checksumsToFind = Creator.CreateChecksumSet(checksums); + using var obj = Creator.CreateChecksumSet(checksums); + var checksumsToFind = obj.Object; - var numberOfChecksumsToSearch = checksumsToFind.Object.Count; + var numberOfChecksumsToSearch = checksumsToFind.Count; + Contract.ThrowIfTrue(checksumsToFind.Contains(Checksum.Null)); - if (checksumsToFind.Object.Remove(Checksum.Null)) - assetMap[Checksum.Null] = SolutionAsset.Null; + await FindAssetsAsync(checksumsToFind, assetMap, cancellationToken).ConfigureAwait(false); - await FindAssetsAsync(checksumsToFind.Object, assetMap, cancellationToken).ConfigureAwait(false); + Contract.ThrowIfTrue(checksumsToFind.Count > 0); Contract.ThrowIfTrue(assetMap.Count != numberOfChecksumsToSearch); - - // no checksum left to find - Debug.Assert(checksumsToFind.Object.Count == 0); - } - - /// - /// Find an assets of the specified within . Once an asset of given checksum is found the corresponding asset is placed to - /// and the checksum is removed from . - /// - private async Task FindAssetsAsync(HashSet remainingChecksumsToFind, Dictionary result, CancellationToken cancellationToken) - { - using var resultPool = Creator.CreateResultSet(); - - await FindAssetsAsync(remainingChecksumsToFind, resultPool.Object, cancellationToken).ConfigureAwait(false); - - foreach (var (checksum, value) in resultPool.Object) - { - result[checksum] = new SolutionAsset(checksum, value); - } } - private async Task FindAssetsAsync(HashSet remainingChecksumsToFind, Dictionary result, CancellationToken cancellationToken) + private async Task FindAssetsAsync(HashSet remainingChecksumsToFind, Dictionary result, CancellationToken cancellationToken) { var solutionState = this.Solution; if (solutionState.TryGetStateChecksums(out var stateChecksums)) @@ -114,24 +94,20 @@ public readonly struct TestAccessor(Scope scope) /// Retrieve asset of a specified available within from /// the storage. /// - public async ValueTask GetAssetAsync(Checksum checksum, CancellationToken cancellationToken) + public async ValueTask GetAssetAsync(Checksum checksum, CancellationToken cancellationToken) { - if (checksum == Checksum.Null) - { - // check nil case - return SolutionAsset.Null; - } + Contract.ThrowIfTrue(checksum == Checksum.Null); using var checksumPool = Creator.CreateChecksumSet(checksum); - using var resultPool = Creator.CreateResultSet(); + using var _ = Creator.CreateResultMap(out var resultPool); - await scope.FindAssetsAsync(checksumPool.Object, resultPool.Object, cancellationToken).ConfigureAwait(false); - Contract.ThrowIfTrue(resultPool.Object.Count != 1); + await scope.FindAssetsAsync(checksumPool.Object, resultPool, cancellationToken).ConfigureAwait(false); + Contract.ThrowIfTrue(resultPool.Count != 1); - var (resultingChecksum, value) = resultPool.Object.First(); + var (resultingChecksum, value) = resultPool.First(); Contract.ThrowIfFalse(checksum == resultingChecksum); - return new SolutionAsset(checksum, value); + return value; } } } diff --git a/src/Workspaces/Remote/Core/SolutionAssetStorage.cs b/src/Workspaces/Remote/Core/SolutionAssetStorage.cs index 5a2a5ffbf3d5c..49050acba04b9 100644 --- a/src/Workspaces/Remote/Core/SolutionAssetStorage.cs +++ b/src/Workspaces/Remote/Core/SolutionAssetStorage.cs @@ -116,7 +116,7 @@ internal TestAccessor(SolutionAssetStorage solutionAssetStorage) _solutionAssetStorage = solutionAssetStorage; } - public async ValueTask GetRequiredAssetAsync(Checksum checksum, CancellationToken cancellationToken) + public async ValueTask GetRequiredAssetAsync(Checksum checksum, CancellationToken cancellationToken) { return await _solutionAssetStorage._checksumToScope.Single().Value.GetTestAccessor().GetAssetAsync(checksum, cancellationToken).ConfigureAwait(false); } diff --git a/src/Workspaces/Remote/ServiceHub/Host/SolutionAssetSource.cs b/src/Workspaces/Remote/ServiceHub/Host/SolutionAssetSource.cs index 95aa88020a349..addf63d8f3512 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/SolutionAssetSource.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/SolutionAssetSource.cs @@ -2,19 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; using System.Collections.Immutable; -using System.IO; -using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Serialization; using Microsoft.ServiceHub.Framework; using Microsoft.VisualStudio.Threading; -using Roslyn.Utilities; -using StreamJsonRpc; namespace Microsoft.CodeAnalysis.Remote { diff --git a/src/Workspaces/Remote/ServiceHub/Host/TestUtils.cs b/src/Workspaces/Remote/ServiceHub/Host/TestUtils.cs index c49594bcba43e..6efa6d2d0e41f 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/TestUtils.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/TestUtils.cs @@ -81,7 +81,7 @@ internal static async Task AssertChecksumsAsync( return; - static void AppendMismatch(List> items, string title, StringBuilder stringBuilder) + static void AppendMismatch(List> items, string title, StringBuilder stringBuilder) { if (items.Count == 0) { @@ -97,13 +97,13 @@ static void AppendMismatch(List> items, string t stringBuilder.AppendLine(); } - async Task>> GetAssetFromAssetServiceAsync(IEnumerable checksums) + async Task>> GetAssetFromAssetServiceAsync(IEnumerable checksums) { - var items = new List>(); + var items = new List>(); foreach (var checksum in checksums) { - items.Add(new KeyValuePair(checksum, await assetService.GetAssetAsync(checksum, CancellationToken.None).ConfigureAwait(false))); + items.Add(new KeyValuePair(checksum, await assetService.GetAssetAsync(checksum, CancellationToken.None).ConfigureAwait(false))); } return items; @@ -141,9 +141,9 @@ async Task> GetAllChildrenChecksumsAsync(Checksum solutionChec /// create checksum to correspoing object map from solution /// this map should contain every parts of solution that can be used to re-create the solution back /// - public static async Task> GetAssetMapAsync(this Solution solution, CancellationToken cancellationToken) + public static async Task> GetAssetMapAsync(this Solution solution, CancellationToken cancellationToken) { - var map = new Dictionary(); + var map = new Dictionary(); await solution.AppendAssetMapAsync(map, cancellationToken).ConfigureAwait(false); return map; } @@ -152,19 +152,19 @@ async Task> GetAllChildrenChecksumsAsync(Checksum solutionChec /// create checksum to correspoing object map from project /// this map should contain every parts of project that can be used to re-create the project back /// - public static async Task> GetAssetMapAsync(this Project project, CancellationToken cancellationToken) + public static async Task> GetAssetMapAsync(this Project project, CancellationToken cancellationToken) { - var map = new Dictionary(); + var map = new Dictionary(); await project.AppendAssetMapAsync(map, cancellationToken).ConfigureAwait(false); return map; } - public static Task AppendAssetMapAsync(this Solution solution, Dictionary map, CancellationToken cancellationToken) + public static Task AppendAssetMapAsync(this Solution solution, Dictionary map, CancellationToken cancellationToken) => AppendAssetMapAsync(solution, map, projectId: null, cancellationToken); public static async Task AppendAssetMapAsync( - this Solution solution, Dictionary map, ProjectId? projectId, CancellationToken cancellationToken) + this Solution solution, Dictionary map, ProjectId? projectId, CancellationToken cancellationToken) { if (projectId == null) { @@ -186,7 +186,7 @@ public static async Task AppendAssetMapAsync( } } - private static async Task AppendAssetMapAsync(this Project project, Dictionary map, CancellationToken cancellationToken) + private static async Task AppendAssetMapAsync(this Project project, Dictionary map, CancellationToken cancellationToken) { if (!RemoteSupportedLanguages.IsSupported(project.Language)) {