diff --git a/Directory.Packages.props b/Directory.Packages.props index 09f082e2..6d1dd95c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -8,6 +8,7 @@ + @@ -26,7 +27,6 @@ - diff --git a/src/Speckle.Objects/packages.lock.json b/src/Speckle.Objects/packages.lock.json index 601bfa28..a9e35e79 100644 --- a/src/Speckle.Objects/packages.lock.json +++ b/src/Speckle.Objects/packages.lock.json @@ -222,6 +222,14 @@ "System.Runtime": "4.3.0" } }, + "System.Threading.Tasks.Extensions": { + "type": "Transitive", + "resolved": "4.5.4", + "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + } + }, "speckle.sdk": { "type": "Project", "dependencies": { @@ -230,13 +238,13 @@ "Microsoft.Data.Sqlite": "[7.0.7, )", "Microsoft.Extensions.DependencyInjection.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Logging": "[2.2.0, )", + "Microsoft.Extensions.ObjectPool": "[8.0.8, )", "Microsoft.IO.RecyclableMemoryStream": "[3.0.1, )", "Polly": "[7.2.3, )", "Polly.Contrib.WaitAndRetry": "[1.1.1, )", "Polly.Extensions.Http": "[3.0.0, )", "Speckle.DoubleNumerics": "[4.0.1, )", - "Speckle.Newtonsoft.Json": "[13.0.2, )", - "System.Threading.Tasks.Extensions": "[4.5.4, )" + "Speckle.Newtonsoft.Json": "[13.0.2, )" } }, "GraphQL.Client": { @@ -284,6 +292,12 @@ "Microsoft.Extensions.Options": "2.2.0" } }, + "Microsoft.Extensions.ObjectPool": { + "type": "CentralTransitive", + "requested": "[8.0.8, )", + "resolved": "8.0.8", + "contentHash": "wnjTFjEvvSbOs3iMfl6CeJcUgPHZMYUB9uAQbGQGxGwVRl4GydNpMSkVntTzoi7AqQeYumU9yDSNeVbpq+ebow==" + }, "Microsoft.IO.RecyclableMemoryStream": { "type": "CentralTransitive", "requested": "[3.0.1, )", @@ -325,15 +339,6 @@ "requested": "[13.0.2, )", "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" - }, - "System.Threading.Tasks.Extensions": { - "type": "CentralTransitive", - "requested": "[4.5.4, )", - "resolved": "4.5.4", - "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "4.5.3" - } } }, "net8.0": { @@ -510,13 +515,13 @@ "Microsoft.Data.Sqlite": "[7.0.7, )", "Microsoft.Extensions.DependencyInjection.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Logging": "[2.2.0, )", + "Microsoft.Extensions.ObjectPool": "[8.0.8, )", "Microsoft.IO.RecyclableMemoryStream": "[3.0.1, )", "Polly": "[7.2.3, )", "Polly.Contrib.WaitAndRetry": "[1.1.1, )", "Polly.Extensions.Http": "[3.0.0, )", "Speckle.DoubleNumerics": "[4.0.1, )", - "Speckle.Newtonsoft.Json": "[13.0.2, )", - "System.Threading.Tasks.Extensions": "[4.5.4, )" + "Speckle.Newtonsoft.Json": "[13.0.2, )" } }, "GraphQL.Client": { @@ -564,6 +569,12 @@ "Microsoft.Extensions.Options": "2.2.0" } }, + "Microsoft.Extensions.ObjectPool": { + "type": "CentralTransitive", + "requested": "[8.0.8, )", + "resolved": "8.0.8", + "contentHash": "wnjTFjEvvSbOs3iMfl6CeJcUgPHZMYUB9uAQbGQGxGwVRl4GydNpMSkVntTzoi7AqQeYumU9yDSNeVbpq+ebow==" + }, "Microsoft.IO.RecyclableMemoryStream": { "type": "CentralTransitive", "requested": "[3.0.1, )", @@ -602,12 +613,6 @@ "requested": "[13.0.2, )", "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" - }, - "System.Threading.Tasks.Extensions": { - "type": "CentralTransitive", - "requested": "[4.5.4, )", - "resolved": "4.5.4", - "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" } } } diff --git a/src/Speckle.Sdk/Helpers/SpeckleObjectSerializer2Pool.cs b/src/Speckle.Sdk/Helpers/SpeckleObjectSerializer2Pool.cs index 449e70ff..1d16213d 100644 --- a/src/Speckle.Sdk/Helpers/SpeckleObjectSerializer2Pool.cs +++ b/src/Speckle.Sdk/Helpers/SpeckleObjectSerializer2Pool.cs @@ -1,4 +1,5 @@ using System.Buffers; +using Microsoft.Extensions.ObjectPool; using Microsoft.IO; using Speckle.Newtonsoft.Json; using Speckle.Sdk.Common; @@ -38,4 +39,19 @@ private class SerializerPool(ArrayPool pool) : IArrayPool public void Return(T[]? array) => pool.Return(array.NotNull()); } + + + public ObjectPool> + DictPool { get; }= new DefaultObjectPoolProvider().Create(new DictPoolPolicy()); + + private class DictPoolPolicy : PooledObjectPolicy> + { + public override Dictionary Create() => new Dictionary(StringComparer.OrdinalIgnoreCase); + + public override bool Return(Dictionary obj) + { + obj.Clear(); + return true; + } + } } diff --git a/src/Speckle.Sdk/Serialisation/SpeckleObjectDeserializer2.cs b/src/Speckle.Sdk/Serialisation/SpeckleObjectDeserializer2.cs new file mode 100644 index 00000000..03dec3c0 --- /dev/null +++ b/src/Speckle.Sdk/Serialisation/SpeckleObjectDeserializer2.cs @@ -0,0 +1,352 @@ +using System.Collections.Concurrent; +using System.Numerics; +using System.Reflection; +using Speckle.Newtonsoft.Json; +using Speckle.Sdk.Common; +using Speckle.Sdk.Helpers; +using Speckle.Sdk.Host; +using Speckle.Sdk.Models; +using Speckle.Sdk.Serialisation.Utilities; +using Speckle.Sdk.Transports; + +namespace Speckle.Sdk.Serialisation; + +public sealed class SpeckleObjectDeserializer2 +{ + public SpeckleObjectSerializer2Pool Pool { get; } = SpeckleObjectSerializer2Pool.Instance; + private bool _isBusy; + private readonly object _callbackLock = new(); + private readonly object?[] _invokeNull = [null]; + + // id -> Base if already deserialized or id -> Task if was handled by a bg thread + private ConcurrentDictionary? _deserializedObjects; + + /// + /// Property that describes the type of the object. + /// + private const string TYPE_DISCRIMINATOR = nameof(Base.speckle_type); + + public CancellationToken CancellationToken { get; set; } + + /// + /// The sync transport. This transport will be used synchronously. + /// + public ITransport ReadTransport { get; set; } + + public Action? OnProgressAction { get; set; } + + private long _currentCount; + private readonly HashSet _ids = new(); + private long _processedCount; + + public string? BlobStorageFolder { get; set; } + + /// The JSON string of the object to be deserialized + /// A typed object deserialized from the + /// Thrown when + /// was null + /// cannot be deserialised to type + // /// did not contain the required json objects (closures) + public async ValueTask DeserializeAsync(string rootObjectJson) + { + if (_isBusy) + { + throw new InvalidOperationException( + "A deserializer instance can deserialize only 1 object at a time. Consider creating multiple deserializer instances" + ); + } + + try + { + _isBusy = true; + _deserializedObjects = new(StringComparer.Ordinal); + _currentCount = 0; + return (Base)(await DeserializeJsonAsyncInternal(rootObjectJson).NotNull().ConfigureAwait(false)); + } + finally + { + _deserializedObjects = null; + _isBusy = false; + } + } + + private async ValueTask DeserializeJsonAsyncInternal(string objectJson) + { + if (objectJson is null) + { + throw new ArgumentNullException(nameof(objectJson), $"Cannot deserialize {nameof(objectJson)}, value was null"); + } + // Apparently this automatically parses DateTimes in strings if it matches the format: + // JObject doc1 = JObject.Parse(objectJson); + + // This is equivalent code that doesn't parse datetimes: + using JsonReader reader = Pool.GetJsonTextReader(new StringReader(objectJson)); + + reader.DateParseHandling = DateParseHandling.None; + + object? converted; + try + { + reader.Read(); + converted = await ReadObjectAsync(reader, CancellationToken).ConfigureAwait(false); + } + catch (Exception ex) when (!ex.IsFatal() && ex is not OperationCanceledException) + { + throw new SpeckleDeserializeException($"Failed to deserialize", ex); + } + + lock (_callbackLock) + { + _processedCount++; + OnProgressAction?.Invoke( + new ProgressArgs(ProgressEvent.DeserializeObject, _currentCount, _ids.Count, _processedCount) + ); + } + + return converted; + } + + //this should be buffered + private async ValueTask> ReadArrayAsync(JsonReader reader, CancellationToken ct) + { + reader.Read(); + List retList = new(); + while (reader.TokenType != JsonToken.EndArray) + { + object? convertedValue = await ReadPropertyAsync(reader, ct).ConfigureAwait(false); + if (convertedValue is DataChunk chunk) + { + retList.AddRange(chunk.data); + } + else + { + retList.Add(convertedValue); + } + reader.Read(); //goes to next + } + return retList; + } + + private async ValueTask ReadObjectAsync(JsonReader reader, CancellationToken ct) + { + reader.Read(); + Dictionary dict = Pool.DictPool.Get(); + while (reader.TokenType != JsonToken.EndObject) + { + switch (reader.TokenType) + { + case JsonToken.PropertyName: + { + string propName = (reader.Value?.ToString()).NotNull(); + if (propName == "__closure") + { + reader.Read(); //goes to prop value + var closures = ClosureParser.GetClosures(reader); + foreach (var closure in closures) + { + _ids.Add(closure.Item1); + } + + foreach (var closure in closures) + { + string objId = closure.Item1; + //don't do anything with return value but later check if null + // https://linear.app/speckle/issue/CXPLA-54/when-deserializing-dont-allow-closures-that-arent-downloadable + await TryGetDeserializedAsync(objId).ConfigureAwait(false); + } + reader.Read(); //goes to next + continue; + } + reader.Read(); //goes prop value + object? convertedValue = await ReadPropertyAsync(reader, ct).ConfigureAwait(false); + dict[propName] = convertedValue; + reader.Read(); //goes to next + } + break; + default: + throw new InvalidOperationException($"Unknown {reader.ValueType} with {reader.Value}"); + } + } + + if (!dict.TryGetValue(TYPE_DISCRIMINATOR, out object? speckleType)) + { + return dict; + } + + if (speckleType as string == "reference" && dict.TryGetValue("referencedId", out object? referencedId)) + { + var objId = (string)referencedId.NotNull(); + object? deserialized = await TryGetDeserializedAsync(objId).ConfigureAwait(false); + return deserialized; + } + + var b = Dict2Base(dict); + Pool.DictPool.Return(dict); + return b; + } + + private async ValueTask TryGetDeserializedAsync(string objId) + { + object? deserialized = null; + _deserializedObjects.NotNull(); + if (_deserializedObjects.TryGetValue(objId, out object? o)) + { + deserialized = o; + } + + if (deserialized is ValueTask valueTask) + { + try + { + deserialized = valueTask.Result; + } + catch (AggregateException ex) + { + throw new SpeckleDeserializeException("Failed to deserialize reference object", ex); + } + + if (_deserializedObjects.TryAdd(objId, deserialized)) + { + _currentCount++; + } + } + if (deserialized is Task task) + { + try + { + deserialized = task.Result; + } + catch (AggregateException ex) + { + throw new SpeckleDeserializeException("Failed to deserialize reference object", ex); + } + + if (_deserializedObjects.TryAdd(objId, deserialized)) + { + _currentCount++; + } + } + if (deserialized != null) + { + return deserialized; + } + + // This reference was not already deserialized. Do it now in sync mode + string? objectJson = await ReadTransport.GetObject(objId).ConfigureAwait(false); + if (objectJson is null) + { + return null; + } + + deserialized = await DeserializeJsonAsyncInternal(objectJson).ConfigureAwait(false); + + if (_deserializedObjects.NotNull().TryAdd(objId, deserialized)) + { + _currentCount++; + } + + return deserialized; + } + + private async ValueTask ReadPropertyAsync(JsonReader reader, CancellationToken ct) + { + switch (reader.TokenType) + { + case JsonToken.Undefined: + case JsonToken.Null: + case JsonToken.None: + return null; + case JsonToken.Boolean: + return (bool)reader.Value.NotNull(); + case JsonToken.Integer: + if (reader.Value is long longValue) + { + return longValue; + } + if (reader.Value is BigInteger bitInt) + { + // This is behaviour carried over from v2 to facilitate large numbers from Python + // This is quite hacky, as it's a bit questionable exactly what numbers are supported, and with what tolerance + // For this reason, this can be considered undocumented behaviour, and is only for values within the range of a 64bit integer. + return (double)bitInt; + } + + throw new ArgumentException( + $"Found an unsupported integer type {reader.Value?.GetType()} with value {reader.Value}" + ); + case JsonToken.Float: + return (double)reader.Value.NotNull(); + case JsonToken.String: + return (string)reader.Value.NotNull(); + case JsonToken.Date: + return (DateTime)reader.Value.NotNull(); + case JsonToken.StartArray: + return await ReadArrayAsync(reader, ct).ConfigureAwait(false); + case JsonToken.StartObject: + var dict = await ReadObjectAsync(reader, ct).ConfigureAwait(false); + return dict; + + default: + throw new ArgumentException("Json value not supported: " + reader.ValueType); + } + } + + private Base Dict2Base(Dictionary dictObj) + { + string typeName = (string)dictObj[TYPE_DISCRIMINATOR].NotNull(); + Type type = TypeLoader.GetType(typeName); + Base baseObj = (Base)Activator.CreateInstance(type).NotNull(); + + dictObj.Remove(TYPE_DISCRIMINATOR); + dictObj.Remove("__closure"); + + var staticProperties = TypeCache.GetTypeProperties(typeName); + foreach (var entry in dictObj) + { + if (staticProperties.TryGetValue(entry.Key, out PropertyInfo? value) && value.CanWrite) + { + if (entry.Value == null) + { + // Check for JsonProperty(NullValueHandling = NullValueHandling.Ignore) attribute + JsonPropertyAttribute? attr = TypeLoader.GetJsonPropertyAttribute(value); + if (attr is { NullValueHandling: NullValueHandling.Ignore }) + { + continue; + } + } + + Type targetValueType = value.PropertyType; + bool conversionOk = ValueConverter.ConvertValue(targetValueType, entry.Value, out object? convertedValue); + if (conversionOk) + { + value.SetValue(baseObj, convertedValue); + } + else + { + // Cannot convert the value in the json to the static property type + throw new SpeckleDeserializeException( + $"Cannot deserialize {entry.Value?.GetType().FullName} to {targetValueType.FullName}" + ); + } + } + else + { + // No writable property with this name + CallSiteCache.SetValue(entry.Key, baseObj, entry.Value); + } + } + + if (baseObj is Blob bb && BlobStorageFolder != null) + { + bb.filePath = bb.GetLocalDestinationPath(BlobStorageFolder); + } + + var onDeserializedCallbacks = TypeCache.GetOnDeserializedCallbacks(typeName); + foreach (MethodInfo onDeserialized in onDeserializedCallbacks) + { + onDeserialized.Invoke(baseObj, _invokeNull); + } + + return baseObj; + } +} diff --git a/src/Speckle.Sdk/Speckle.Sdk.csproj b/src/Speckle.Sdk/Speckle.Sdk.csproj index ab198be1..8a72687d 100644 --- a/src/Speckle.Sdk/Speckle.Sdk.csproj +++ b/src/Speckle.Sdk/Speckle.Sdk.csproj @@ -29,6 +29,7 @@ + @@ -44,7 +45,6 @@ - diff --git a/src/Speckle.Sdk/packages.lock.json b/src/Speckle.Sdk/packages.lock.json index 741121d0..4a1135a2 100644 --- a/src/Speckle.Sdk/packages.lock.json +++ b/src/Speckle.Sdk/packages.lock.json @@ -53,6 +53,12 @@ "Microsoft.Extensions.Options": "2.2.0" } }, + "Microsoft.Extensions.ObjectPool": { + "type": "Direct", + "requested": "[8.0.8, )", + "resolved": "8.0.8", + "contentHash": "wnjTFjEvvSbOs3iMfl6CeJcUgPHZMYUB9uAQbGQGxGwVRl4GydNpMSkVntTzoi7AqQeYumU9yDSNeVbpq+ebow==" + }, "Microsoft.IO.RecyclableMemoryStream": { "type": "Direct", "requested": "[3.0.1, )", @@ -126,15 +132,6 @@ "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" }, - "System.Threading.Tasks.Extensions": { - "type": "Direct", - "requested": "[4.5.4, )", - "resolved": "4.5.4", - "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "4.5.3" - } - }, "GraphQL.Client.Abstractions": { "type": "Transitive", "resolved": "6.0.0", @@ -317,6 +314,14 @@ "dependencies": { "System.Runtime": "4.3.0" } + }, + "System.Threading.Tasks.Extensions": { + "type": "Transitive", + "resolved": "4.5.4", + "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + } } }, "net8.0": { @@ -371,6 +376,12 @@ "Microsoft.Extensions.Options": "2.2.0" } }, + "Microsoft.Extensions.ObjectPool": { + "type": "Direct", + "requested": "[8.0.8, )", + "resolved": "8.0.8", + "contentHash": "wnjTFjEvvSbOs3iMfl6CeJcUgPHZMYUB9uAQbGQGxGwVRl4GydNpMSkVntTzoi7AqQeYumU9yDSNeVbpq+ebow==" + }, "Microsoft.IO.RecyclableMemoryStream": { "type": "Direct", "requested": "[3.0.1, )", @@ -432,12 +443,6 @@ "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" }, - "System.Threading.Tasks.Extensions": { - "type": "Direct", - "requested": "[4.5.4, )", - "resolved": "4.5.4", - "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" - }, "GraphQL.Client.Abstractions": { "type": "Transitive", "resolved": "6.0.0", diff --git a/tests/Speckle.Objects.Tests.Unit/packages.lock.json b/tests/Speckle.Objects.Tests.Unit/packages.lock.json index 587ef8f9..8d72263b 100644 --- a/tests/Speckle.Objects.Tests.Unit/packages.lock.json +++ b/tests/Speckle.Objects.Tests.Unit/packages.lock.json @@ -278,13 +278,13 @@ "Microsoft.Data.Sqlite": "[7.0.7, )", "Microsoft.Extensions.DependencyInjection.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Logging": "[2.2.0, )", + "Microsoft.Extensions.ObjectPool": "[8.0.8, )", "Microsoft.IO.RecyclableMemoryStream": "[3.0.1, )", "Polly": "[7.2.3, )", "Polly.Contrib.WaitAndRetry": "[1.1.1, )", "Polly.Extensions.Http": "[3.0.0, )", "Speckle.DoubleNumerics": "[4.0.1, )", - "Speckle.Newtonsoft.Json": "[13.0.2, )", - "System.Threading.Tasks.Extensions": "[4.5.4, )" + "Speckle.Newtonsoft.Json": "[13.0.2, )" } }, "GraphQL.Client": { @@ -332,6 +332,12 @@ "Microsoft.Extensions.Options": "2.2.0" } }, + "Microsoft.Extensions.ObjectPool": { + "type": "CentralTransitive", + "requested": "[8.0.8, )", + "resolved": "8.0.8", + "contentHash": "wnjTFjEvvSbOs3iMfl6CeJcUgPHZMYUB9uAQbGQGxGwVRl4GydNpMSkVntTzoi7AqQeYumU9yDSNeVbpq+ebow==" + }, "Microsoft.IO.RecyclableMemoryStream": { "type": "CentralTransitive", "requested": "[3.0.1, )", @@ -370,12 +376,6 @@ "requested": "[13.0.2, )", "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" - }, - "System.Threading.Tasks.Extensions": { - "type": "CentralTransitive", - "requested": "[4.5.4, )", - "resolved": "4.5.4", - "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" } } } diff --git a/tests/Speckle.Sdk.Performance.Testing/packages.lock.json b/tests/Speckle.Sdk.Performance.Testing/packages.lock.json index 09ff7039..e45aa284 100644 --- a/tests/Speckle.Sdk.Performance.Testing/packages.lock.json +++ b/tests/Speckle.Sdk.Performance.Testing/packages.lock.json @@ -319,6 +319,11 @@ "System.Runtime.CompilerServices.Unsafe": "4.5.2" } }, + "System.Threading.Tasks.Extensions": { + "type": "Transitive", + "resolved": "4.5.4", + "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" + }, "speckle.objects": { "type": "Project", "dependencies": { @@ -333,13 +338,13 @@ "Microsoft.Data.Sqlite": "[7.0.7, )", "Microsoft.Extensions.DependencyInjection.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Logging": "[2.2.0, )", + "Microsoft.Extensions.ObjectPool": "[8.0.8, )", "Microsoft.IO.RecyclableMemoryStream": "[3.0.1, )", "Polly": "[7.2.3, )", "Polly.Contrib.WaitAndRetry": "[1.1.1, )", "Polly.Extensions.Http": "[3.0.0, )", "Speckle.DoubleNumerics": "[4.0.1, )", - "Speckle.Newtonsoft.Json": "[13.0.2, )", - "System.Threading.Tasks.Extensions": "[4.5.4, )" + "Speckle.Newtonsoft.Json": "[13.0.2, )" } }, "speckle.sdk.tests.performance": { @@ -422,6 +427,12 @@ "Microsoft.Extensions.Options": "2.2.0" } }, + "Microsoft.Extensions.ObjectPool": { + "type": "CentralTransitive", + "requested": "[8.0.8, )", + "resolved": "8.0.8", + "contentHash": "wnjTFjEvvSbOs3iMfl6CeJcUgPHZMYUB9uAQbGQGxGwVRl4GydNpMSkVntTzoi7AqQeYumU9yDSNeVbpq+ebow==" + }, "Microsoft.IO.RecyclableMemoryStream": { "type": "CentralTransitive", "requested": "[3.0.1, )", @@ -460,12 +471,6 @@ "requested": "[13.0.2, )", "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" - }, - "System.Threading.Tasks.Extensions": { - "type": "CentralTransitive", - "requested": "[4.5.4, )", - "resolved": "4.5.4", - "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" } } } diff --git a/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json b/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json index 587ef8f9..8d72263b 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json +++ b/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json @@ -278,13 +278,13 @@ "Microsoft.Data.Sqlite": "[7.0.7, )", "Microsoft.Extensions.DependencyInjection.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Logging": "[2.2.0, )", + "Microsoft.Extensions.ObjectPool": "[8.0.8, )", "Microsoft.IO.RecyclableMemoryStream": "[3.0.1, )", "Polly": "[7.2.3, )", "Polly.Contrib.WaitAndRetry": "[1.1.1, )", "Polly.Extensions.Http": "[3.0.0, )", "Speckle.DoubleNumerics": "[4.0.1, )", - "Speckle.Newtonsoft.Json": "[13.0.2, )", - "System.Threading.Tasks.Extensions": "[4.5.4, )" + "Speckle.Newtonsoft.Json": "[13.0.2, )" } }, "GraphQL.Client": { @@ -332,6 +332,12 @@ "Microsoft.Extensions.Options": "2.2.0" } }, + "Microsoft.Extensions.ObjectPool": { + "type": "CentralTransitive", + "requested": "[8.0.8, )", + "resolved": "8.0.8", + "contentHash": "wnjTFjEvvSbOs3iMfl6CeJcUgPHZMYUB9uAQbGQGxGwVRl4GydNpMSkVntTzoi7AqQeYumU9yDSNeVbpq+ebow==" + }, "Microsoft.IO.RecyclableMemoryStream": { "type": "CentralTransitive", "requested": "[3.0.1, )", @@ -370,12 +376,6 @@ "requested": "[13.0.2, )", "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" - }, - "System.Threading.Tasks.Extensions": { - "type": "CentralTransitive", - "requested": "[4.5.4, )", - "resolved": "4.5.4", - "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" } } } diff --git a/tests/Speckle.Sdk.Tests.Integration/packages.lock.json b/tests/Speckle.Sdk.Tests.Integration/packages.lock.json index 491c9872..55699d02 100644 --- a/tests/Speckle.Sdk.Tests.Integration/packages.lock.json +++ b/tests/Speckle.Sdk.Tests.Integration/packages.lock.json @@ -272,13 +272,13 @@ "Microsoft.Data.Sqlite": "[7.0.7, )", "Microsoft.Extensions.DependencyInjection.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Logging": "[2.2.0, )", + "Microsoft.Extensions.ObjectPool": "[8.0.8, )", "Microsoft.IO.RecyclableMemoryStream": "[3.0.1, )", "Polly": "[7.2.3, )", "Polly.Contrib.WaitAndRetry": "[1.1.1, )", "Polly.Extensions.Http": "[3.0.0, )", "Speckle.DoubleNumerics": "[4.0.1, )", - "Speckle.Newtonsoft.Json": "[13.0.2, )", - "System.Threading.Tasks.Extensions": "[4.5.4, )" + "Speckle.Newtonsoft.Json": "[13.0.2, )" } }, "speckle.sdk.tests.unit": { @@ -348,6 +348,12 @@ "Microsoft.Extensions.Options": "2.2.0" } }, + "Microsoft.Extensions.ObjectPool": { + "type": "CentralTransitive", + "requested": "[8.0.8, )", + "resolved": "8.0.8", + "contentHash": "wnjTFjEvvSbOs3iMfl6CeJcUgPHZMYUB9uAQbGQGxGwVRl4GydNpMSkVntTzoi7AqQeYumU9yDSNeVbpq+ebow==" + }, "Microsoft.IO.RecyclableMemoryStream": { "type": "CentralTransitive", "requested": "[3.0.1, )", @@ -386,12 +392,6 @@ "requested": "[13.0.2, )", "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" - }, - "System.Threading.Tasks.Extensions": { - "type": "CentralTransitive", - "requested": "[4.5.4, )", - "resolved": "4.5.4", - "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" } } } diff --git a/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralDeserializerTest.cs b/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralDeserializerTest.cs index b64ddf4a..b2797fb7 100644 --- a/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralDeserializerTest.cs +++ b/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralDeserializerTest.cs @@ -22,12 +22,15 @@ public class GeneralDeserializer : IDisposable public async Task Setup() { TypeLoader.Initialize(typeof(Base).Assembly, typeof(Point).Assembly); + var url = "https://latest.speckle.systems/projects/a3ac1b2706/models/59d3b0f3c6"; //small? + + //var url = "https://latest.speckle.systems/projects/2099ac4b5f/models/da511c4d1e"; //perf? _dataSource = new TestDataHelper(); await _dataSource .SeedTransport( new Account() { - serverInfo = new() { url = "https://latest.speckle.systems/projects/2099ac4b5f/models/da511c4d1e" } + serverInfo = new() { url =url } }, "2099ac4b5f", "30fb4cbe6eb2202b9e7b4a4fcc3dd2b6" @@ -46,7 +49,7 @@ public async Task RunTest() [Benchmark] public async Task RunTest2() { - SpeckleObjectDeserializer sut = new() { ReadTransport = _dataSource.Transport }; + SpeckleObjectDeserializer2 sut = new() { ReadTransport = _dataSource.Transport }; string data = await _dataSource.Transport.GetObject(_dataSource.ObjectId)!; return await sut.DeserializeAsync(data); } diff --git a/tests/Speckle.Sdk.Tests.Performance/packages.lock.json b/tests/Speckle.Sdk.Tests.Performance/packages.lock.json index 0889d65f..57c10730 100644 --- a/tests/Speckle.Sdk.Tests.Performance/packages.lock.json +++ b/tests/Speckle.Sdk.Tests.Performance/packages.lock.json @@ -346,6 +346,11 @@ "System.Runtime.CompilerServices.Unsafe": "4.5.2" } }, + "System.Threading.Tasks.Extensions": { + "type": "Transitive", + "resolved": "4.5.4", + "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" + }, "speckle.objects": { "type": "Project", "dependencies": { @@ -360,13 +365,13 @@ "Microsoft.Data.Sqlite": "[7.0.7, )", "Microsoft.Extensions.DependencyInjection.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Logging": "[2.2.0, )", + "Microsoft.Extensions.ObjectPool": "[8.0.8, )", "Microsoft.IO.RecyclableMemoryStream": "[3.0.1, )", "Polly": "[7.2.3, )", "Polly.Contrib.WaitAndRetry": "[1.1.1, )", "Polly.Extensions.Http": "[3.0.0, )", "Speckle.DoubleNumerics": "[4.0.1, )", - "Speckle.Newtonsoft.Json": "[13.0.2, )", - "System.Threading.Tasks.Extensions": "[4.5.4, )" + "Speckle.Newtonsoft.Json": "[13.0.2, )" } }, "GraphQL.Client": { @@ -414,6 +419,12 @@ "Microsoft.Extensions.Options": "2.2.0" } }, + "Microsoft.Extensions.ObjectPool": { + "type": "CentralTransitive", + "requested": "[8.0.8, )", + "resolved": "8.0.8", + "contentHash": "wnjTFjEvvSbOs3iMfl6CeJcUgPHZMYUB9uAQbGQGxGwVRl4GydNpMSkVntTzoi7AqQeYumU9yDSNeVbpq+ebow==" + }, "Microsoft.IO.RecyclableMemoryStream": { "type": "CentralTransitive", "requested": "[3.0.1, )", @@ -452,12 +463,6 @@ "requested": "[13.0.2, )", "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" - }, - "System.Threading.Tasks.Extensions": { - "type": "CentralTransitive", - "requested": "[4.5.4, )", - "resolved": "4.5.4", - "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" } } } diff --git a/tests/Speckle.Sdk.Tests.Unit/packages.lock.json b/tests/Speckle.Sdk.Tests.Unit/packages.lock.json index c07ced15..8e774e98 100644 --- a/tests/Speckle.Sdk.Tests.Unit/packages.lock.json +++ b/tests/Speckle.Sdk.Tests.Unit/packages.lock.json @@ -287,13 +287,13 @@ "Microsoft.Data.Sqlite": "[7.0.7, )", "Microsoft.Extensions.DependencyInjection.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Logging": "[2.2.0, )", + "Microsoft.Extensions.ObjectPool": "[8.0.8, )", "Microsoft.IO.RecyclableMemoryStream": "[3.0.1, )", "Polly": "[7.2.3, )", "Polly.Contrib.WaitAndRetry": "[1.1.1, )", "Polly.Extensions.Http": "[3.0.0, )", "Speckle.DoubleNumerics": "[4.0.1, )", - "Speckle.Newtonsoft.Json": "[13.0.2, )", - "System.Threading.Tasks.Extensions": "[4.5.4, )" + "Speckle.Newtonsoft.Json": "[13.0.2, )" } }, "GraphQL.Client": { @@ -341,6 +341,12 @@ "Microsoft.Extensions.Options": "2.2.0" } }, + "Microsoft.Extensions.ObjectPool": { + "type": "CentralTransitive", + "requested": "[8.0.8, )", + "resolved": "8.0.8", + "contentHash": "wnjTFjEvvSbOs3iMfl6CeJcUgPHZMYUB9uAQbGQGxGwVRl4GydNpMSkVntTzoi7AqQeYumU9yDSNeVbpq+ebow==" + }, "Microsoft.IO.RecyclableMemoryStream": { "type": "CentralTransitive", "requested": "[3.0.1, )", @@ -373,12 +379,6 @@ "requested": "[13.0.2, )", "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" - }, - "System.Threading.Tasks.Extensions": { - "type": "CentralTransitive", - "requested": "[4.5.4, )", - "resolved": "4.5.4", - "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" } } }