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

Consistently use CharArrayPool in JsonWriter to cut cost of initializing char arrays #2093

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/Microsoft.OData.Core/Json/JsonWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ public void WriteName(string name)

currentScope.ObjectCount++;

JsonValueUtils.WriteEscapedJsonString(this.writer, name, this.stringEscapeOption, this.wrappedBuffer);
JsonValueUtils.WriteEscapedJsonString(this.writer, name, this.stringEscapeOption, this.wrappedBuffer, this.ArrayPool);
this.writer.Write(JsonConstants.NameValueSeparator);
}

Expand Down Expand Up @@ -280,7 +280,7 @@ public void WriteValue(long value)
if (isIeee754Compatible)
{
JsonValueUtils.WriteValue(this.writer, value.ToString(CultureInfo.InvariantCulture),
this.stringEscapeOption, this.wrappedBuffer);
this.stringEscapeOption, this.wrappedBuffer, this.ArrayPool);
}
else
{
Expand Down Expand Up @@ -320,7 +320,7 @@ public void WriteValue(decimal value)
if (isIeee754Compatible)
{
JsonValueUtils.WriteValue(this.writer, value.ToString(CultureInfo.InvariantCulture),
this.stringEscapeOption, this.wrappedBuffer);
this.stringEscapeOption, this.wrappedBuffer, this.ArrayPool);
}
else
{
Expand Down Expand Up @@ -395,7 +395,7 @@ public void WriteValue(sbyte value)
public void WriteValue(string value)
{
this.WriteValueSeparator();
JsonValueUtils.WriteValue(this.writer, value, this.stringEscapeOption, this.wrappedBuffer);
JsonValueUtils.WriteValue(this.writer, value, this.stringEscapeOption, this.wrappedBuffer, this.ArrayPool);
}

/// <summary>
Expand Down
12 changes: 6 additions & 6 deletions src/Microsoft.OData.Core/Json/JsonWriterAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public async Task WriteNameAsync(string name)

currentScope.ObjectCount++;

await this.writer.WriteEscapedJsonStringAsync(name, this.stringEscapeOption, this.wrappedBuffer)
await this.writer.WriteEscapedJsonStringAsync(name, this.stringEscapeOption, this.wrappedBuffer, this.ArrayPool)
.ConfigureAwait(false);
await this.writer.WriteAsync(JsonConstants.NameValueSeparator).ConfigureAwait(false);
}
Expand Down Expand Up @@ -148,7 +148,7 @@ public async Task WriteValueAsync(long value)
if (isIeee754Compatible)
{
await this.writer.WriteValueAsync(value.ToString(CultureInfo.InvariantCulture),
this.stringEscapeOption, this.wrappedBuffer).ConfigureAwait(false);
this.stringEscapeOption, this.wrappedBuffer, this.ArrayPool).ConfigureAwait(false);
}
else
{
Expand Down Expand Up @@ -179,7 +179,7 @@ public async Task WriteValueAsync(decimal value)
if (isIeee754Compatible)
{
await this.writer.WriteValueAsync(value.ToString(CultureInfo.InvariantCulture),
this.stringEscapeOption, this.wrappedBuffer).ConfigureAwait(false);
this.stringEscapeOption, this.wrappedBuffer, this.ArrayPool).ConfigureAwait(false);
}
else
{
Expand Down Expand Up @@ -234,15 +234,15 @@ public async Task WriteValueAsync(sbyte value)
public async Task WriteValueAsync(string value)
{
await this.WriteValueSeparatorAsync().ConfigureAwait(false);
await this.writer.WriteValueAsync(value, this.stringEscapeOption, this.wrappedBuffer)
await this.writer.WriteValueAsync(value, this.stringEscapeOption, this.wrappedBuffer, this.ArrayPool)
.ConfigureAwait(false);
}

/// <inheritdoc/>
public async Task WriteValueAsync(byte[] value)
{
await this.WriteValueSeparatorAsync().ConfigureAwait(false);
await this.writer.WriteValueAsync(value, this.wrappedBuffer, ArrayPool).ConfigureAwait(false);
await this.writer.WriteValueAsync(value, this.wrappedBuffer, this.ArrayPool).ConfigureAwait(false);
}

/// <inheritdoc/>
Expand Down Expand Up @@ -270,7 +270,7 @@ public async Task<Stream> StartStreamValueScopeAsync()
// ODL supports net45 and netstandard1.1 (in addition to .netstandard2.0)
// This makes it complicated to implement IAsyncDisposable in ODataBinaryStreamWriter
// TODO: Can the returned stream be safely used asynchronously?
this.binaryValueStream = new ODataBinaryStreamWriter(writer, this.wrappedBuffer, ArrayPool);
this.binaryValueStream = new ODataBinaryStreamWriter(writer, this.wrappedBuffer, this.ArrayPool);
return this.binaryValueStream;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
//---------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Microsoft.OData.Json;
using System.Threading.Tasks;
using Microsoft.OData.Edm;
using Microsoft.OData.Json;
using Xunit;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace Microsoft.OData.Tests.Json
{
Expand Down Expand Up @@ -359,5 +359,35 @@ private async Task VerifyWriterPrimitiveValueWithIeee754CompatibleAsync<T>(T par
}

#endregion

[Fact]
public Task WriteNameAsyncUsesProvidedCharArrayPool()
{
// Note: CharArrayPool is used if string has special chars
// This test is mostly theoretical since special characters are not allowed in names
return SetupJsonWriterRunTestAndVerifyRentAsync(
(jsonWriter) => jsonWriter.WriteNameAsync("foo\tbar"));
}

[Fact]
public Task WriteStringValueUsesProvidedCharArrayPool()
{
return SetupJsonWriterRunTestAndVerifyRentAsync(
(jsonWriter) => jsonWriter.WriteValueAsync("foo\tbar"));
}

private async Task SetupJsonWriterRunTestAndVerifyRentAsync(Func<JsonWriter, Task> func)
{
var jsonWriter = new JsonWriter(new StringWriter(builder), isIeee754Compatible: true);
bool rentVerified = false;

Action<int> rentVerifier = (minSize) => { rentVerified = true; };
jsonWriter.ArrayPool = new MockCharArrayPool { RentVerifier = rentVerifier };

await jsonWriter.StartObjectScopeAsync();
await func(jsonWriter);

Assert.True(rentVerified);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
using System;
using System.IO;
using System.Text;
using Microsoft.OData.Json;
using Microsoft.OData.Edm;
using Microsoft.OData.Json;
using Xunit;

namespace Microsoft.OData.Tests.Json
Expand Down Expand Up @@ -174,5 +174,35 @@ private void VerifyWriterPrimitiveValueWithIeee754Compatible<T>(T parameter, str
}

#endregion

[Fact]
public void WriteNameUsesProvidedCharArrayPool()
{
// Note: CharArrayPool is used if string has special chars
// This test is mostly theoretical since special characters are not allowed in names
SetupJsonWriterRunTestAndVerifyRent(
(jsonWriter) => jsonWriter.WriteName("foo\tbar"));
}

[Fact]
public void WriteStringValueUsesProvidedCharArrayPool()
{
SetupJsonWriterRunTestAndVerifyRent(
(jsonWriter) => jsonWriter.WriteValue("foo\tbar"));
}

private void SetupJsonWriterRunTestAndVerifyRent(Action<JsonWriter> action)
{
var jsonWriter = new JsonWriter(new StringWriter(builder), isIeee754Compatible: true);
bool rentVerified = false;

Action<int> rentVerifier = (minSize) => { rentVerified = true; };
jsonWriter.ArrayPool = new MockCharArrayPool { RentVerifier = rentVerifier };

jsonWriter.StartObjectScope();
action(jsonWriter);

Assert.True(rentVerified);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//---------------------------------------------------------------------
// <copyright file="MockCharArrayPool.cs" company="Microsoft">
// Copyright (C) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
// </copyright>
//---------------------------------------------------------------------

using System;
using Microsoft.OData.Buffers;

namespace Microsoft.OData.Tests.Json
{
public class MockCharArrayPool : ICharArrayPool
{
public Action<int> RentVerifier;
public Action<char[]> ReturnVerifier;

public char[] Rent(int minSize)
{
var charArray = new char[minSize];
RentVerifier(minSize);

return charArray;
}

public void Return(char[] array)
{
ReturnVerifier(array);
// Do nothing else
}
}
}