Use pool and remove some async
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user