Skip to content

Commit

Permalink
Consistently use CharArrayPool in JsonWriter to cut cost of initializ…
Browse files Browse the repository at this point in the history
…ing char arrays (#2093)

Co-authored-by: John Gathogo <[email protected]>
  • Loading branch information
gathogojr and John Gathogo authored May 21, 2021
1 parent aa8d20f commit b1394a5
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 14 deletions.
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
}
}
}

0 comments on commit b1394a5

Please sign in to comment.