From 9a669d8af46c48b0612bd9e44687705d6428ed9c Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 20 Sep 2023 10:08:21 -0400 Subject: [PATCH] Use Utf8JsonWriterCache in JsonNode.To{Json}String --- .../src/System/Text/Json/Nodes/JsonNode.To.cs | 50 ++++++++++++------- .../System/Text/Json/Nodes/JsonValueOfT.cs | 29 +++++++++-- .../Text/Json/Writer/Utf8JsonWriterCache.cs | 13 +++-- 3 files changed, 65 insertions(+), 27 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.To.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.To.cs index 838b05423912f..0304718c81aa2 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.To.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.To.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Threading; + namespace System.Text.Json.Nodes { public abstract partial class JsonNode @@ -12,8 +14,25 @@ public abstract partial class JsonNode /// JSON representation of current instance. public string ToJsonString(JsonSerializerOptions? options = null) { - using PooledByteBufferWriter output = WriteToPooledBuffer(options, options?.GetWriterOptions() ?? default); - return JsonHelpers.Utf8GetString(output.WrittenMemory.Span); + JsonWriterOptions writerOptions = default; + int defaultBufferSize = JsonSerializerOptions.BufferSizeDefault; + if (options is not null) + { + writerOptions = options.GetWriterOptions(); + defaultBufferSize = options.DefaultBufferSize; + } + + Utf8JsonWriter writer = Utf8JsonWriterCache.RentWriterAndBuffer(writerOptions, defaultBufferSize, out PooledByteBufferWriter output); + try + { + WriteTo(writer, options); + writer.Flush(); + return JsonHelpers.Utf8GetString(output.WrittenMemory.Span); + } + finally + { + Utf8JsonWriterCache.ReturnWriterAndBuffer(writer, output); + } } /// @@ -37,8 +56,17 @@ public override string ToString() } } - using PooledByteBufferWriter output = WriteToPooledBuffer(writerOptions: new JsonWriterOptions { Indented = true }); - return JsonHelpers.Utf8GetString(output.WrittenMemory.Span); + Utf8JsonWriter writer = Utf8JsonWriterCache.RentWriterAndBuffer(new JsonWriterOptions { Indented = true }, JsonSerializerOptions.BufferSizeDefault, out PooledByteBufferWriter output); + try + { + WriteTo(writer); + writer.Flush(); + return JsonHelpers.Utf8GetString(output.WrittenMemory.Span); + } + finally + { + Utf8JsonWriterCache.ReturnWriterAndBuffer(writer, output); + } } /// @@ -50,19 +78,5 @@ public override string ToString() /// /// Options to control the serialization behavior. public abstract void WriteTo(Utf8JsonWriter writer, JsonSerializerOptions? options = null); - - /// - /// Creates a pooled buffer writer instance and serializes all contents to it. - /// - internal PooledByteBufferWriter WriteToPooledBuffer( - JsonSerializerOptions? options = null, - JsonWriterOptions writerOptions = default, - int bufferSize = JsonSerializerOptions.BufferSizeDefault) - { - var bufferWriter = new PooledByteBufferWriter(bufferSize); - using var writer = new Utf8JsonWriter(bufferWriter, writerOptions); - WriteTo(writer, options); - return bufferWriter; - } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfT.cs index 0be2c9517a376..86db69d82cd74 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfT.cs @@ -72,8 +72,17 @@ internal sealed override JsonValueKind GetValueKindCore() return element.ValueKind; } - using PooledByteBufferWriter output = WriteToPooledBuffer(); - return JsonElement.ParseValue(output.WrittenMemory.Span, options: default).ValueKind; + Utf8JsonWriter writer = Utf8JsonWriterCache.RentWriterAndBuffer(default, JsonSerializerOptions.BufferSizeDefault, out PooledByteBufferWriter output); + try + { + WriteTo(writer); + writer.Flush(); + return JsonElement.ParseValue(output.WrittenMemory.Span, options: default).ValueKind; + } + finally + { + Utf8JsonWriterCache.ReturnWriterAndBuffer(writer, output); + } } internal sealed override bool DeepEqualsCore(JsonNode? otherNode) @@ -107,9 +116,21 @@ internal sealed override bool DeepEqualsCore(JsonNode? otherNode) } } - using PooledByteBufferWriter thisOutput = WriteToPooledBuffer(); - using PooledByteBufferWriter otherOutput = otherNode.WriteToPooledBuffer(); + using PooledByteBufferWriter thisOutput = WriteToPooledBuffer(this); + using PooledByteBufferWriter otherOutput = WriteToPooledBuffer(otherNode); return thisOutput.WrittenMemory.Span.SequenceEqual(otherOutput.WrittenMemory.Span); + + static PooledByteBufferWriter WriteToPooledBuffer( + JsonNode node, + JsonSerializerOptions? options = null, + JsonWriterOptions writerOptions = default, + int bufferSize = JsonSerializerOptions.BufferSizeDefault) + { + var bufferWriter = new PooledByteBufferWriter(bufferSize); + using var writer = new Utf8JsonWriter(bufferWriter, writerOptions); + node.WriteTo(writer, options); + return bufferWriter; + } } internal TypeToConvert ConvertJsonElement() diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriterCache.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriterCache.cs index bff98e9b81649..b0d9528031286 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriterCache.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriterCache.cs @@ -13,7 +13,10 @@ internal static class Utf8JsonWriterCache [ThreadStatic] private static ThreadLocalState? t_threadLocalState; - public static Utf8JsonWriter RentWriterAndBuffer(JsonSerializerOptions options, out PooledByteBufferWriter bufferWriter) + public static Utf8JsonWriter RentWriterAndBuffer(JsonSerializerOptions options, out PooledByteBufferWriter bufferWriter) => + RentWriterAndBuffer(options.GetWriterOptions(), options.DefaultBufferSize, out bufferWriter); + + public static Utf8JsonWriter RentWriterAndBuffer(JsonWriterOptions options, int defaultBufferSize, out PooledByteBufferWriter bufferWriter) { ThreadLocalState state = t_threadLocalState ??= new(); Utf8JsonWriter writer; @@ -24,14 +27,14 @@ public static Utf8JsonWriter RentWriterAndBuffer(JsonSerializerOptions options, bufferWriter = state.BufferWriter; writer = state.Writer; - bufferWriter.InitializeEmptyInstance(options.DefaultBufferSize); - writer.Reset(bufferWriter, options.GetWriterOptions()); + bufferWriter.InitializeEmptyInstance(defaultBufferSize); + writer.Reset(bufferWriter, options); } else { // We're in a recursive JsonSerializer call -- return fresh instances. - bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize); - writer = new Utf8JsonWriter(bufferWriter, options.GetWriterOptions()); + bufferWriter = new PooledByteBufferWriter(defaultBufferSize); + writer = new Utf8JsonWriter(bufferWriter, options); } return writer;