From 5c5574c62535db3db51ecd4966bf04dcf8e52a61 Mon Sep 17 00:00:00 2001 From: halgari Date: Tue, 23 Jan 2024 06:30:07 -0700 Subject: [PATCH] More docs --- README.md | 6 ++- docs/Serialization.md | 49 +++++++++++++++++++ mkdocs.yml | 2 + .../RocksDBEventStore.cs | 1 + 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 docs/Serialization.md diff --git a/README.md b/README.md index 4e9bb466..64f82623 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # NexusMods.EventSourcing +EventSourcing and CQRS library for .NET. This library is designed for single process multi threaded applications, and provides +extremely high performance event sourcing and CQRS capabilities. The current datastore is based on RocksDB, but the interface is +designed to be easily swapped out for other storage systems. -This is a template repository for `NexusMods.App.*` repositories. +## Documentation +The full docs can be found [here](https://nexus-mods.github.io/NexusMods.EventSourcing/) ## License diff --git a/docs/Serialization.md b/docs/Serialization.md new file mode 100644 index 00000000..6422650f --- /dev/null +++ b/docs/Serialization.md @@ -0,0 +1,49 @@ +--- +hide: + - toc +--- + +## Serialization + +Events and snapshot data are stored in a custom, extremely high performance binary serialization format. Since events are +readonly, and snapshots are versioned, there is a lot of flexibility in the serialization format. + +The core of the serialization format is the `ISerializer` interface. This interface is indicating if a given serializer +(registered via Dependency Injection) can serialize a given type. If it can, the `TryGetFixedSize` may be called to get +the size of the serialized data. This is used to pre-allocate buffers for serialization. Returning false from this method +means that the serializer does not support fixed size serialization, and dynamic sized serialization will be used. + +Serializers then implement either `IFixedSizeSerializer` or `IVariableSizedSerializer`. The fixed size serializer is used +when the `TryGetFixedSize` method returns true. The dynamic size serializer is used when the `TryGetFixedSize` method returns +false. + +`IEvent` records are seralized via the BinaryEventSerializer. This serializer is designed to be extremely fast, and auto +generates the serialization code for each event type. The format isn't documented, but in general the members are sorted +by name, and the fixed sized members are written first in a large block. This allows for the fixed sized members to be +pre-allocated and serialized in a single block. Since all events are marked with an `EventId` attribute, no type information +is included in the serialized data. + +!!!info + Events are assumed to be immutable, records and are not versioned. This is a solid assumption based on the structure of + the system, and allows for the serialization format to be extremely fast. But this does mean that special consideration + must be taken when designing events. Prefer to use a new event type for each change, rather than assuming that a new + property will be added to an existing event. + +## Composite Types +Currently, composite types are not supported. This includes tuples and classes. This functionality could be added in the future, +but for now it's easy enough to structure records to avoid the need for composite types. + +For example, let's say an event needs to add 3 files, instead of writing an event like this: + +```csharp +public record AddFiles(string name, (string path, string hash)[] files) : IEvent; +``` + +Restructure the event to use several value arrays: + +```csharp +public record AddFiles(string name, string[] paths, string[] hashes) : IEvent; +``` + +Not only does this avoid the need for composite types, but it also likely is slightly faster to serialize and deserialize, +as all the values of like type are packed together diff --git a/mkdocs.yml b/mkdocs.yml index 0c067871..23a35632 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -49,5 +49,7 @@ theme: nav: - Home: index.md - Adapting to Changes: AdaptingToChanges.md + - Serialization: Serialization.md - Secondary Indexes: SecondaryIndexes.md + - Storage Model: StorageModel.md diff --git a/src/NexusMods.EventSourcing.RocksDB/RocksDBEventStore.cs b/src/NexusMods.EventSourcing.RocksDB/RocksDBEventStore.cs index 310e6c5d..c94da971 100644 --- a/src/NexusMods.EventSourcing.RocksDB/RocksDBEventStore.cs +++ b/src/NexusMods.EventSourcing.RocksDB/RocksDBEventStore.cs @@ -51,6 +51,7 @@ public RocksDBEventStore(TSerializer serializer, Settings settings, ISerializati var options = new DbOptions(); options.SetCreateIfMissing(); options.SetCreateMissingColumnFamilies(); + options.SetCompression(Compression.Zstd); _db = RocksDb.Open(options, settings.StorageLocation.ToString(), _families);