Skip to content
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

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from

Conversation

Nigusu-Allehu
Copy link
Contributor

@Nigusu-Allehu Nigusu-Allehu commented Oct 3, 2024

Bug

Fixes: NuGet/Home#13059

Description

This PR makes sure we use System.Text.Json to read the cache file in CacheFileFormat.

PR Checklist

  • Meaningful title, helpful description and a linked NuGet/Home issue
  • Added tests
  • Link to an issue or pull request to update docs if this PR changes settings, environment variables, new feature, etc.

@Nigusu-Allehu Nigusu-Allehu requested a review from a team as a code owner October 3, 2024 23:04
@Nigusu-Allehu Nigusu-Allehu marked this pull request as draft October 3, 2024 23:04
@Nigusu-Allehu Nigusu-Allehu self-assigned this Oct 3, 2024
@Nigusu-Allehu Nigusu-Allehu marked this pull request as ready for review October 5, 2024 01:44
/// <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>
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Member

@zivkan zivkan Oct 10, 2024

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>().

Copy link
Member

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.

Copy link
Member

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.

Copy link
Member

@nkolev92 nkolev92 left a 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 :shipit:

@Nigusu-Allehu Nigusu-Allehu force-pushed the dev-nyenework-migrate-to-system-text-json branch from 012c80f to 2834cc5 Compare October 15, 2024 21:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use System.Text.Json to read the cache file in CacheFileFormat
3 participants