Skip to content

Commit

Permalink
Merge pull request #20 from Nexus-Mods/set-store
Browse files Browse the repository at this point in the history
Rework once again of the datom store, taking hints from DataHike and leveraging RocksDB even more
  • Loading branch information
halgari authored Mar 27, 2024
2 parents ef12313 + 8dbd76f commit 62e7c0a
Show file tree
Hide file tree
Showing 130 changed files with 2,464 additions and 1,870 deletions.
31 changes: 0 additions & 31 deletions benchmarks/NexusMods.EventSourcing.Benchmarks/AppHost.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using NexusMods.EventSourcing.Abstractions;
using NexusMods.EventSourcing.Storage;
using NexusMods.EventSourcing.Storage.Abstractions;
using NexusMods.EventSourcing.Storage.InMemoryBackend;
using NexusMods.EventSourcing.TestModel;
using NexusMods.Paths;
using Xunit;

namespace NexusMods.EventSourcing.Benchmarks.Benchmarks;

public class ABenchmark : IAsyncLifetime
{
private IHost _host = null!;
protected IConnection Connection = null!;

public IServiceProvider Services => _host.Services;

public async Task InitializeAsync()
{
var builder = Host.CreateDefaultBuilder()
.ConfigureServices(services =>
{
services.AddEventSourcingStorage()
.AddRocksDbBackend()
.AddEventSourcing()
.AddTestModel()
.AddDatomStoreSettings(new DatomStoreSettings
{
Path = FileSystem.Shared.FromUnsanitizedFullPath("benchmarks" + Guid.NewGuid())
});
});

_host = builder.Build();
Connection = await NexusMods.EventSourcing.Connection.Start(Services);
}

public async Task DisposeAsync()
{
var path = Services.GetRequiredService<DatomStoreSettings>().Path;
await _host.StopAsync();
_host.Dispose();

if (path.DirectoryExists())
path.DeleteDirectory();
if (path.FileExists)
path.Delete();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,22 @@
namespace NexusMods.EventSourcing.Benchmarks.Benchmarks;

[MemoryDiagnoser]
public class ReadTests : IAsyncLifetime
public class ReadTests : ABenchmark
{
private IConnection _connection = null!;
private List<EntityId> _entityIdsAscending = null!;
private List<EntityId> _entityIdsDescending = null!;
private List<EntityId> _entityIdsRandom = null!;
private readonly IServiceProvider _services;
private EntityId _readId;
private IDb _db = null!;
private EntityId[] _entityIds = null!;

public ReadTests()
{
_services = AppHost.Create();
}

private const int MaxCount = 10000;

[GlobalSetup]
public async Task Setup()
{
await InitializeAsync();
var tx = _connection.BeginTransaction();
var tx = Connection.BeginTransaction();
var entityIds = new List<EntityId>();
for (var i = 0; i < MaxCount; i++)
for (var i = 0; i < Count; i++)
{
var file = new File(tx)
{
Expand All @@ -48,42 +40,16 @@ public async Task Setup()
}
var result = await tx.Commit();

entityIds = entityIds.Select(e => result[e]).ToList();
_entityIdsAscending = entityIds.OrderBy(id => id.Value).ToList();
_entityIdsDescending = entityIds.OrderByDescending(id => id.Value).ToList();
_entityIds = entityIds.Select(e => result[e]).ToArray();

var idArray = entityIds.ToArray();
Random.Shared.Shuffle(idArray);
_entityIdsRandom = idArray.ToList();
_readId = _entityIds[_entityIds.Length / 2];

_readId = Ids.Take(Count).Skip(Count / 2).First();

_db = _connection.Db;
_db = Connection.Db;
}


[Params(1, 1000, MaxCount)]
public int Count { get; set; } = MaxCount;

public enum SortOrder
{
Ascending,
Descending,
Random
}


//[Params(SortOrder.Ascending, SortOrder.Descending, SortOrder.Random)]
public SortOrder Order { get; set; } = SortOrder.Descending;

public List<EntityId> Ids => Order switch
{
SortOrder.Ascending => _entityIdsAscending,
SortOrder.Descending => _entityIdsDescending,
SortOrder.Random => _entityIdsRandom,
_ => throw new ArgumentOutOfRangeException()
};

[Benchmark]
public ulong ReadFiles()
{
Expand All @@ -92,13 +58,10 @@ public ulong ReadFiles()
return sum;
}

public async Task InitializeAsync()
{
_connection = await AppHost.CreateConnection(_services);
}

public Task DisposeAsync()
[Benchmark]
public long ReadAll()
{
return Task.CompletedTask;
return _db.Get<File>(_entityIds)
.Sum(e => (long)e.Index);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace NexusMods.EventSourcing.Benchmarks.Benchmarks;

public class WriteTests
{
/*
private readonly IConnection _connection;
public WriteTests()
Expand Down Expand Up @@ -51,5 +52,6 @@ public async Task AddFiles()
loaded.Should().NotBeNull("the entity should be in the database");
}
}
*/

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Update="JetBrains.Annotations" Version="2023.3.0" />
</ItemGroup>

<ItemGroup>
Expand Down
14 changes: 10 additions & 4 deletions benchmarks/NexusMods.EventSourcing.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using NexusMods.EventSourcing.Benchmarks.Benchmarks;


#if DEBUG
//#if DEBUG

var benchmark = new ReadTests
{
Expand All @@ -15,14 +15,20 @@

var sw = Stopwatch.StartNew();
await benchmark.Setup();
ulong result = 0;
for (var i = 0; i < 1000000; i++)
long result = 0;
for (var i = 0; i < 10000; i++)
{
result = benchmark.ReadFiles();
result = benchmark.ReadAll();
}
Console.WriteLine("Elapsed: " + sw.Elapsed + " Result: " + result);



/*
#else
BenchmarkRunner.Run<ReadTests>();
#endif
*/

3 changes: 2 additions & 1 deletion benchmarks/OneBillionDatomsTest/OneBillionDatomsTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Update="JetBrains.Annotations" Version="2023.3.0" />
</ItemGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions benchmarks/OneBillionDatomsTest/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
{
s.AddEventSourcingStorage()
.AddEventSourcing()
.AddRocksDbBackend()
.AddTestModel()
.AddSingleton<DatomStoreSettings>(_ => new DatomStoreSettings
{
Expand Down
4 changes: 1 addition & 3 deletions docs/IndexFormat.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ hide:

## Index Format

The index format of the framework follows fairly closely to one found in Datomic, although differences likely exist due it having
a different set of constraints and requirements. The base format of the system is a sorted set of tuples. However each tuple
exists in multiple indexes with a different sorting and conflict resolution strategy for each.
The index format of the framework will look familiar to those who have used Datomic in the past, although there's some very critical

In general data flows through 4 core indexes:

Expand Down
5 changes: 5 additions & 0 deletions src/NexusMods.EventSourcing.Abstractions/AttributeId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@ public readonly partial struct AttributeId
/// </summary>
/// <returns></returns>
public EntityId ToEntityId() => EntityId.From(Value);

/// <summary>
/// Minimum value for an AttributeId.
/// </summary>
public static AttributeId Min => new(ulong.MinValue);
}
55 changes: 0 additions & 55 deletions src/NexusMods.EventSourcing.Abstractions/Datom.cs

This file was deleted.

Loading

0 comments on commit 62e7c0a

Please sign in to comment.