Skip to content

Commit

Permalink
Merge pull request #108 from Nexus-Mods/better-benchmarks-and-fix-for…
Browse files Browse the repository at this point in the history
…-empty-tx

Fix for empty transactions + Some read benchmarks
  • Loading branch information
halgari authored Oct 24, 2024
2 parents dca14f6 + 14b107e commit 24d83aa
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System.Linq;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using NexusMods.MnemonicDB.Abstractions;
using NexusMods.MnemonicDB.Abstractions.ElementComparers;
using NexusMods.MnemonicDB.Abstractions.IndexSegments;
using NexusMods.MnemonicDB.TestModel;
using NexusMods.Paths;

namespace NexusMods.MnemonicDB.Benchmarks.Benchmarks;

[MemoryDiagnoser]
public class ColdStartBenchmarks : ABenchmark
{
[GlobalSetup]
public async ValueTask GlobalSetup()
{
await InitializeAsync();
await InsertData();
}

private async Task InsertData()
{
foreach (var loadout in Enumerable.Range(0, 10))
{
using var tx = Connection.BeginTransaction();
var loadoutEntity = new Loadout.New(tx)
{
Name = $"Loadout {loadout}"
};
foreach (var mod in Enumerable.Range(0, 1000))
{
var modEntity = new Mod.New(tx)
{
Name = $"Mod {mod}",
Source = new System.Uri($"http://mod{mod}.com"),
LoadoutId = loadoutEntity,
OptionalHash = Hashing.xxHash3.Hash.FromLong(0)
};
foreach (var file in Enumerable.Range(0, 100))
{
_ = new File.New(tx)
{
Path = $"File {file}",
ModId = modEntity,
Size = Size.FromLong(file),
Hash = Hashing.xxHash3.Hash.FromLong(file)
};
}
}
await tx.Commit();
}
}

[IterationSetup]
public void IterationSetup()
{
Connection.Db.ClearIndexCache();
}

[Benchmark]
public Size TotalSizeEAVT()
{
var loadout = Loadout.FindByName(Connection.Db, "Loadout 5").First();
var totalSize = Size.FromLong(0);

foreach (var mod in loadout.Mods)
{
foreach (var file in mod.Files)
{
totalSize += file.Size;
}
}

return totalSize;
}


[Benchmark]
public Size TotalSizeAEVT()
{
var loadoutId = Connection.Db.Datoms(Loadout.Name, "Loadout 5").First();
var modIds = Connection.Db.Datoms(Mod.LoadoutId, loadoutId.E).Select(e => e.E).ToHashSet();
var fileIds = Connection.Db.Datoms(File.ModId).ToLookup(d => ValueTag.Reference.Read<EntityId>(d.ValueSpan), d => d.E);
var fileSizes = Connection.Db.Datoms(File.Size)
.ToDictionary(d => d.E, d => Size.From(ValueTag.UInt64.Read<ulong>(d.ValueSpan)));

var totalSize = Size.FromLong(0);
foreach (var modId in modIds)
{
foreach (var fileId in fileIds[modId])
{
totalSize += fileSizes[fileId];
}
}
return totalSize;
}
}
2 changes: 1 addition & 1 deletion benchmarks/NexusMods.MnemonicDB.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

#else

BenchmarkRunner.Run<ReadThenWriteBenchmarks>(config: DefaultConfig.Instance.WithOption(ConfigOptions.DisableOptimizationsValidator, true));
BenchmarkRunner.Run<ColdStartBenchmarks>();
#endif


5 changes: 5 additions & 0 deletions src/NexusMods.MnemonicDB.Abstractions/IDb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,9 @@ public interface IDb : IEquatable<IDb>
/// </summary>
TReturn AnalyzerData<TAnalyzer, TReturn>()
where TAnalyzer : IAnalyzer<TReturn>;

/// <summary>
/// Clears the internal cache of the database.
/// </summary>
void ClearIndexCache();
}
9 changes: 8 additions & 1 deletion src/NexusMods.MnemonicDB/Caching/IndexSegmentCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -283,5 +283,12 @@ private void UpdateEntry(CacheKey key, IndexSegment segment)
return;
}
}


/// <summary>
/// Clears the cache.
/// </summary>
public void Clear()
{
_root = new CacheRoot(ImmutableDictionary<CacheKey, CacheValue>.Empty);
}
}
5 changes: 5 additions & 0 deletions src/NexusMods.MnemonicDB/Db.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ TReturn IDb.AnalyzerData<TAnalyzer, TReturn>()
throw new KeyNotFoundException($"Analyzer {typeof(TAnalyzer).Name} not found");
}

public void ClearIndexCache()
{
_cache.Clear();
}

public IndexSegment Datoms<TValue>(IWritableAttribute<TValue> attribute, TValue value)
{
return Datoms(SliceDescriptor.Create(attribute, value, AttributeCache));
Expand Down
5 changes: 3 additions & 2 deletions src/NexusMods.MnemonicDB/Storage/DatomStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ public DatomStore(

Backend.Init(settings.Path);

if (bootstrap) Bootstrap();
if (bootstrap)
Bootstrap();
}

/// <inheritdoc />
Expand Down Expand Up @@ -308,7 +309,7 @@ private StoreResult Log(IInternalTxFunctionImpl pendingTransaction)

return new StoreResult
{
AssignedTxId = _thisTx,
AssignedTxId = _asOfTx,
Remaps = _remaps.ToFrozenDictionary(),
Snapshot = CurrentSnapshot
};
Expand Down
8 changes: 8 additions & 0 deletions tests/NexusMods.MnemonicDB.Tests/ComplexModelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,15 @@ public async Task CanRestartStorage(int modCount, int filesPerMod, int extraFile
await extraTx.Commit();

Logger.LogInformation("Restarting storage");
Connection.Db.RecentlyAdded.Should().NotBeEmpty("the last transaction added data");

var lastTxId = Connection.TxId;
await RestartDatomStore();

Connection.TxId.Should().Be(lastTxId, "the transaction id should be the same after a restart");
Connection.Db.BasisTxId.Should().Be(lastTxId, "the basis transaction id should be the same after a restart");

Connection.Db.RecentlyAdded.Should().NotBeEmpty("the restarted database should populate the recently added");
Logger.LogInformation("Storage restarted");


Expand Down

0 comments on commit 24d83aa

Please sign in to comment.