From 286471d6f01e8c2ae5ec635ed966da8252a506cf Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 11:11:18 +0000 Subject: [PATCH 1/6] refactor options to use on factories, add dummies --- .../V2/DummySendServerObjectManager.cs | 21 ++++++++-- .../V2/Receive/DeserializeProcess.cs | 11 +++--- .../V2/Receive/ObjectDeserializer.cs | 2 +- .../V2/Receive/ObjectDeserializerFactory.cs | 2 +- .../Serialisation/V2/Receive/ObjectLoader.cs | 4 +- .../Serialisation/V2/Send/SerializeProcess.cs | 9 ++--- .../V2/SerializeProcessFactory.cs | 39 ++++++++++++++++--- .../Program.cs | 8 ++-- .../DetachedTests.cs | 8 ++-- .../SerializationTests.cs | 12 +++--- .../Benchmarks/GeneralDeserializerTest.cs | 4 +- 11 files changed, 80 insertions(+), 40 deletions(-) rename tests/Speckle.Sdk.Serialization.Testing/DummyServerObjectManager.cs => src/Speckle.Sdk/Serialisation/V2/DummySendServerObjectManager.cs (60%) diff --git a/tests/Speckle.Sdk.Serialization.Testing/DummyServerObjectManager.cs b/src/Speckle.Sdk/Serialisation/V2/DummySendServerObjectManager.cs similarity index 60% rename from tests/Speckle.Sdk.Serialization.Testing/DummyServerObjectManager.cs rename to src/Speckle.Sdk/Serialisation/V2/DummySendServerObjectManager.cs index 226238f6..e50ef75e 100644 --- a/tests/Speckle.Sdk.Serialization.Testing/DummyServerObjectManager.cs +++ b/src/Speckle.Sdk/Serialisation/V2/DummySendServerObjectManager.cs @@ -1,11 +1,26 @@ using System.Text; using Speckle.Sdk.Dependencies.Serialization; -using Speckle.Sdk.Serialisation.V2; +using Speckle.Sdk.SQLite; using Speckle.Sdk.Transports; -namespace Speckle.Sdk.Serialization.Testing; +namespace Speckle.Sdk.Serialisation.V2; -public class DummyServerObjectManager : IServerObjectManager +public class DummySqLiteJsonCacheManager : ISqLiteJsonCacheManager +{ + public IEnumerable GetAllObjects() => throw new NotImplementedException(); + + public void DeleteObject(string id) => throw new NotImplementedException(); + + public string? GetObject(string id) => throw new NotImplementedException(); + + public void SaveObject(string id, string json) => throw new NotImplementedException(); + + public void SaveObjects(IEnumerable<(string id, string json)> items) => throw new NotImplementedException(); + + public bool HasObject(string objectId) => throw new NotImplementedException(); +} + +public class DummySendServerObjectManager : IServerObjectManager { public IAsyncEnumerable<(string, string)> DownloadObjects( IReadOnlyList objectIds, diff --git a/src/Speckle.Sdk/Serialisation/V2/Receive/DeserializeProcess.cs b/src/Speckle.Sdk/Serialisation/V2/Receive/DeserializeProcess.cs index 183b3d60..aa224248 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Receive/DeserializeProcess.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Receive/DeserializeProcess.cs @@ -6,7 +6,7 @@ namespace Speckle.Sdk.Serialisation.V2.Receive; -public record DeserializeOptions( +public record DeserializeProcessOptions( bool SkipCache, bool ThrowOnMissingReferences = true, bool SkipInvalidConverts = false @@ -16,10 +16,11 @@ public record DeserializeOptions( public sealed class DeserializeProcess( IProgress? progress, IObjectLoader objectLoader, - IObjectDeserializerFactory objectDeserializerFactory + IObjectDeserializerFactory objectDeserializerFactory, + DeserializeProcessOptions? options = null ) : IDeserializeProcess { - private DeserializeOptions _options = new(false); + private readonly DeserializeProcessOptions _options = options ?? new(false); private readonly ConcurrentDictionary)> _closures = new(); private readonly ConcurrentDictionary _baseCache = new(); @@ -30,11 +31,9 @@ IObjectDeserializerFactory objectDeserializerFactory public async Task Deserialize( string rootId, - CancellationToken cancellationToken, - DeserializeOptions? options = null + CancellationToken cancellationToken ) { - _options = options ?? _options; var (rootJson, childrenIds) = await objectLoader .GetAndCache(rootId, _options, cancellationToken) .ConfigureAwait(false); diff --git a/src/Speckle.Sdk/Serialisation/V2/Receive/ObjectDeserializer.cs b/src/Speckle.Sdk/Serialisation/V2/Receive/ObjectDeserializer.cs index 8cdf757f..651fcf0d 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Receive/ObjectDeserializer.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Receive/ObjectDeserializer.cs @@ -13,7 +13,7 @@ public sealed class ObjectDeserializer( IReadOnlyList currentClosures, IReadOnlyDictionary references, SpeckleObjectSerializerPool pool, - DeserializeOptions? options = null + DeserializeProcessOptions? options = null ) : IObjectDeserializer { /// The JSON string of the object to be deserialized diff --git a/src/Speckle.Sdk/Serialisation/V2/Receive/ObjectDeserializerFactory.cs b/src/Speckle.Sdk/Serialisation/V2/Receive/ObjectDeserializerFactory.cs index 9458c121..01e6d480 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Receive/ObjectDeserializerFactory.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Receive/ObjectDeserializerFactory.cs @@ -10,6 +10,6 @@ public IObjectDeserializer Create( string currentId, IReadOnlyList currentClosures, IReadOnlyDictionary references, - DeserializeOptions? options = null + DeserializeProcessOptions? options = null ) => new ObjectDeserializer(currentId, currentClosures, references, SpeckleObjectSerializerPool.Instance, options); } diff --git a/src/Speckle.Sdk/Serialisation/V2/Receive/ObjectLoader.cs b/src/Speckle.Sdk/Serialisation/V2/Receive/ObjectLoader.cs index d7d9322d..124b5d5f 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Receive/ObjectLoader.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Receive/ObjectLoader.cs @@ -17,11 +17,11 @@ public sealed class ObjectLoader( private int? _allChildrenCount; private long _checkCache; private long _cached; - private DeserializeOptions _options = new(false); + private DeserializeProcessOptions _options = new(false); public async Task<(string, IReadOnlyList)> GetAndCache( string rootId, - DeserializeOptions options, + DeserializeProcessOptions options, CancellationToken cancellationToken ) { diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs b/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs index d6f9aed2..a3a5a9f6 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs @@ -21,7 +21,8 @@ public class SerializeProcess( ISqLiteJsonCacheManager sqLiteJsonCacheManager, IServerObjectManager serverObjectManager, IBaseChildFinder baseChildFinder, - IObjectSerializerFactory objectSerializerFactory + IObjectSerializerFactory objectSerializerFactory, + SerializeProcessOptions? options = null ) : ChannelSaver, ISerializeProcess { private readonly ConcurrentDictionary _jsonCache = new(); @@ -34,15 +35,13 @@ IObjectSerializerFactory objectSerializerFactory private long _cached; private long _serialized; - private SerializeProcessOptions _options = new(false, false, false); + private readonly SerializeProcessOptions _options = options ?? new(false, false, false); public async Task Serialize( Base root, - CancellationToken cancellationToken, - SerializeProcessOptions? options = null + CancellationToken cancellationToken ) { - _options = options ?? _options; var channelTask = Start(cancellationToken); await Traverse(root, true, cancellationToken).ConfigureAwait(false); await channelTask.ConfigureAwait(false); diff --git a/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs b/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs index 48346809..9d48827e 100644 --- a/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs +++ b/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs @@ -13,13 +13,20 @@ ISerializeProcess CreateSerializeProcess( Uri url, string streamId, string? authorizationToken, - IProgress? progress + IProgress? progress, + SerializeProcessOptions? options = null ); IDeserializeProcess CreateDeserializeProcess( Uri url, string streamId, string? authorizationToken, - IProgress? progress + IProgress? progress, + DeserializeProcessOptions? options = null + ); + + public ISerializeProcess CreateSerializeProcess( + SerializeProcessOptions? options = null, + IProgress? progress = null ); } @@ -36,7 +43,8 @@ public ISerializeProcess CreateSerializeProcess( Uri url, string streamId, string? authorizationToken, - IProgress? progress + IProgress? progress, + SerializeProcessOptions? options = null ) { var sqLiteJsonCacheManager = sqLiteJsonCacheManagerFactory.CreateFromStream(streamId); @@ -46,7 +54,25 @@ public ISerializeProcess CreateSerializeProcess( sqLiteJsonCacheManager, serverObjectManager, baseChildFinder, - objectSerializerFactory + objectSerializerFactory, + options + ); + } + + public ISerializeProcess CreateSerializeProcess( + SerializeProcessOptions? options = null, + IProgress? progress = null + ) + { + var sqLiteJsonCacheManager = new DummySqLiteJsonCacheManager(); + var serverObjectManager = new DummySendServerObjectManager(); + return new SerializeProcess( + progress, + sqLiteJsonCacheManager, + serverObjectManager, + baseChildFinder, + objectSerializerFactory, + options ); } @@ -54,13 +80,14 @@ public IDeserializeProcess CreateDeserializeProcess( Uri url, string streamId, string? authorizationToken, - IProgress? progress + IProgress? progress, + DeserializeProcessOptions? options = null ) { var sqLiteJsonCacheManager = sqLiteJsonCacheManagerFactory.CreateFromStream(streamId); var serverObjectManager = new ServerObjectManager(speckleHttp, activityFactory, url, streamId, authorizationToken); var objectLoader = new ObjectLoader(sqLiteJsonCacheManager, serverObjectManager, progress); - return new DeserializeProcess(progress, objectLoader, objectDeserializerFactory); + return new DeserializeProcess(progress, objectLoader, objectDeserializerFactory, options); } } diff --git a/tests/Speckle.Sdk.Serialization.Testing/Program.cs b/tests/Speckle.Sdk.Serialization.Testing/Program.cs index 74bbef0e..095da2fa 100644 --- a/tests/Speckle.Sdk.Serialization.Testing/Program.cs +++ b/tests/Speckle.Sdk.Serialization.Testing/Program.cs @@ -50,15 +50,15 @@ new ObjectDeserializerFactory(), serviceProvider.GetRequiredService() ); -var process = factory.CreateDeserializeProcess(new Uri(url), streamId, token, progress); -var @base = await process.Deserialize(rootId, default, new(skipCacheReceive)).ConfigureAwait(false); +var process = factory.CreateDeserializeProcess(new Uri(url), streamId, token, progress, new(skipCacheReceive)); +var @base = await process.Deserialize(rootId, default).ConfigureAwait(false); Console.WriteLine("Deserialized"); Console.ReadLine(); Console.WriteLine("Executing"); -var process2 = factory.CreateSerializeProcess(new Uri(url), streamId, token, progress); +var process2 = factory.CreateSerializeProcess(new Uri(url), streamId, token, progress, new SerializeProcessOptions(skipCacheSendCheck, skipCacheSendSave, true)); await process2 - .Serialize(@base, default, new SerializeProcessOptions(skipCacheSendCheck, skipCacheSendSave, true)) + .Serialize(@base, default) .ConfigureAwait(false); Console.WriteLine("Detach"); Console.ReadLine(); diff --git a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs index f15d5088..061411af 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs @@ -73,9 +73,9 @@ public async Task CanSerialize_New_Detached() new DummySendCacheManager(objects), new DummyServerObjectManager(), new BaseChildFinder(new BasePropertyGatherer()), - new ObjectSerializerFactory(new BasePropertyGatherer()) + new ObjectSerializerFactory(new BasePropertyGatherer()), new SerializeProcessOptions(false, false, true) ); - await process2.Serialize(@base, default, new SerializeProcessOptions(false, false, true)).ConfigureAwait(false); + await process2.Serialize(@base, default).ConfigureAwait(false); objects.Count.ShouldBe(2); objects.ContainsKey("9ff8efb13c62fa80f3d1c4519376ba13").ShouldBeTrue(); @@ -264,10 +264,10 @@ public async Task CanSerialize_New_Detached2() new DummySendCacheManager(objects), new DummyServerObjectManager(), new BaseChildFinder(new BasePropertyGatherer()), - new ObjectSerializerFactory(new BasePropertyGatherer()) + new ObjectSerializerFactory(new BasePropertyGatherer()), new SerializeProcessOptions(false, false, true) ); var results = await process2 - .Serialize(@base, default, new SerializeProcessOptions(false, false, true)) + .Serialize(@base, default) .ConfigureAwait(false); objects.Count.ShouldBe(9); diff --git a/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs b/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs index 30f1e8eb..fa62df3a 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs @@ -24,7 +24,7 @@ private class TestLoader(string json) : IObjectLoader { public Task<(string, IReadOnlyList)> GetAndCache( string rootId, - DeserializeOptions? options, + DeserializeProcessOptions? options, CancellationToken cancellationToken ) { @@ -88,7 +88,7 @@ public class TestObjectLoader(Dictionary idToObject) : IObjectLo { public Task<(string, IReadOnlyList)> GetAndCache( string rootId, - DeserializeOptions? options, + DeserializeProcessOptions? options, CancellationToken cancellationToken ) { @@ -251,8 +251,8 @@ public async Task Roundtrip_Test_New(string fileName, string rootId, int oldCoun new DummyReceiveServerObjectManager(closure), null ); - var process = new DeserializeProcess(null, o, new ObjectDeserializerFactory()); - var root = await process.Deserialize(rootId, default, new DeserializeOptions(true)); + var process = new DeserializeProcess(null, o, new ObjectDeserializerFactory(), new (true)); + var root = await process.Deserialize(rootId, default); process.BaseCache.Count.ShouldBe(oldCount); process.Total.ShouldBe(oldCount); @@ -262,9 +262,9 @@ public async Task Roundtrip_Test_New(string fileName, string rootId, int oldCoun new DummySqLiteSendManager(), new DummySendServerObjectManager(newIdToJson), new BaseChildFinder(new BasePropertyGatherer()), - new ObjectSerializerFactory(new BasePropertyGatherer()) + new ObjectSerializerFactory(new BasePropertyGatherer()), new SerializeProcessOptions(true, true, false) ); - var (rootId2, _) = await serializeProcess.Serialize(root, default, new SerializeProcessOptions(true, true, false)); + var (rootId2, _) = await serializeProcess.Serialize(root, default); rootId2.ShouldBe(root.id); newIdToJson.Count.ShouldBe(newCount); diff --git a/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralDeserializerTest.cs b/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralDeserializerTest.cs index 510889f6..6ffc63ea 100644 --- a/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralDeserializerTest.cs +++ b/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralDeserializerTest.cs @@ -57,8 +57,8 @@ public async Task RunTest_New() null ); var o = new ObjectLoader(sqlite, serverObjects, null); - var process = new DeserializeProcess(null, o, new ObjectDeserializerFactory()); - return await process.Deserialize(rootId, default, new(skipCache)).ConfigureAwait(false); + var process = new DeserializeProcess(null, o, new ObjectDeserializerFactory(), new(skipCache)); + return await process.Deserialize(rootId, default).ConfigureAwait(false); } /* From d46bfecfe911f222201186e0abb8f063fbaf6124 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 12:39:38 +0000 Subject: [PATCH 2/6] format --- .../Serialisation/V2/Receive/DeserializeProcess.cs | 5 +---- .../Serialisation/V2/Send/SerializeProcess.cs | 5 +---- .../Serialisation/V2/SerializeProcessFactory.cs | 2 +- tests/Speckle.Sdk.Serialization.Testing/Program.cs | 12 ++++++++---- .../Speckle.Sdk.Serialization.Tests/DetachedTests.cs | 10 +++++----- .../SerializationTests.cs | 5 +++-- 6 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/Speckle.Sdk/Serialisation/V2/Receive/DeserializeProcess.cs b/src/Speckle.Sdk/Serialisation/V2/Receive/DeserializeProcess.cs index aa224248..ea3cce01 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Receive/DeserializeProcess.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Receive/DeserializeProcess.cs @@ -29,10 +29,7 @@ public sealed class DeserializeProcess( public IReadOnlyDictionary BaseCache => _baseCache; public long Total { get; private set; } - public async Task Deserialize( - string rootId, - CancellationToken cancellationToken - ) + public async Task Deserialize(string rootId, CancellationToken cancellationToken) { var (rootJson, childrenIds) = await objectLoader .GetAndCache(rootId, _options, cancellationToken) diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs b/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs index a3a5a9f6..9340a316 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs @@ -37,10 +37,7 @@ public class SerializeProcess( private readonly SerializeProcessOptions _options = options ?? new(false, false, false); - public async Task Serialize( - Base root, - CancellationToken cancellationToken - ) + public async Task Serialize(Base root, CancellationToken cancellationToken) { var channelTask = Start(cancellationToken); await Traverse(root, true, cancellationToken).ConfigureAwait(false); diff --git a/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs b/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs index 9d48827e..36cc08af 100644 --- a/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs +++ b/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs @@ -58,7 +58,7 @@ public ISerializeProcess CreateSerializeProcess( options ); } - + public ISerializeProcess CreateSerializeProcess( SerializeProcessOptions? options = null, IProgress? progress = null diff --git a/tests/Speckle.Sdk.Serialization.Testing/Program.cs b/tests/Speckle.Sdk.Serialization.Testing/Program.cs index 095da2fa..5df2d34d 100644 --- a/tests/Speckle.Sdk.Serialization.Testing/Program.cs +++ b/tests/Speckle.Sdk.Serialization.Testing/Program.cs @@ -56,10 +56,14 @@ Console.ReadLine(); Console.WriteLine("Executing"); -var process2 = factory.CreateSerializeProcess(new Uri(url), streamId, token, progress, new SerializeProcessOptions(skipCacheSendCheck, skipCacheSendSave, true)); -await process2 - .Serialize(@base, default) - .ConfigureAwait(false); +var process2 = factory.CreateSerializeProcess( + new Uri(url), + streamId, + token, + progress, + new SerializeProcessOptions(skipCacheSendCheck, skipCacheSendSave, true) +); +await process2.Serialize(@base, default).ConfigureAwait(false); Console.WriteLine("Detach"); Console.ReadLine(); #pragma warning restore CA1506 diff --git a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs index 061411af..54316cd2 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs @@ -73,7 +73,8 @@ public async Task CanSerialize_New_Detached() new DummySendCacheManager(objects), new DummyServerObjectManager(), new BaseChildFinder(new BasePropertyGatherer()), - new ObjectSerializerFactory(new BasePropertyGatherer()), new SerializeProcessOptions(false, false, true) + new ObjectSerializerFactory(new BasePropertyGatherer()), + new SerializeProcessOptions(false, false, true) ); await process2.Serialize(@base, default).ConfigureAwait(false); @@ -264,11 +265,10 @@ public async Task CanSerialize_New_Detached2() new DummySendCacheManager(objects), new DummyServerObjectManager(), new BaseChildFinder(new BasePropertyGatherer()), - new ObjectSerializerFactory(new BasePropertyGatherer()), new SerializeProcessOptions(false, false, true) + new ObjectSerializerFactory(new BasePropertyGatherer()), + new SerializeProcessOptions(false, false, true) ); - var results = await process2 - .Serialize(@base, default) - .ConfigureAwait(false); + var results = await process2.Serialize(@base, default).ConfigureAwait(false); objects.Count.ShouldBe(9); var x = JObject.Parse(objects["fd4efeb8a036838c53ad1cf9e82b8992"]); diff --git a/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs b/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs index fa62df3a..90496a57 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs @@ -251,7 +251,7 @@ public async Task Roundtrip_Test_New(string fileName, string rootId, int oldCoun new DummyReceiveServerObjectManager(closure), null ); - var process = new DeserializeProcess(null, o, new ObjectDeserializerFactory(), new (true)); + var process = new DeserializeProcess(null, o, new ObjectDeserializerFactory(), new(true)); var root = await process.Deserialize(rootId, default); process.BaseCache.Count.ShouldBe(oldCount); process.Total.ShouldBe(oldCount); @@ -262,7 +262,8 @@ public async Task Roundtrip_Test_New(string fileName, string rootId, int oldCoun new DummySqLiteSendManager(), new DummySendServerObjectManager(newIdToJson), new BaseChildFinder(new BasePropertyGatherer()), - new ObjectSerializerFactory(new BasePropertyGatherer()), new SerializeProcessOptions(true, true, false) + new ObjectSerializerFactory(new BasePropertyGatherer()), + new SerializeProcessOptions(true, true, false) ); var (rootId2, _) = await serializeProcess.Serialize(root, default); From 3e53cfaca75040f5eb6c36458cee421ad5996b65 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 13:53:55 +0000 Subject: [PATCH 3/6] reduce lists to yield return --- .../Serialisation/V2/Send/ObjectSerializer.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs index 83fd30fd..95b3b6ed 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs @@ -61,16 +61,21 @@ public ObjectSerializer( { try { + (Id, Json) item; try { - var item = SerializeBase(baseObj, true).NotNull(); - _baseCache.TryAdd(baseObj, new(item.Item2, _currentClosures)); - return [new(item.Item1, item.Item2), .. _chunks]; + item = SerializeBase(baseObj, true).NotNull(); } catch (Exception ex) when (!ex.IsFatal() && ex is not OperationCanceledException) { throw new SpeckleSerializeException($"Failed to extract (pre-serialize) properties from the {baseObj}", ex); } + _baseCache.TryAdd(baseObj, new(item.Item2, _currentClosures)); + yield return (item.Item1, item.Item2); + foreach (var chunk in _chunks) + { + yield return chunk; + } } finally { From ac87b94cd6aa3dde6b34a52c46c57687650a62da Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 14:43:10 +0000 Subject: [PATCH 4/6] get primitives first to avoid to string --- .../Serialisation/V2/Send/ObjectSerializer.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs index 95b3b6ed..4ea0f64b 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs @@ -95,6 +95,25 @@ private void SerializeProperty(object? obj, JsonWriter writer, PropertyAttribute return; } + switch (obj) + { + case double d: + writer.WriteValue(d); + return; + case string d: + writer.WriteValue(d); + return; + case bool d: + writer.WriteValue(d); + return; + case int d: + writer.WriteValue(d); + return; + case long d: + writer.WriteValue(d); + return; + } + if (obj.GetType().IsPrimitive || obj is string) { writer.WriteValue(obj); From 428841e6d09a6374158f40b4902f0f1a2a08b23d Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 14:43:30 +0000 Subject: [PATCH 5/6] fmt --- src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs index 4ea0f64b..f1e21dcc 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs @@ -64,7 +64,7 @@ public ObjectSerializer( (Id, Json) item; try { - item = SerializeBase(baseObj, true).NotNull(); + item = SerializeBase(baseObj, true).NotNull(); } catch (Exception ex) when (!ex.IsFatal() && ex is not OperationCanceledException) { From 369ddebf05fe7931f4a8c1630dc0c984bb4aaa83 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 15:09:45 +0000 Subject: [PATCH 6/6] add cache base option --- .../Serialisation/V2/Send/EmptyDictionary.cs | 47 +++++++++++++++++++ .../Serialisation/V2/Send/ObjectSerializer.cs | 7 ++- .../V2/Send/ObjectSerializerFactory.cs | 7 +-- .../Serialisation/V2/Send/SerializeProcess.cs | 9 ++-- .../Program.cs | 2 +- .../DetachedTests.cs | 12 +++-- .../SerializationTests.cs | 2 +- 7 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 src/Speckle.Sdk/Serialisation/V2/Send/EmptyDictionary.cs diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/EmptyDictionary.cs b/src/Speckle.Sdk/Serialisation/V2/Send/EmptyDictionary.cs new file mode 100644 index 00000000..7059231a --- /dev/null +++ b/src/Speckle.Sdk/Serialisation/V2/Send/EmptyDictionary.cs @@ -0,0 +1,47 @@ +using System.Collections; +using System.Diagnostics.CodeAnalysis; + +namespace Speckle.Sdk.Serialisation.V2.Send; + +public class EmptyDictionary : IDictionary +{ + public IEnumerator> GetEnumerator() => throw new NotImplementedException(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public void Add(KeyValuePair item) { } + + public void Clear() => throw new NotImplementedException(); + + public bool Contains(KeyValuePair item) => false; + + public void CopyTo(KeyValuePair[] array, int arrayIndex) => throw new NotImplementedException(); + + public bool Remove(KeyValuePair item) => false; + + public int Count => 0; + public bool IsReadOnly => false; + + public void Add(TKey key, TValue value) { } + + public bool ContainsKey(TKey key) => false; + + public bool Remove(TKey key) => false; + + public bool TryGetValue(TKey key, [UnscopedRef] out TValue value) + { + value = default!; + return false; + } + + public TValue this[TKey key] + { +#pragma warning disable CA1065 + get => throw new NotImplementedException(); +#pragma warning restore CA1065 + set { } + } + + public ICollection Keys { get; } + public ICollection Values { get; } +} diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs index f1e21dcc..80368556 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializer.cs @@ -1,5 +1,4 @@ using System.Collections; -using System.Collections.Concurrent; using System.Drawing; using System.Globalization; using Speckle.DoubleNumerics; @@ -21,7 +20,7 @@ public class ObjectSerializer : IObjectSerializer { private HashSet _parentObjects = new(); private readonly Closures _currentClosures = new(); - private readonly ConcurrentDictionary _baseCache; + private readonly IDictionary _baseCache; private readonly bool _trackDetachedChildren; private readonly IBasePropertyGatherer _propertyGatherer; @@ -42,7 +41,7 @@ public class ObjectSerializer : IObjectSerializer /// public ObjectSerializer( IBasePropertyGatherer propertyGatherer, - ConcurrentDictionary baseCache, + IDictionary baseCache, bool trackDetachedChildren = false, CancellationToken cancellationToken = default ) @@ -70,7 +69,7 @@ public ObjectSerializer( { throw new SpeckleSerializeException($"Failed to extract (pre-serialize) properties from the {baseObj}", ex); } - _baseCache.TryAdd(baseObj, new(item.Item2, _currentClosures)); + _baseCache[baseObj] = new(item.Item2, _currentClosures); yield return (item.Item1, item.Item2); foreach (var chunk in _chunks) { diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializerFactory.cs b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializerFactory.cs index c244bff8..2fa75d05 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializerFactory.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSerializerFactory.cs @@ -1,4 +1,3 @@ -using System.Collections.Concurrent; using Speckle.InterfaceGenerator; using Speckle.Sdk.Models; @@ -7,8 +6,6 @@ namespace Speckle.Sdk.Serialisation.V2.Send; [GenerateAutoInterface] public class ObjectSerializerFactory(IBasePropertyGatherer propertyGatherer) : IObjectSerializerFactory { - public IObjectSerializer Create( - ConcurrentDictionary baseCache, - CancellationToken cancellationToken - ) => new ObjectSerializer(propertyGatherer, baseCache, true, cancellationToken); + public IObjectSerializer Create(IDictionary baseCache, CancellationToken cancellationToken) => + new ObjectSerializer(propertyGatherer, baseCache, true, cancellationToken); } diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs b/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs index 9340a316..9fd6ac59 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs @@ -8,7 +8,7 @@ namespace Speckle.Sdk.Serialisation.V2.Send; -public record SerializeProcessOptions(bool SkipCacheRead, bool SkipCacheWrite, bool SkipServer); +public record SerializeProcessOptions(bool SkipCacheRead, bool SkipCacheWrite, bool SkipServer, bool CacheBases); public readonly record struct SerializeProcessResults( string RootId, @@ -25,8 +25,11 @@ public class SerializeProcess( SerializeProcessOptions? options = null ) : ChannelSaver, ISerializeProcess { + private readonly SerializeProcessOptions _options = options ?? new(false, false, false, true); private readonly ConcurrentDictionary _jsonCache = new(); - private readonly ConcurrentDictionary _baseCache = new(); + + private readonly IDictionary _baseCache = + options?.CacheBases ?? true ? new ConcurrentDictionary() : new EmptyDictionary(); private readonly ConcurrentDictionary _objectReferences = new(); private long _totalFound; @@ -35,8 +38,6 @@ public class SerializeProcess( private long _cached; private long _serialized; - private readonly SerializeProcessOptions _options = options ?? new(false, false, false); - public async Task Serialize(Base root, CancellationToken cancellationToken) { var channelTask = Start(cancellationToken); diff --git a/tests/Speckle.Sdk.Serialization.Testing/Program.cs b/tests/Speckle.Sdk.Serialization.Testing/Program.cs index 5df2d34d..b807f795 100644 --- a/tests/Speckle.Sdk.Serialization.Testing/Program.cs +++ b/tests/Speckle.Sdk.Serialization.Testing/Program.cs @@ -61,7 +61,7 @@ streamId, token, progress, - new SerializeProcessOptions(skipCacheSendCheck, skipCacheSendSave, true) + new SerializeProcessOptions(skipCacheSendCheck, skipCacheSendSave, true, true) ); await process2.Serialize(@base, default).ConfigureAwait(false); Console.WriteLine("Detach"); diff --git a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs index 54316cd2..dabdda56 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs @@ -26,7 +26,9 @@ public void Setup() } [Test(Description = "Checks that all typed properties (including obsolete ones) are returned")] - public async Task CanSerialize_New_Detached() + [TestCase(true)] + [TestCase(false)] + public async Task CanSerialize_New_Detached(bool cacheBases) { var expectedJson = """ { @@ -74,7 +76,7 @@ public async Task CanSerialize_New_Detached() new DummyServerObjectManager(), new BaseChildFinder(new BasePropertyGatherer()), new ObjectSerializerFactory(new BasePropertyGatherer()), - new SerializeProcessOptions(false, false, true) + new SerializeProcessOptions(false, false, true, cacheBases) ); await process2.Serialize(@base, default).ConfigureAwait(false); @@ -191,7 +193,9 @@ public void GetPropertiesExpected_All() } [Test(Description = "Checks that all typed properties (including obsolete ones) are returned")] - public async Task CanSerialize_New_Detached2() + [TestCase(true)] + [TestCase(false)] + public async Task CanSerialize_New_Detached2(bool cacheBases) { var root = """ @@ -266,7 +270,7 @@ public async Task CanSerialize_New_Detached2() new DummyServerObjectManager(), new BaseChildFinder(new BasePropertyGatherer()), new ObjectSerializerFactory(new BasePropertyGatherer()), - new SerializeProcessOptions(false, false, true) + new SerializeProcessOptions(false, false, true, cacheBases) ); var results = await process2.Serialize(@base, default).ConfigureAwait(false); diff --git a/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs b/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs index 90496a57..77532e46 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs @@ -263,7 +263,7 @@ public async Task Roundtrip_Test_New(string fileName, string rootId, int oldCoun new DummySendServerObjectManager(newIdToJson), new BaseChildFinder(new BasePropertyGatherer()), new ObjectSerializerFactory(new BasePropertyGatherer()), - new SerializeProcessOptions(true, true, false) + new SerializeProcessOptions(true, true, false, true) ); var (rootId2, _) = await serializeProcess.Serialize(root, default);