Skip to content

Commit

Permalink
LMDB implemented, but it doesn't work due to the size bug thing (again)
Browse files Browse the repository at this point in the history
  • Loading branch information
halgari committed Dec 16, 2023
1 parent 4f339e3 commit 8062cb2
Show file tree
Hide file tree
Showing 10 changed files with 247 additions and 22 deletions.
7 changes: 7 additions & 0 deletions NexusMods.EventSourcing.sln
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NexusMods.EventSourcing.Fas
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NexusMods.EventSourcing.RocksDB", "src\NexusMods.EventSourcing.RocksDB\NexusMods.EventSourcing.RocksDB.csproj", "{B8D0772A-FAD1-49AD-A85B-B2B6C5B14420}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NexusMods.EventSourcing.LMDB", "src\NexusMods.EventSourcing.LMDB\NexusMods.EventSourcing.LMDB.csproj", "{4D9C9933-B3F9-4713-B3C7-A7C5E3D47E14}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -53,6 +55,7 @@ Global
{96977D99-BF4B-4952-B594-6E44CCD826B9} = {72AFE85F-8C12-436A-894E-638ED2C92A76}
{AFB69777-0A6A-4C61-A621-32C894673002} = {0377EBE6-F147-4233-86AD-32C821B9567E}
{B8D0772A-FAD1-49AD-A85B-B2B6C5B14420} = {0377EBE6-F147-4233-86AD-32C821B9567E}
{4D9C9933-B3F9-4713-B3C7-A7C5E3D47E14} = {0377EBE6-F147-4233-86AD-32C821B9567E}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A92DED3D-BC67-4E04-9A06-9A1B302B3070}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -83,5 +86,9 @@ Global
{B8D0772A-FAD1-49AD-A85B-B2B6C5B14420}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B8D0772A-FAD1-49AD-A85B-B2B6C5B14420}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8D0772A-FAD1-49AD-A85B-B2B6C5B14420}.Release|Any CPU.Build.0 = Release|Any CPU
{4D9C9933-B3F9-4713-B3C7-A7C5E3D47E14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4D9C9933-B3F9-4713-B3C7-A7C5E3D47E14}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4D9C9933-B3F9-4713-B3C7-A7C5E3D47E14}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4D9C9933-B3F9-4713-B3C7-A7C5E3D47E14}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Linq;
using BenchmarkDotNet.Attributes;
using Microsoft.Extensions.Logging;
using NexusMods.EventSourcing.Abstractions;
using NexusMods.EventSourcing.RocksDB;
using NexusMods.EventSourcing.TestModel;
using NexusMods.EventSourcing.TestModel.Events;
using NexusMods.EventSourcing.TestModel.Model;

namespace NexusMods.EventSourcing.Benchmarks;

[MemoryDiagnoser]
public class EventStoreBenchmarks : ABenchmark
{
private readonly EntityId<Loadout>[] _ids;
private readonly RenameLoadout[] _events;

public EventStoreBenchmarks()
{
_ids = Enumerable.Range(0, 100)
.Select(_ => EntityId<Loadout>.NewId())
.ToArray();

_events = _ids
.Select(id => new RenameLoadout(id, "Loadout"))
.ToArray();

}


[Params(typeof(InMemoryEventStore<EventSerializer>),
//typeof(FasterKVEventStore<EventSerializer>),
typeof(RocksDBEventStore<EventSerializer>))]
public Type EventStoreType { get; set; } = null!;

[GlobalSetup]
public void Setup()
{
MakeStore(EventStoreType);

foreach (var evEvent in _events)
{
EventStore.Add(evEvent);
}
}

[Benchmark]
public void AddEvent()
{
var rndEvent = _events[Random.Shared.Next(0, _events.Length)];
EventStore.Add(rndEvent);
}


[Benchmark]
public void ReadEvents()
{
var ingester = new EventCounter();
EventStore.EventsForEntity(_ids[Random.Shared.Next(0, _ids.Length)].Value, ingester);
}

private struct EventCounter : IEventIngester
{
public int Count { get; private set; }

public void Ingest(IEvent @event)
{
Count++;
}
}


}
2 changes: 1 addition & 1 deletion benchmarks/NexusMods.EventSourcing.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@
readBenchmarks.LoadAllEntities();
Console.WriteLine("LoadAllEntities done");
#else
BenchmarkRunner.Run<EntityContextBenchmarks>();
BenchmarkRunner.Run<EventStoreBenchmarks>();
#endif
99 changes: 99 additions & 0 deletions src/NexusMods.EventSourcing.LMDB/LMDBEventStore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using System;
using System.Buffers.Binary;
using LightningDB;
using NexusMods.EventSourcing.Abstractions;

