-
Notifications
You must be signed in to change notification settings - Fork 697
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
System.Text.Json Migration - Adding code to parse the Project.Assets.Json file using STJ. #5558
System.Text.Json Migration - Adding code to parse the Project.Assets.Json file using STJ. #5558
Conversation
This PR has been automatically marked as stale because it has no activity for 7 days. It will be closed if no further activity occurs within another 7 days of this comment. If it is closed, you may reopen it anytime when you're ready again, as long as you don't delete the branch. |
src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamAssetsLogMessageConverter.cs
Outdated
Show resolved
Hide resolved
src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileConverter.cs
Show resolved
Hide resolved
src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileTargetLibraryConverter.cs
Outdated
Show resolved
Hide resolved
src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileTargetLibraryConverter.cs
Outdated
Show resolved
Hide resolved
src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileTargetLibraryConverter.cs
Outdated
Show resolved
Hide resolved
@@ -141,5 +170,36 @@ internal static JToken WriteString(string item) | |||
{ | |||
return item != null ? new JValue(item) : JValue.CreateNull(); | |||
} | |||
|
|||
internal static NuGetVersion ParseNugetVersion(string value) |
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.
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.
I think defining a great lifetime for these caches would be challenging.
I'm comfortable if this change starts with the assets file read scope, but we should look into expanding it.
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.
The title of this PR is to migrate to System.Text.Json, and the existing Newtonsoft.Json code doesn't do caching, so can you bump caching work to a different PR?
I'm behind on my other priorities, but ideally I should start work on NuGet/Home#12124 in the next sprint or two. For that work, I need this PR merged into the feature branch, and the feature branch merged into the dev branch.
If merging the assets file System.Text.Json work is delayed, then that will delay my ability to start on this other work. Therefore, I'd like to minimize scope creep that blocks other work.
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.
I love that, so I went ahead and undid the caching stuff and saved a stash of it.
src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileItemConverter.cs
Outdated
Show resolved
Hide resolved
{ | ||
/// <summary> | ||
/// A <see cref="Utf8JsonStreamReaderConverter{T}"/> to allow read JSON into <see cref="LockFileTargetLibrary"/> | ||
/// </summary> |
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.
It would be super helpful if these convertors showed an example of what exactly they were parsing to be able to match that to the code.
var propertyName = reader.GetString(); | ||
var (targetLibraryName, version) = propertyName.SplitInTwo('/'); | ||
lockFileTargetLibrary.Name = targetLibraryName; | ||
lockFileTargetLibrary.Version = version is null ? null : JsonUtility.ParseNugetVersion(version); |
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.
Separate to this PR, but JsonUtility.ParseNuGetVersion should be a candidate for moving to parsing from a UTF8 string, or at least a ReadOnlySpan to avoid the wasted allocation to split the version into a string, only to throw it away. This is about ~3% of allocations in the trace you shared.
{ | ||
string propertyName = reader.GetString(); | ||
string versionString = reader.ReadNextTokenAsString(); | ||
|
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.
35% of allocations come from these values, I feel like sharing the strings for common dependencies would be helpful in reducing allocations, especially given the version number is immediately thrown away.
src/NuGet.Core/NuGet.ProjectModel/Utf8JsonStreamProjectFileDependencyGroupConverter.cs
Outdated
Show resolved
Hide resolved
src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileTargetLibraryConverter.cs
Outdated
Show resolved
Hide resolved
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.
I have a few correctness concerns about methods in the shared/generic Utf8JsonStreamReader
class. Even if specific converters are using them in a safe way, since it's in a utility class that could be called by any (internal) method, I think that raises the quality bar so that it should adhere to the principal of least surprise.
test/NuGet.Core.Tests/NuGet.ProjectModel.Test/JsonPackageSpecReaderTests.cs
Outdated
Show resolved
Hide resolved
test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileParsingEnvironmentVariable.cs
Outdated
Show resolved
Hide resolved
We don't expect 3rd party tools to write the asset file, and we have a lot of integration tests. So, I think if the tests pass using STJ, then it should be quite safe, but the env var to fall back to NJ is a sufficient safety barrier. So, I think that STJ by default is fine. |
Great job getting this done! You probably need to do a rebase before merging into dev. |
ed7f00c
into
dev-jgonz120-FeatureBranch-Stj-Migration
…Json file using STJ. (#5558) Update the LockFileFormat class to use STJ for parsing the assets file.
…Json file using STJ. (#5558) Update the LockFileFormat class to use STJ for parsing the assets file.
Crated a new struct to parse the assets file using System.Text.Json instead of Newtonsoft. It will read the file without loading it completely in memory, reducing memory allocations. PRs associated with this: * Create class for reading Json files in chunks (#5530) * System.Text.Json Migration - Adding code to parse the PackageSpec using STJ (#5541) * System.Text.Json Migration - Adding code to parse the Project.Assets.Json file using STJ. (#5558) * Create class for reading Json files in chunks (#5530)
Bug
Fixes: NuGet/Home#12715
Regression? Last working version:
Description
This PR update the LockFileFormat class to use STJ for parsing the assets file. There are some comments that were pointed out from #5530 which I think should be done as a separate PR if we decide to move forward with them, so there is potentially one more PR to come.
Benchmark Results
PR Checklist
PR has a meaningful title
PR has a linked issue.
Described changes
Tests
Documentation