-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move to a callback-style approach to deserializing objects (part2) #72944
Merged
Merged
Changes from 9 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
7b02207
avoid more arrays
CyrusNajmabadi 8573ebd
Avoid arrays in more cases
CyrusNajmabadi f5fadb2
Not working
CyrusNajmabadi 17a6af4
Closer
CyrusNajmabadi 5b5baaf
Fallout
CyrusNajmabadi 888e25a
tests
CyrusNajmabadi 56f9c34
Merge branch 'avoidArray' into avoidArray2
CyrusNajmabadi c66e2f7
Merge remote-tracking branch 'upstream/main' into avoidArray2
CyrusNajmabadi 5c4831f
Add assrt
CyrusNajmabadi 8cdec8d
remove
CyrusNajmabadi a5a7605
array builder
CyrusNajmabadi 0896aa6
static lambda
CyrusNajmabadi b54747d
wrap
CyrusNajmabadi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,28 +39,25 @@ public override async ValueTask<T> GetAssetAsync<T>( | |
using var _1 = PooledHashSet<Checksum>.GetInstance(out var checksums); | ||
checksums.Add(checksum); | ||
|
||
using var _2 = PooledDictionary<Checksum, T>.GetInstance(out var results); | ||
await this.SynchronizeAssetsAsync(assetPath, checksums, results, cancellationToken).ConfigureAwait(false); | ||
var called = false; | ||
T? result = default; | ||
await this.SynchronizeAssetsAsync<T, VoidResult>(assetPath, checksums, (_, asset, _) => | ||
{ | ||
Contract.ThrowIfTrue(called); | ||
called = true; | ||
CyrusNajmabadi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
result = asset; | ||
}, default, cancellationToken).ConfigureAwait(false); | ||
|
||
Contract.ThrowIfFalse(called); | ||
Contract.ThrowIfNull((object?)result); | ||
|
||
return results[checksum]; | ||
return result; | ||
} | ||
|
||
public override async ValueTask<ImmutableArray<(Checksum checksum, T asset)>> GetAssetsAsync<T>( | ||
AssetPath assetPath, HashSet<Checksum> checksums, CancellationToken cancellationToken) | ||
public override async ValueTask GetAssetsAsync<T, TArg>( | ||
AssetPath assetPath, HashSet<Checksum> checksums, Action<Checksum, T, TArg> callback, TArg arg, CancellationToken cancellationToken) | ||
{ | ||
using var _ = PooledDictionary<Checksum, T>.GetInstance(out var results); | ||
|
||
await this.SynchronizeAssetsAsync(assetPath, checksums, results, cancellationToken).ConfigureAwait(false); | ||
|
||
var result = new (Checksum checksum, T asset)[checksums.Count]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no intermediary alloc! |
||
var index = 0; | ||
foreach (var (checksum, assetObject) in results) | ||
{ | ||
result[index] = (checksum, assetObject); | ||
index++; | ||
} | ||
|
||
return ImmutableCollectionsMarshal.AsImmutableArray(result); | ||
await this.SynchronizeAssetsAsync(assetPath, checksums, callback, arg, cancellationToken).ConfigureAwait(false); | ||
} | ||
|
||
public async ValueTask SynchronizeSolutionAssetsAsync(Checksum solutionChecksum, CancellationToken cancellationToken) | ||
|
@@ -88,17 +85,15 @@ public async ValueTask SynchronizeSolutionAssetsAsync(Checksum solutionChecksum, | |
|
||
async ValueTask SynchronizeSolutionAssetsWorkerAsync() | ||
{ | ||
using var _1 = PooledDictionary<Checksum, object>.GetInstance(out var checksumToObjects); | ||
|
||
// first, get top level solution state for the given solution checksum | ||
var compilationStateChecksums = await this.GetAssetAsync<SolutionCompilationStateChecksums>( | ||
assetPath: AssetPath.SolutionOnly, solutionChecksum, cancellationToken).ConfigureAwait(false); | ||
|
||
using var _2 = PooledHashSet<Checksum>.GetInstance(out var checksums); | ||
using var _1 = PooledHashSet<Checksum>.GetInstance(out var checksums); | ||
|
||
// second, get direct children of the solution compilation state. | ||
compilationStateChecksums.AddAllTo(checksums); | ||
await this.SynchronizeAssetsAsync<object>(assetPath: AssetPath.SolutionOnly, checksums, results: null, cancellationToken).ConfigureAwait(false); | ||
await this.SynchronizeAssetsAsync<object, VoidResult>(assetPath: AssetPath.SolutionOnly, checksums, callback: null, arg: default, cancellationToken).ConfigureAwait(false); | ||
|
||
// third, get direct children of the solution state. | ||
var stateChecksums = await this.GetAssetAsync<SolutionStateChecksums>( | ||
|
@@ -108,7 +103,13 @@ async ValueTask SynchronizeSolutionAssetsWorkerAsync() | |
// the project states and we want to get that all in one batch. | ||
checksums.Clear(); | ||
stateChecksums.AddAllTo(checksums); | ||
await this.SynchronizeAssetsAsync(assetPath: AssetPath.SolutionAndTopLevelProjectsOnly, checksums, checksumToObjects, cancellationToken).ConfigureAwait(false); | ||
|
||
using var _2 = PooledDictionary<Checksum, object>.GetInstance(out var checksumToObjects); | ||
|
||
await this.SynchronizeAssetsAsync<object, Dictionary<Checksum, object>>( | ||
assetPath: AssetPath.SolutionAndTopLevelProjectsOnly, checksums, | ||
CyrusNajmabadi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
static (checksum, asset, checksumToObjects) => checksumToObjects.Add(checksum, asset), | ||
arg: checksumToObjects, cancellationToken).ConfigureAwait(false); | ||
|
||
// fourth, get all projects and documents in the solution | ||
foreach (var (projectChecksum, _) in stateChecksums.Projects) | ||
|
@@ -151,8 +152,8 @@ async ValueTask SynchronizeProjectAssetsWorkerAsync() | |
AddAll(checksums, projectChecksums.AnalyzerConfigDocuments.Checksums); | ||
|
||
// First synchronize all the top-level info about this project. | ||
await this.SynchronizeAssetsAsync<object>( | ||
assetPath: AssetPath.ProjectAndDocuments(projectChecksums.ProjectId), checksums, results: null, cancellationToken).ConfigureAwait(false); | ||
await this.SynchronizeAssetsAsync<object, VoidResult>( | ||
assetPath: AssetPath.ProjectAndDocuments(projectChecksums.ProjectId), checksums, callback: null, arg: default, cancellationToken).ConfigureAwait(false); | ||
|
||
checksums.Clear(); | ||
|
||
|
@@ -161,8 +162,8 @@ await this.SynchronizeAssetsAsync<object>( | |
await CollectChecksumChildrenAsync(checksums, projectChecksums.AdditionalDocuments).ConfigureAwait(false); | ||
await CollectChecksumChildrenAsync(checksums, projectChecksums.AnalyzerConfigDocuments).ConfigureAwait(false); | ||
|
||
await this.SynchronizeAssetsAsync<object>( | ||
assetPath: AssetPath.ProjectAndDocuments(projectChecksums.ProjectId), checksums, results: null, cancellationToken).ConfigureAwait(false); | ||
await this.SynchronizeAssetsAsync<object, VoidResult>( | ||
assetPath: AssetPath.ProjectAndDocuments(projectChecksums.ProjectId), checksums, callback: null, arg: default, cancellationToken).ConfigureAwait(false); | ||
} | ||
|
||
async ValueTask CollectChecksumChildrenAsync(HashSet<Checksum> checksums, ChecksumsAndIds<DocumentId> collection) | ||
|
@@ -185,8 +186,8 @@ static void AddAll(HashSet<Checksum> checksums, ChecksumCollection checksumColle | |
} | ||
} | ||
|
||
public async ValueTask SynchronizeAssetsAsync<T>( | ||
AssetPath assetPath, HashSet<Checksum> checksums, Dictionary<Checksum, T>? results, CancellationToken cancellationToken) | ||
public async ValueTask SynchronizeAssetsAsync<T, TArg>( | ||
AssetPath assetPath, HashSet<Checksum> checksums, Action<Checksum, T, TArg>? callback, TArg? arg, CancellationToken cancellationToken) | ||
{ | ||
Contract.ThrowIfTrue(checksums.Contains(Checksum.Null)); | ||
if (checksums.Count == 0) | ||
|
@@ -211,7 +212,7 @@ public async ValueTask SynchronizeAssetsAsync<T>( | |
{ | ||
if (_assetCache.TryGetAsset<T>(checksum, out var existing)) | ||
{ | ||
AddResult(checksum, existing); | ||
callback?.Invoke(checksum, existing, arg!); | ||
} | ||
else | ||
{ | ||
|
@@ -239,37 +240,31 @@ public async ValueTask SynchronizeAssetsAsync<T>( | |
{ | ||
var missingChecksumsMemory = new ReadOnlyMemory<Checksum>(missingChecksums, 0, missingChecksumsCount); | ||
|
||
var currentIndex = 0; | ||
await RequestAssetsAsync(assetPath, missingChecksumsMemory, (int index, T missingAsset) => | ||
{ | ||
Contract.ThrowIfTrue(currentIndex != index); | ||
|
||
var missingChecksum = missingChecksums[index]; | ||
|
||
AddResult(missingChecksum, missingAsset); | ||
_assetCache.GetOrAdd(missingChecksum, missingAsset!); | ||
|
||
currentIndex++; | ||
}, cancellationToken).ConfigureAwait(false); | ||
await RequestAssetsAsync( | ||
assetPath, missingChecksumsMemory, | ||
static ( | ||
int index, | ||
T missingAsset, | ||
(AssetProvider assetProvider, Checksum[] missingChecksums, Action<Checksum, T, TArg>? callback, TArg? arg) tuple) => | ||
{ | ||
var missingChecksum = tuple.missingChecksums[index]; | ||
|
||
Contract.ThrowIfTrue(currentIndex != missingChecksumsCount); | ||
tuple.callback?.Invoke(missingChecksum, missingAsset, tuple.arg!); | ||
tuple.assetProvider._assetCache.GetOrAdd(missingChecksum, missingAsset!); | ||
}, | ||
(this, missingChecksums, callback, arg), | ||
cancellationToken).ConfigureAwait(false); | ||
} | ||
|
||
if (usePool) | ||
s_checksumPool.Free(missingChecksums); | ||
} | ||
|
||
return; | ||
|
||
void AddResult(Checksum checksum, T result) | ||
{ | ||
if (results != null) | ||
results[checksum] = result; | ||
} | ||
} | ||
|
||
private async ValueTask RequestAssetsAsync<T>( | ||
AssetPath assetPath, ReadOnlyMemory<Checksum> checksums, Action<int, T> callback, CancellationToken cancellationToken) | ||
private async ValueTask RequestAssetsAsync<T, TArg>( | ||
AssetPath assetPath, ReadOnlyMemory<Checksum> checksums, Action<int, T, TArg> callback, TArg arg, CancellationToken cancellationToken) | ||
{ | ||
#if NETCOREAPP | ||
Contract.ThrowIfTrue(checksums.Span.Contains(Checksum.Null)); | ||
|
@@ -280,6 +275,6 @@ private async ValueTask RequestAssetsAsync<T>( | |
if (checksums.Length == 0) | ||
return; | ||
|
||
await _assetSource.GetAssetsAsync(_solutionChecksum, assetPath, checksums, _serializerService, callback, cancellationToken).ConfigureAwait(false); | ||
await _assetSource.GetAssetsAsync(_solutionChecksum, assetPath, checksums, _serializerService, callback, arg, cancellationToken).ConfigureAwait(false); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed