Skip to content

Commit aab3c0c

Browse files
committed
Add readonly helpers, compaction, and zstd compression
1 parent 1c09025 commit aab3c0c

File tree

9 files changed

+88
-4
lines changed

9 files changed

+88
-4
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
## Changelog
22

3+
### 0.9.99 - 21/1/2025
4+
* Provide a way to open a RocksDB backend in read-only mode
5+
* Default to zstd compression for RocksDB vs the previous snappy compression
6+
* Provide a `FlushAndCompact` method on the connection so that the user can manually trigger a compaction of the database
7+
38
### 0.9.98 - 16/1/2025
49
* Massively improve performance of the `ObserveDatoms` function. It is now ~200x faster than the previous version
510
* Clean up the logging in the inner transacting loop, switch to high performance logging for those few critical messages

src/NexusMods.MnemonicDB.Abstractions/IConnection.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ public interface IConnection
7575
/// of datoms that were excised.
7676
/// </summary>
7777
public Task<ICommitResult> Excise(EntityId[] entityIds);
78+
79+
/// <summary>
80+
/// Flushes the in-memory transaction log to the database, and compacts the database to remove any unused space.
81+
/// </summary>
82+
public Task<ICommitResult> FlushAndCompact();
7883

7984
/// <summary>
8085
/// Update the database's schema with the given attributes.

src/NexusMods.MnemonicDB/Connection.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,14 @@ public async Task<ICommitResult> Excise(EntityId[] entityIds)
244244
return await tx.Commit();
245245
}
246246

247+
/// <inheritdoc />
248+
public async Task<ICommitResult> FlushAndCompact()
249+
{
250+
var tx = new Transaction(this);
251+
tx.Set(new FlushAndCompact());
252+
return await tx.Commit();
253+
}
254+
247255
/// <inheritdoc />
248256
public Task UpdateSchema(params IAttribute[] attribute)
249257
{
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using NexusMods.MnemonicDB.Storage;
2+
3+
namespace NexusMods.MnemonicDB.InternalTxFunctions;
4+
5+
/// <summary>
6+
/// Performs a flush and compact operation on the backend.
7+
/// </summary>
8+
internal class FlushAndCompact : AInternalFn
9+
{
10+
public override void Execute(DatomStore store)
11+
{
12+
store.Backend.FlushAndCompact();
13+
}
14+
}

src/NexusMods.MnemonicDB/Storage/Abstractions/IStoreBackend.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,10 @@ public interface IStoreBackend : IDisposable
3434
/// during calls to GetIterator
3535
/// </summary>
3636
public ISnapshot GetSnapshot();
37-
37+
38+
/// <summary>
39+
/// Flushes all the logs to disk, and performs a compaction, recommended if you want to archive the database
40+
/// and move it somewhere else.
41+
/// </summary>
42+
public void FlushAndCompact();
3843
}

src/NexusMods.MnemonicDB/Storage/InMemoryBackend/Backend.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ public ISnapshot GetSnapshot()
5151
return new Snapshot(_index, AttributeCache);
5252
}
5353

54+
/// <inheritdoc />
55+
public void FlushAndCompact()
56+
{
57+
// No need to do anything
58+
}
59+
5460
/// <inheritdoc />
5561
public void Dispose() { }
5662
}

src/NexusMods.MnemonicDB/Storage/RocksDbBackend/Backend.cs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ public class Backend : IStoreBackend
1414
{
1515
internal RocksDb? Db = null!;
1616
private IntPtr _comparator;
17+
private readonly bool _isReadOnly;
1718

1819
/// <summary>
1920
/// Default constructor
2021
/// </summary>
21-
public Backend()
22+
public Backend(bool readOnly = false)
2223
{
24+
_isReadOnly = readOnly;
2325
AttributeCache = new AttributeCache();
2426
}
2527

@@ -50,10 +52,25 @@ public void Init(AbsolutePath location)
5052
var options = new DbOptions()
5153
.SetCreateIfMissing()
5254
.SetCreateMissingColumnFamilies()
53-
.SetCompression(Compression.Lz4)
55+
.SetCompression(Compression.Zstd)
5456
.SetComparator(_comparator);
5557

56-
Db = RocksDb.Open(options, location.ToString());
58+
Native.Instance.rocksdb_options_set_bottommost_compression(options.Handle, (int)Compression.Zstd);
59+
60+
if (_isReadOnly)
61+
Db = RocksDb.OpenReadOnly(options, location.ToString(), false);
62+
else
63+
Db = RocksDb.Open(options, location.ToString());
64+
}
65+
66+
/// <summary>
67+
/// Flushes all the logs to disk, and performs a compaction, recommended if you want to archive the database
68+
/// and move it somewhere else.
69+
/// </summary>
70+
public void FlushAndCompact()
71+
{
72+
Db?.Flush(new FlushOptions().SetWaitForFlush(true));
73+
Db?.CompactRange([0x00], [0xFF]);
5774
}
5875

5976
/// <inheritdoc />

tests/NexusMods.MnemonicDB.Storage.Tests/NullConnection.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ public Task<ICommitResult> Excise(EntityId[] entityIds)
3737
throw new NotSupportedException();
3838
}
3939

40+
public Task<ICommitResult> FlushAndCompact()
41+
{
42+
throw new NotSupportedException();
43+
}
44+
4045
public Task UpdateSchema(params IAttribute[] attribute)
4146
{
4247
throw new NotSupportedException();

tests/NexusMods.MnemonicDB.Tests/DbTests.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,4 +1233,23 @@ public async Task CanHandleLargeNumbersOfSubscribers()
12331233
sub.Dispose();
12341234
}
12351235
}
1236+
1237+
[Fact]
1238+
public async Task CanFlushAndCompactTheDB()
1239+
{
1240+
var tx = Connection.BeginTransaction();
1241+
1242+
for (int i = 0; i < 1000; i++)
1243+
{
1244+
_ = new Mod.New(tx)
1245+
{
1246+
Name = "Test Mod " + i,
1247+
Source = new Uri("http://test.com"),
1248+
LoadoutId = EntityId.From(0)
1249+
};
1250+
}
1251+
await tx.Commit();
1252+
1253+
await Connection.FlushAndCompact();
1254+
}
12361255
}

0 commit comments

Comments
 (0)