namespace NexusMods.EventSourcing.LMDB;

public class LMDBEventStore<TSerializer> : IEventStore
where TSerializer : IEventSerializer
{
private readonly TSerializer _serializer;
private readonly Settings _settings;
private readonly LightningEnvironment _env;
private TransactionId _tx;

public LMDBEventStore(TSerializer serializer, Settings settings)
{
_serializer = serializer;
_settings = settings;

_env = new LightningEnvironment(_settings.StorageLocation.ToString());
_env.MapSize = 1024L * 1024L; // 1 TiB
_env.Open();
_tx = TransactionId.From(0);
}

public TransactionId Add<T>(T eventValue) where T : IEvent
{
using var tx = _env.BeginTransaction();

lock (this)
{
_tx = _tx.Next();

{
using var db = tx.OpenDatabase("events");
Span<byte> keySpan = stackalloc byte[8];
BinaryPrimitives.WriteUInt64BigEndian(keySpan, _tx.Value);
var serialized = _serializer.Serialize(eventValue);
tx.Put(db, keySpan, serialized);
}

{
using var db = tx.OpenDatabase("entityIndex");
var ingester = new ModifiedEntitiesIngester();
eventValue.Apply(ingester);
Span<byte> keySpan = stackalloc byte[24];
BinaryPrimitives.WriteUInt64BigEndian(keySpan[16..], _tx.Value);
foreach (var entityId in ingester.Entities)
{
entityId.Value.TryWriteBytes(keySpan);
tx.Put(db, keySpan, keySpan);
}
}
tx.Commit();
return _tx;
}
}

public void EventsForEntity<TIngester>(EntityId entityId, TIngester ingester) where TIngester : IEventIngester
{
using var tx = _env.BeginTransaction(TransactionBeginFlags.ReadOnly);
using var dbEIdx = tx.OpenDatabase("entityIndex");
using var dbEvents = tx.OpenDatabase("events");

using var cursor = tx.CreateCursor(dbEIdx);

Span<byte> startKey = stackalloc byte[24];
entityId.Value.TryWriteBytes(startKey);
Span<byte> endKey = stackalloc byte[24];
entityId.Value.TryWriteBytes(endKey);
BinaryPrimitives.WriteUInt64BigEndian(endKey[16..], ulong.MaxValue);

cursor.SetRange(startKey);

while (true)
{
var (result, key, _) = cursor.GetCurrent();
if (result != MDBResultCode.Success)
{
break;
}

var id = EntityId.From(new Guid(key.AsSpan()[..16]));
if (id != entityId)
{
break;
}

var eventData = tx.Get(dbEvents, key.AsSpan()[16..]);
if (eventData.resultCode != MDBResultCode.Success)
{
break;
}
var evt = _serializer.Deserialize(eventData.value.AsSpan());
ingester.Ingest(evt);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="LightningDB" Version="0.16.0" />
<PackageReference Include="NexusMods.Paths" Version="0.4.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\NexusMods.EventSourcing.Abstractions\NexusMods.EventSourcing.Abstractions.csproj" />
<ProjectReference Include="..\NexusMods.EventSourcing\NexusMods.EventSourcing.csproj" />
</ItemGroup>

</Project>
8 changes: 8 additions & 0 deletions src/NexusMods.EventSourcing.LMDB/Settings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using NexusMods.Paths;

namespace NexusMods.EventSourcing.LMDB;

public class Settings
{
public AbsolutePath StorageLocation { get; set; } = default!;
}
42 changes: 21 additions & 21 deletions src/NexusMods.EventSourcing.RocksDB/RocksDBEventStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,29 @@ public RocksDBEventStore(TSerializer serializer, Settings settings)
public TransactionId Add<T>(T eventValue) where T : IEvent
{
lock (this)
{
_tx = _tx.Next();
{
_tx = _tx.Next();

{
Span<byte> keySpan = stackalloc byte[8];
BinaryPrimitives.WriteUInt64BigEndian(keySpan, _tx.Value);
var serialized = _serializer.Serialize(eventValue);
_db.Put(keySpan, serialized, _eventsColumn);
}
{
Span<byte> keySpan = stackalloc byte[8];
BinaryPrimitives.WriteUInt64BigEndian(keySpan, _tx.Value);
var serialized = _serializer.Serialize(eventValue);
_db.Put(keySpan, serialized, _eventsColumn);
}

{
var ingester = new ModifiedEntitiesIngester();
eventValue.Apply(ingester);
Span<byte> keySpan = stackalloc byte[24];
BinaryPrimitives.WriteUInt64BigEndian(keySpan[16..], _tx.Value);
foreach (var entityId in ingester.Entities)
{
entityId.Value.TryWriteBytes(keySpan);
_db.Put(keySpan, keySpan, _entityIndexColumn);
}
}
return _tx;
}
{
var ingester = new ModifiedEntitiesIngester();
eventValue.Apply(ingester);
Span<byte> keySpan = stackalloc byte[24];
BinaryPrimitives.WriteUInt64BigEndian(keySpan[16..], _tx.Value);
foreach (var entityId in ingester.Entities)
{
entityId.Value.TryWriteBytes(keySpan);
_db.Put(keySpan, keySpan, _entityIndexColumn);
}
}
return _tx;
}
}

public void EventsForEntity<TIngester>(EntityId entityId, TIngester ingester) where TIngester : IEventIngester
Expand Down
5 changes: 5 additions & 0 deletions tests/NexusMods.EventSourcing.Tests/Contexts/TestContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ public IAccumulator GetAccumulator<TOwner, TAttribute>(EntityId ownerId, TAttrib
return loadedValues[attributeDefinition];
}

public void EmptyCaches()
{
throw new NotImplementedException();
}

private readonly struct Ingester(EntityId id) : IEventIngester, IEventContext
{
public readonly Dictionary<IAttribute,IAccumulator> Values = new();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using NexusMods.EventSourcing.LMDB;
using NexusMods.Paths;
using Settings = NexusMods.EventSourcing.RocksDB.Settings;

namespace NexusMods.EventSourcing.Tests.EventStoreTests;

public class LMDBEventStoreTests(EventSerializer serializer) : AEventStoreTest<LMDBEventStore<EventSerializer>>(
new LMDBEventStore<EventSerializer>(serializer, new LMDB.Settings
{
StorageLocation = FileSystem.Shared.GetKnownPath(KnownPath.EntryDirectory)
.Combine("FasterKV.EventStore" + Guid.NewGuid())
}));
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\NexusMods.EventSourcing.Abstractions\NexusMods.EventSourcing.Abstractions.csproj" />
<ProjectReference Include="..\..\src\NexusMods.EventSourcing.FasterKV\NexusMods.EventSourcing.FasterKV.csproj" />
<ProjectReference Include="..\..\src\NexusMods.EventSourcing.LMDB\NexusMods.EventSourcing.LMDB.csproj" />
<ProjectReference Include="..\..\src\NexusMods.EventSourcing.RocksDB\NexusMods.EventSourcing.RocksDB.csproj" />
<ProjectReference Include="..\..\src\NexusMods.EventSourcing\NexusMods.EventSourcing.csproj" />
<ProjectReference Include="..\NexusMods.EventSourcing.TestModel\NexusMods.EventSourcing.TestModel.csproj" />
Expand Down

0 comments on commit 8062cb2

Please sign in to comment.