-
Notifications
You must be signed in to change notification settings - Fork 689
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
Migrate CacheFileFormat to System.Text.Json #6081
base: dev
Are you sure you want to change the base?
Conversation
/// <summary> | ||
/// since Log messages property in CacheFile is an interface type, we have the following custom converter to deserialize the IAssetsLogMessage objects. | ||
/// </summary> | ||
private class AssetsLogMessageConverter : JsonConverter<IAssetsLogMessage> |
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.
Part of the idea of calling the LockFileFormat implementation was to avoid maintaining 2 different implementations of the assets file log message reading.
Is there anything in that implementation we can reuse given that there's an STJ implementation?
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.
You are right. LockFileFormat has implementations for reading and writing IAssetsLogMessage. However, as you mentioned, it is currently implemented using NSJ. I don't think we could reuse it currently for a STJ implementation. I think, in the future, when we migrate LockFileFormat, this converter could be used by every method trying to read and write asset file log messages.
Maybe if we modify ReadLogMessage in LockFileFormat to take in a delegate that allows it to read its input, we could be able to use it to read log messages from both NSJ JObject
and STJ JsonElement
. The new ReadLogMessage, could have a definition that looks like
- delegate
public delegate T JsonPropertyReader<T>(object json, string property)
private static IAssetsLogMessage ReadLogMessage( object json, string projectPath, JsonPropertyReader<string> readStringProperty, JsonPropertyReader<int> readIntProperty)
My fear is we might introduce some allocation overhead from the delegates.
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 lock file reading is implementing with STJ too: ef5bce3.
It's what's used by default.
There seems to be a converter implemented there:
internal static readonly Utf8JsonStreamIAssetsLogMessageConverter IAssetsLogMessageConverter = new Utf8JsonStreamIAssetsLogMessageConverter(); |
I was thinking we can use that: https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamIAssetsLogMessageConverter.cs.
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.
unfortunately, not really. STJ's Utf8JsonReader
doesn't have a Read()
or MoveNext()
method that can read from a stream. Instead, it returns false when the end of the buffer is reached and the caller is then responsible for reading from the stream and filling the buffer, before trying again.
While STJ can internally do a reading stream with by-reflection (or source generator) serializer, if you implement their JsonConverter
, it will buffer the entire object in memory. Since we'd need a converter for the root object, this means that STJ would need JsonSerializer.Deserialize<AssetsFile>(stream)
to buffer the entire assets file in memory, and since that can be multiple megabytes, we don't do that.
STJ's docs recommend you implement your own streaming JsonReader, which is what we did for the assets file, and hence IUtf8JsonStreamReaderConverter<T>
is a custom NuGet thing: https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.ProjectModel/Utf8JsonStreamReaderConverter.cs#L9
This means it can't (easily?) be reused with STJ's JsonConverter<T>
or JsonSerializer.Deserialize<T>()
.
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 largest part of the implementation for CacheFileFormat is the log messages.
I know it's not the recommended way, but I'm wondering if we're better off just following that pattern with CacheFileFormat.
I'm just trying to further minimize code duplication with serialization. We'll need 2 to implement STJ, I'd hate to have 3.
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.
If we're not incorporating my feedback to use the existing converter, let's at least add detailed tests about the converter.
Replaying the restore messages correctly is really important tot he experience given how often a restore no-ops.
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's a few comments, but these are really conversations, stylistic ideas.
Once we're closed on this, I think this is ready to
012c80f
to
2834cc5
Compare
Bug
Fixes: NuGet/Home#13059
Description
This PR makes sure we use System.Text.Json to read the cache file in CacheFileFormat.
PR Checklist