Use pool and remove some async

This commit is contained in:
Adam Hathcock
2024-09-25 15:52:44 +01:00
parent d73bf365c2
commit ddeac27f04
6 changed files with 64 additions and 50 deletions
@@ -140,9 +140,7 @@ public partial class Operations
}
// Shoot out the total children count, wasteful
var count = (
await ClosureParser.GetClosuresAsync(objString, localTransport.CancellationToken).ConfigureAwait(false)
).Count;
var count = ClosureParser.GetClosures(objString).Count;
onTotalChildrenCountKnown?.Invoke(count);
@@ -78,14 +78,13 @@ public sealed class SpeckleObjectDeserializer
// JObject doc1 = JObject.Parse(objectJson);
// This is equivalent code that doesn't parse datetimes:
using JsonReader reader = new JsonTextReader(new StringReader(objectJson));
using JsonTextReader reader = SpeckleObjectSerializerPool.Instance.GetJsonTextReader(new StringReader(objectJson));
reader.DateParseHandling = DateParseHandling.None;
object? converted;
try
{
await reader.ReadAsync(CancellationToken).ConfigureAwait(false);
reader.Read();
converted = await ReadObjectAsync(reader, CancellationToken).ConfigureAwait(false);
}
catch (Exception ex) when (!ex.IsFatal() && ex is not OperationCanceledException)
@@ -107,7 +106,7 @@ public sealed class SpeckleObjectDeserializer
//this should be buffered
private async Task<List<object?>> ReadArrayAsync(JsonReader reader, CancellationToken ct)
{
await reader.ReadAsync(ct).ConfigureAwait(false);
reader.Read();
List<object?> retList = new();
while (reader.TokenType != JsonToken.EndArray)
{
@@ -120,14 +119,14 @@ public sealed class SpeckleObjectDeserializer
{
retList.Add(convertedValue);
}
await reader.ReadAsync(ct).ConfigureAwait(false); //goes to next
reader.Read(); //goes to next
}
return retList;
}
private async Task<object?> ReadObjectAsync(JsonReader reader, CancellationToken ct)
{
await reader.ReadAsync(ct).ConfigureAwait(false);
reader.Read();
Dictionary<string, object?> dict = new();
while (reader.TokenType != JsonToken.EndObject)
{
@@ -138,8 +137,8 @@ public sealed class SpeckleObjectDeserializer
string propName = (reader.Value?.ToString()).NotNull();
if (propName == "__closure")
{
await reader.ReadAsync(ct).ConfigureAwait(false); //goes to prop value
var closures = await ClosureParser.GetClosuresAsync(reader).ConfigureAwait(false);
reader.Read(); //goes to prop value
var closures = ClosureParser.GetClosures(reader);
foreach (var closure in closures)
{
_ids.Add(closure.Item1);
@@ -152,13 +151,13 @@ public sealed class SpeckleObjectDeserializer
// https://linear.app/speckle/issue/CXPLA-54/when-deserializing-dont-allow-closures-that-arent-downloadable
await TryGetDeserializedAsync(objId).ConfigureAwait(false);
}
await reader.ReadAsync(ct).ConfigureAwait(false); //goes to next
reader.Read(); //goes to next
continue;
}
await reader.ReadAsync(ct).ConfigureAwait(false); //goes prop value
reader.Read(); //goes prop value
object? convertedValue = await ReadPropertyAsync(reader, ct).ConfigureAwait(false);
dict[propName] = convertedValue;
await reader.ReadAsync(ct).ConfigureAwait(false); //goes to next
reader.Read(); //goes to next
}
break;
default:
@@ -0,0 +1,25 @@
using System.Buffers;
using Speckle.Newtonsoft.Json;
using Speckle.Sdk.Common;
namespace Speckle.Sdk.Serialisation;
public class SpeckleObjectSerializerPool
{
public static readonly SpeckleObjectSerializerPool Instance = new();
private SpeckleObjectSerializerPool() { }
public JsonTextWriter GetJsonTextWriter(TextWriter writer) => new(writer) { ArrayPool = _charPool };
public JsonTextReader GetJsonTextReader(TextReader reader) => new(reader) { ArrayPool = _charPool };
private readonly SerializerPool<char> _charPool = new(ArrayPool<char>.Create(4096, 4096));
private class SerializerPool<T>(ArrayPool<T> pool) : IArrayPool<T>
{
public T[] Rent(int minimumLength) => pool.Rent(minimumLength);
public void Return(T[]? array) => pool.Return(array.NotNull());
}
}
@@ -5,27 +5,26 @@ namespace Speckle.Sdk.Serialisation.Utilities;
public static class ClosureParser
{
public static async Task<IReadOnlyList<(string, int)>> GetClosuresAsync(
string rootObjectJson,
CancellationToken cancellationToken = default
)
public static IReadOnlyList<(string, int)> GetClosures(string rootObjectJson)
{
try
{
using JsonTextReader reader = new(new StringReader(rootObjectJson));
await reader.ReadAsync(cancellationToken).ConfigureAwait(false);
using JsonTextReader reader = SpeckleObjectSerializerPool.Instance.GetJsonTextReader(
new StringReader(rootObjectJson)
);
reader.Read();
while (reader.TokenType != JsonToken.EndObject)
{
switch (reader.TokenType)
{
case JsonToken.StartObject:
{
var closureList = await ReadObjectAsync(reader, cancellationToken).ConfigureAwait(false);
var closureList = ReadObject(reader);
return closureList;
}
default:
await reader.ReadAsync(cancellationToken).ConfigureAwait(false);
await reader.SkipAsync(cancellationToken).ConfigureAwait(false);
reader.Read();
reader.Skip();
break;
}
}
@@ -34,17 +33,12 @@ public static class ClosureParser
return [];
}
public static async Task<IEnumerable<string>> GetChildrenIdsAsync(
string rootObjectJson,
CancellationToken cancellationToken = default
) => (await GetClosuresAsync(rootObjectJson, cancellationToken).ConfigureAwait(false)).Select(x => x.Item1);
public static IEnumerable<string> GetChildrenIds(string rootObjectJson) =>
GetClosures(rootObjectJson).Select(x => x.Item1);
private static async Task<IReadOnlyList<(string, int)>> ReadObjectAsync(
JsonTextReader reader,
CancellationToken cancellationToken
)
private static IReadOnlyList<(string, int)> ReadObject(JsonTextReader reader)
{
await reader.ReadAsync(cancellationToken).ConfigureAwait(false);
reader.Read();
while (reader.TokenType != JsonToken.EndObject)
{
switch (reader.TokenType)
@@ -53,46 +47,46 @@ public static class ClosureParser
{
if (reader.Value as string == "__closure")
{
await reader.ReadAsync(cancellationToken).ConfigureAwait(false); //goes to prop vale
var closureList = await ReadClosureEnumerableAsync(reader).ConfigureAwait(false);
reader.Read(); //goes to prop vale
var closureList = ReadClosureEnumerable(reader);
return closureList;
}
await reader.ReadAsync(cancellationToken).ConfigureAwait(false); //goes to prop vale
await reader.SkipAsync(cancellationToken).ConfigureAwait(false);
await reader.ReadAsync(cancellationToken).ConfigureAwait(false); //goes to next
reader.Read(); //goes to prop vale
reader.Skip();
reader.Read(); //goes to next
}
break;
default:
await reader.ReadAsync(cancellationToken).ConfigureAwait(false);
await reader.SkipAsync(cancellationToken).ConfigureAwait(false);
await reader.ReadAsync(cancellationToken).ConfigureAwait(false);
reader.Read();
reader.Skip();
reader.Read();
break;
}
}
return [];
}
public static async Task<IReadOnlyList<(string, int)>> GetClosuresAsync(JsonReader reader)
public static IReadOnlyList<(string, int)> GetClosures(JsonReader reader)
{
if (reader.TokenType != JsonToken.StartObject)
{
return Array.Empty<(string, int)>();
}
var closureList = await ReadClosureEnumerableAsync(reader).ConfigureAwait(false);
var closureList = ReadClosureEnumerable(reader);
closureList.Sort((a, b) => b.Item2.CompareTo(a.Item2));
return closureList;
}
private static async Task<List<(string, int)>> ReadClosureEnumerableAsync(JsonReader reader)
private static List<(string, int)> ReadClosureEnumerable(JsonReader reader)
{
List<(string, int)> closureList = new();
await reader.ReadAsync().ConfigureAwait(false); //startobject
reader.Read(); //startobject
while (reader.TokenType != JsonToken.EndObject)
{
var childId = (reader.Value as string).NotNull(); // propertyName
int childMinDepth = (await reader.ReadAsInt32Async().ConfigureAwait(false)).NotNull(); //propertyValue
await reader.ReadAsync().ConfigureAwait(false);
int childMinDepth = (reader.ReadAsInt32()).NotNull(); //propertyValue
reader.Read();
closureList.Add((childId, childMinDepth));
}
return closureList;
@@ -140,9 +140,7 @@ public sealed class ServerTransport : IServerTransport
api.CancellationToken = CancellationToken;
string? rootObjectJson = await api.DownloadSingleObject(StreamId, id, OnProgressAction).ConfigureAwait(false);
var allIds = (
await ClosureParser.GetChildrenIdsAsync(rootObjectJson.NotNull(), CancellationToken).ConfigureAwait(false)
).ToList();
var allIds = ClosureParser.GetChildrenIds(rootObjectJson.NotNull()).ToList();
var childrenIds = allIds.Where(x => !x.Contains("blob:"));
var blobIds = allIds.Where(x => x.Contains("blob:")).Select(x => x.Remove(0, 5));
@@ -30,7 +30,7 @@ public static class TransportHelpers
targetTransport.SaveObject(id, parent);
var closures = (await ClosureParser.GetChildrenIdsAsync(parent, cancellationToken).ConfigureAwait(false)).ToList();
var closures = ClosureParser.GetChildrenIds(parent).ToList();
onTotalChildrenCountKnown?.Invoke(closures.Count);