Skip to content

Optimize JsonReaderData for MemoryStream and make buffer publicly visible for StructuralJsonTypeMappings#38051

Open
JoasE wants to merge 4 commits intodotnet:mainfrom
JoasE:feature/JsonReaderData-Optimization
Open

Optimize JsonReaderData for MemoryStream and make buffer publicly visible for StructuralJsonTypeMappings#38051
JoasE wants to merge 4 commits intodotnet:mainfrom
JoasE:feature/JsonReaderData-Optimization

Conversation

@JoasE
Copy link
Copy Markdown
Contributor

@JoasE JoasE commented Apr 5, 2026

Internally managed providers pass MemoryStream to JsonReaderData. This PR makes their internal buffer accessible and optimizes JsonReaderData to leverage the internal buffer if possible. This prevents duplicate buffering for json MemoryStreams

@JoasE
Copy link
Copy Markdown
Contributor Author

JoasE commented Apr 5, 2026

I don’t do these types of optimizations often, but I ran into this when working on json serialization for cosmos.
I think the TryGetBuffer is a must have, but also have some less substantiated ideas like calling ToArray on smaller streams and increasing initial buffer size for bigger streams. I removed them because I decided I was just guessing at that point, but if you want to take a look at them, you can see them in the Remove guesswork commit.

@JoasE JoasE marked this pull request as ready for review April 6, 2026 06:57
@JoasE JoasE requested a review from a team as a code owner April 6, 2026 06:57
Copilot AI review requested due to automatic review settings April 6, 2026 06:57
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes JSON reading for provider-produced MemoryStream instances by allowing JsonReaderData to directly use a MemoryStream’s internal buffer (when available), avoiding duplicate buffering and reducing allocations during structural JSON materialization.

Changes:

  • Updated JsonReaderData to store its input as ReadOnlyMemory<byte> and added a MemoryStream fast-path using TryGetBuffer().
  • Updated SQL Server structural JSON mapping to create MemoryStream instances with a publicly visible buffer (so TryGetBuffer() succeeds).
  • Updated SQLite structural JSON mapping to use a shared CreateUtf8Stream helper (also creating MemoryStream with a publicly visible buffer) and simplified the expression tree.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/EFCore/Storage/Json/JsonReaderData.cs Adds MemoryStream buffer fast-path and shifts internal buffering to ReadOnlyMemory<byte> + optional mutable buffer.
src/EFCore.SqlServer/Storage/Internal/SqlServerStructuralJsonTypeMapping.cs Creates UTF-8 MemoryStream with publiclyVisible: true to enable buffer reuse in JsonReaderData.
src/EFCore.Sqlite.Core/Storage/Internal/SqliteJsonTypeMapping.cs Introduces CreateUtf8Stream helper and uses it from CustomizeDataReaderExpression, enabling buffer reuse.

@roji
Copy link
Copy Markdown
Member

roji commented Apr 6, 2026

BTW @JoasE our whole JSON reading architecture here is quite inefficient: we read the JSON string, and then expose that as UTF8 data as bytes to be decoded (again!) by Utf8JsonReader etc. The real perf win here would be to have have Utf8JsonReader read directly from the network with any additional buffering/decoding, see #31216.

@roji roji self-assigned this Apr 6, 2026
@JoasE
Copy link
Copy Markdown
Contributor Author

JoasE commented Apr 6, 2026

@roji Thanks for the quick review!

BTW @JoasE our whole JSON reading architecture here is quite inefficient: we read the JSON string, and then expose that as UTF8 data as bytes to be decoded (again!) by Utf8JsonReader etc. The real perf win here would be to have have Utf8JsonReader read directly from the network with any additional buffering/decoding, see #31216.

Good point, I guess my current changes tackle some low-hanging fruit in the meantime, which should also benefit the new Cosmos deserialization work.

@roji roji enabled auto-merge (squash) April 6, 2026 09:33
@roji roji added this to the 11.0.0 milestone Apr 6, 2026
@roji roji added the preview-4 label Apr 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants