Skip to content

Commit

Permalink
Using Tasks for Deserialization (#143)
Browse files Browse the repository at this point in the history
* Use a stack channel for deserialization

* multi-threaded

* add object dictionary pool

* more pooling

* adjust sqlite transport

* format

* Optimize IsPropNameValid

* object loader first pass

* save test

* add cache pre check

* save better deserialize

* mostly works

* uses tasks but slower at end

* rework to make more sense

* add check to avoid multi-deserialize

* modify max parallelism

* async enqueuing of tasks

* switch to more asyncenumerable

* fmt

* fmt

* cleanup sqlite

* make ServerObjectManager

* revert change

* add ability to skip cache check

* cache json to know what is loaded

* testing

* clean up usage

* clean up and added new op

* Fix exception handling

* fixing progress

* remove codejam

* remove stackchannel

* remove console writeline

* add cache check shortcut for root object

* recevie2 benchmark

---------

Co-authored-by: Jedd Morgan <[email protected]>
  • Loading branch information
adamhathcock and JR-Morgan authored Oct 22, 2024
1 parent 3c783b3 commit cca8828
Show file tree
Hide file tree
Showing 35 changed files with 2,338 additions and 76 deletions.
2 changes: 2 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
<!-- Keep at 7 for side by side -->
<PackageVersion Include="Microsoft.Data.Sqlite" Version="7.0.7" />
<PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="8.0.10" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.2.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="2.2.0" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageVersion Include="MongoDB.Driver" Version="2.19.2" />
<PackageVersion Include="Moq" Version="4.20.70" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.6.0" />
Expand Down
7 changes: 7 additions & 0 deletions Speckle.Sdk.sln
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Sdk.Tests.Performance", "tests\Speckle.Sdk.Tests.Performance\Speckle.Sdk.Tests.Performance.csproj", "{870E3396-E6F7-43AE-B120-E651FA4F46BD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Sdk.Serialization.Testing", "tests\Speckle.Sdk.Serialization.Testing\Speckle.Sdk.Serialization.Testing.csproj", "{FF922B6D-D416-4348-8CB8-0C8B28691070}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -84,6 +86,10 @@ Global
{870E3396-E6F7-43AE-B120-E651FA4F46BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{870E3396-E6F7-43AE-B120-E651FA4F46BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{870E3396-E6F7-43AE-B120-E651FA4F46BD}.Release|Any CPU.Build.0 = Release|Any CPU
{FF922B6D-D416-4348-8CB8-0C8B28691070}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FF922B6D-D416-4348-8CB8-0C8B28691070}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF922B6D-D416-4348-8CB8-0C8B28691070}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FF922B6D-D416-4348-8CB8-0C8B28691070}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{A413E196-3696-4F48-B635-04B5F76BF9C9} = {5CB96C27-FC5B-4A41-86B6-951AF99B8116}
Expand All @@ -95,5 +101,6 @@ Global
{4FB41A6D-D139-4111-8115-E3F9F6BEAF24} = {35047EE7-AD1D-4741-80A7-8F0E874718E9}
{B623BD21-5CAA-43F9-A539-1835276C220E} = {DA2AED52-58F9-471E-8AD8-102FD36129E3}
{870E3396-E6F7-43AE-B120-E651FA4F46BD} = {35047EE7-AD1D-4741-80A7-8F0E874718E9}
{FF922B6D-D416-4348-8CB8-0C8B28691070} = {35047EE7-AD1D-4741-80A7-8F0E874718E9}
EndGlobalSection
EndGlobal
31 changes: 31 additions & 0 deletions src/Speckle.Objects/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,12 @@
"type": "Project",
"dependencies": {
"GraphQL.Client": "[6.0.0, )",
"Microsoft.Bcl.AsyncInterfaces": "[8.0.0, )",
"Microsoft.CSharp": "[4.7.0, )",
"Microsoft.Data.Sqlite": "[7.0.7, )",
"Microsoft.Extensions.DependencyInjection.Abstractions": "[2.2.0, )",
"Microsoft.Extensions.Logging": "[2.2.0, )",
"Microsoft.Extensions.ObjectPool": "[8.0.10, )",
"Polly": "[7.2.3, )",
"Polly.Contrib.WaitAndRetry": "[1.1.1, )",
"Polly.Extensions.Http": "[3.0.0, )",
Expand All @@ -256,6 +258,15 @@
"System.Reactive": "5.0.0"
}
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "CentralTransitive",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
},
"Microsoft.CSharp": {
"type": "CentralTransitive",
"requested": "[4.7.0, )",
Expand Down Expand Up @@ -290,6 +301,12 @@
"Microsoft.Extensions.Options": "2.2.0"
}
},
"Microsoft.Extensions.ObjectPool": {
"type": "CentralTransitive",
"requested": "[8.0.10, )",
"resolved": "8.0.10",
"contentHash": "u7gAG7JgxF8VSJUGPSudAcPxOt+ymJKQCSxNRxiuKV+klCQbHljQR75SilpedCTfhPWDhtUwIJpnDVtspr9nMg=="
},
"Polly": {
"type": "CentralTransitive",
"requested": "[7.2.3, )",
Expand Down Expand Up @@ -494,10 +511,12 @@
"type": "Project",
"dependencies": {
"GraphQL.Client": "[6.0.0, )",
"Microsoft.Bcl.AsyncInterfaces": "[8.0.0, )",
"Microsoft.CSharp": "[4.7.0, )",
"Microsoft.Data.Sqlite": "[7.0.7, )",
"Microsoft.Extensions.DependencyInjection.Abstractions": "[2.2.0, )",
"Microsoft.Extensions.Logging": "[2.2.0, )",
"Microsoft.Extensions.ObjectPool": "[8.0.10, )",
"Polly": "[7.2.3, )",
"Polly.Contrib.WaitAndRetry": "[1.1.1, )",
"Polly.Extensions.Http": "[3.0.0, )",
Expand All @@ -516,6 +535,12 @@
"System.Reactive": "5.0.0"
}
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "CentralTransitive",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw=="
},
"Microsoft.CSharp": {
"type": "CentralTransitive",
"requested": "[4.7.0, )",
Expand Down Expand Up @@ -550,6 +575,12 @@
"Microsoft.Extensions.Options": "2.2.0"
}
},
"Microsoft.Extensions.ObjectPool": {
"type": "CentralTransitive",
"requested": "[8.0.10, )",
"resolved": "8.0.10",
"contentHash": "u7gAG7JgxF8VSJUGPSudAcPxOt+ymJKQCSxNRxiuKV+klCQbHljQR75SilpedCTfhPWDhtUwIJpnDVtspr9nMg=="
},
"Polly": {
"type": "CentralTransitive",
"requested": "[7.2.3, )",
Expand Down
34 changes: 34 additions & 0 deletions src/Speckle.Sdk/Api/Operations/Operations.Receive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,46 @@
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models;
using Speckle.Sdk.Serialisation;
using Speckle.Sdk.Serialisation.V2;
using Speckle.Sdk.Serialisation.V2.Receive;
using Speckle.Sdk.Transports;

namespace Speckle.Sdk.Api;

public partial class Operations
{
public async Task<Base> Receive2(
Uri url,
string streamId,
string objectId,
string? authorizationToken = null,
IProgress<ProgressArgs>? onProgressAction = null,
CancellationToken cancellationToken = default
)
{
using var receiveActivity = activityFactory.Start("Operations.Receive");
metricsFactory.CreateCounter<long>("Receive").Add(1);

receiveActivity?.SetTag("objectId", objectId);

try
{
var sqliteTransport = new SQLiteCacheManager(streamId);
var serverObjects = new ServerObjectManager(speckleHttp, activityFactory, url, authorizationToken);
var o = new ObjectLoader(sqliteTransport, serverObjects, streamId, onProgressAction);
var process = new DeserializeProcess(onProgressAction, o);
var result = await process.Deserialize(objectId, cancellationToken).ConfigureAwait(false);
receiveActivity?.SetStatus(SdkActivityStatusCode.Ok);
return result;
}
catch (Exception ex)
{
receiveActivity?.SetStatus(SdkActivityStatusCode.Error);
receiveActivity?.RecordException(ex);
throw;
}
}

/// <summary>
/// Receives an object (and all its sub-children) from the two provided <see cref="ITransport"/>s.
/// <br/>
Expand Down
2 changes: 2 additions & 0 deletions src/Speckle.Sdk/Api/Operations/Operations.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.Extensions.Logging;
using Speckle.InterfaceGenerator;
using Speckle.Sdk.Helpers;
using Speckle.Sdk.Logging;

namespace Speckle.Sdk.Api;
Expand All @@ -12,6 +13,7 @@ namespace Speckle.Sdk.Api;
[GenerateAutoInterface]
public partial class Operations(
ILogger<Operations> logger,
ISpeckleHttp speckleHttp,
ISdkActivityFactory activityFactory,
ISdkMetricsFactory metricsFactory
) : IOperations;
11 changes: 10 additions & 1 deletion src/Speckle.Sdk/Helpers/SpeckleHttpClientHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,25 @@ CancellationToken cancellationToken

if (policyResult.Outcome == OutcomeType.Successful)
{
activity?.SetStatus(SdkActivityStatusCode.Ok);
return policyResult.Result.NotNull();
}
activity?.SetStatus(SdkActivityStatusCode.Error);
if (policyResult.FinalException != null)
{
activity?.RecordException(policyResult.FinalException);
}

// if the policy failed due to a cancellation, AND it was our cancellation token, then don't wrap the exception, and rethrow an new cancellation
if (policyResult.FinalException is OperationCanceledException)
{
cancellationToken.ThrowIfCancellationRequested();
}

throw new HttpRequestException("Policy Failed", policyResult.FinalException);
throw new HttpRequestException(
"Policy Failed: " + policyResult.FinalHandledResult?.StatusCode ?? "Unknown",
policyResult.FinalException
);
}
}
}
28 changes: 28 additions & 0 deletions src/Speckle.Sdk/Serialisation/SpeckleObjectSerializerPool.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Buffers;
using Microsoft.Extensions.ObjectPool;
using Speckle.Newtonsoft.Json;
using Speckle.Sdk.Common;

Expand All @@ -22,4 +23,31 @@ private class SerializerPool<T>(ArrayPool<T> pool) : IArrayPool<T>

public void Return(T[]? array) => pool.Return(array.NotNull());
}

public ObjectPool<Dictionary<string, object?>> ObjectDictionaries { get; } =
ObjectPool.Create(new ObjectDictionaryPolicy());

private class ObjectDictionaryPolicy : IPooledObjectPolicy<Dictionary<string, object?>>
{
public Dictionary<string, object?> Create() => new(50, StringComparer.OrdinalIgnoreCase);

public bool Return(Dictionary<string, object?> obj)
{
obj.Clear();
return true;
}
}

public ObjectPool<List<string>> ListString { get; } = ObjectPool.Create(new ListStringPolicy());

private class ListStringPolicy : IPooledObjectPolicy<List<string>>
{
public List<string> Create() => new(20);

public bool Return(List<string> obj)
{
obj.Clear();
return true;
}
}
}
Loading

0 comments on commit cca8828

Please sign in to comment.