Skip to content

Commit 2503ff9

Browse files
authored
Faster deserialization (#315)
## Description of Changes Leverages clockworklabs/SpacetimeDB#2725 to speed up row deserialization. Also updates DLLs for recent upstream fixes. Changes: - Uses much simpler code when deserializing enums, avoiding the use of reflection - Uses manually monomorphized row deserialization methods, which again avoid the use of reflection when constructing row objects ## API - [ ] This is an API breaking change to the SDK *If the API is breaking, please state below what will break* ## Requires SpacetimeDB PRs clockworklabs/SpacetimeDB#2725 ## Testsuite SpacetimeDB branch name: jgilles/perf/faster-allocation ## Testing *Write instructions for a test that you performed for this PR* - [x] Blackholio - [x] Bitcraft (have done a basic test but no in-depth testing)
1 parent b12cb13 commit 2503ff9

File tree

3 files changed

+38
-6
lines changed

3 files changed

+38
-6
lines changed

src/Table.cs

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
using System.Diagnostics;
44
using System.IO;
55
using System.Linq;
6+
using System.Runtime.CompilerServices;
67
using System.Threading.Tasks;
78
using SpacetimeDB.BSATN;
89
using SpacetimeDB.ClientApi;
910

11+
#nullable enable
1012
namespace SpacetimeDB
1113
{
1214
public abstract class RemoteBase
@@ -50,10 +52,20 @@ public interface IRemoteTableHandle
5052
}
5153

5254

55+
/// <summary>
56+
/// Base class for views of remote tables.
57+
/// </summary>
58+
/// <typeparam name="EventContext"></typeparam>
59+
/// <typeparam name="Row"></typeparam>
5360
public abstract class RemoteTableHandle<EventContext, Row> : RemoteBase, IRemoteTableHandle
5461
where EventContext : class, IEventContext
5562
where Row : class, IStructuralReadWrite, new()
5663
{
64+
// Note: This should really be also parameterized with RowRW: IReadWrite<Row>, but that is a backwards-
65+
// incompatible change. Instead, we call (IReadWrite<Row>)((IStructuralReadWrite)new Row()).GetSerializer().
66+
// Serializer.Read is faster than IStructuralReadWrite.Read<Row> since it's manually monomorphized
67+
// and therefore avoids using reflection when initializing the row object.
68+
5769
public abstract class IndexBase<Column>
5870
where Column : IEquatable<Column>
5971
{
@@ -134,16 +146,35 @@ public RemoteTableHandle(IDbConnection conn) : base(conn) { }
134146
// THE DATA IN THE TABLE.
135147
// The keys of this map are:
136148
// - Primary keys, if we have them.
137-
// - Byte arrays, if we don't.
149+
// - The entire row itself, if we don't.
138150
// But really, the keys are whatever SpacetimeDBClient chooses to give us.
139-
//
140-
// We store the BSATN encodings of objects next to their runtime representation.
141-
// This is memory-inefficient, but allows us to quickly compare objects when seeing if an update is a "real"
142-
// update or just a multiplicity change.
143151
private readonly MultiDictionary<object, IStructuralReadWrite> Entries = new(EqualityComparer<object>.Default, EqualityComparer<Object>.Default);
144152

153+
private static IReadWrite<Row>? _serializer;
154+
155+
/// <summary>
156+
/// Serializer for the rows of this table.
157+
/// </summary>
158+
private static IReadWrite<Row> Serializer
159+
{
160+
get
161+
{
162+
// We can't just initialize this statically, because some BitCraft row types have static
163+
// methods that read SpacetimeDBService.Conn.Db, and these fail if the connection is not
164+
// there on the first load of those types (????).
165+
// This should really be considered an error on their part, but for now we delay initializing any Rows until
166+
// Serializer is actually read, that is, until a row actually needs to be deserialized --
167+
// at which point, the connection should be initialized.
168+
if (_serializer == null)
169+
{
170+
_serializer = (IReadWrite<Row>)new Row().GetSerializer();
171+
}
172+
return _serializer;
173+
}
174+
}
175+
145176
// The function to use for decoding a type value.
146-
IStructuralReadWrite IRemoteTableHandle.DecodeValue(BinaryReader reader) => IStructuralReadWrite.Read<Row>(reader);
177+
IStructuralReadWrite IRemoteTableHandle.DecodeValue(BinaryReader reader) => Serializer.Read(reader);
147178

148179
public delegate void RowEventHandler(EventContext context, Row row);
149180
public event RowEventHandler? OnInsert;
@@ -304,3 +335,4 @@ void IRemoteTableHandle.PostApply(IEventContext context)
304335
}
305336
}
306337
}
338+
#nullable disable

0 commit comments

Comments
 (0)