ByTech.LsmTree
1.1.0
dotnet add package ByTech.LsmTree --version 1.1.0
NuGet\Install-Package ByTech.LsmTree -Version 1.1.0
<PackageReference Include="ByTech.LsmTree" Version="1.1.0" />
<PackageVersion Include="ByTech.LsmTree" Version="1.1.0" />
<PackageReference Include="ByTech.LsmTree" />
paket add ByTech.LsmTree --version 1.1.0
#r "nuget: ByTech.LsmTree, 1.1.0"
#:package ByTech.LsmTree@1.1.0
#addin nuget:?package=ByTech.LsmTree&version=1.1.0
#tool nuget:?package=ByTech.LsmTree&version=1.1.0
ByTech.LsmTree
A disk-based, persistent Log-Structured Merge-tree for .NET 10 — a write-optimized sorted key-value store with WAL-based durability, leveled compaction, bloom-filter accelerated point lookups, and concurrent reads/writes.
v1.1.0 — see the CHANGELOG. Originally exported one-time from the
ByTech.Bedrockdurable-primitives framework.
Features
- Sorted key-value store — point lookups, range scans, prefix scans, batch mutations
- Write-optimized — in-memory memtable, write-ahead log (WAL), leveled disk segments, background flush and compaction
- WAL durability — write-ahead log with replay-on-open crash recovery
- Configurable durability —
MemoryOnly/WriteBuffered/PeriodicSync/FlushOnCommit/ImmediateSync - Bloom filters — accelerated negative point lookups, configurable false-positive rate
- Block cache — hot-block caching for read-mostly workloads
- Online compaction — single-flight tiered/leveled strategy
- Generic keys and values — bring your own
ICodec<T>; built-inUtf8StringCodec,JsonCodec<T>,BytePassthroughCodec, plus aCodecPipeline<T>for layeringICodecMiddleware(compression, encryption, …)
Installation
dotnet add package ByTech.LsmTree
Quick start
using ByTech.LsmTree;
var options = new LsmTreeOptions
{
BaseDirectory = "./data/mystore",
DurabilityLevel = DurabilityLevel.PeriodicSync,
};
await using var tree = new LsmTree<string, string?>(
name: "mystore",
keyCodec: new Utf8StringCodec(),
valueCodec: new Utf8StringCodec()!,
options: options,
tombstoneValue: null,
isTombstone: v => v is null);
await tree.PutAsync("hello", "world");
var value = await tree.GetAsync("hello"); // "world"
await tree.DeleteAsync("hello");
value = await tree.GetAsync("hello"); // null
Range and prefix scans
// Range scan, inclusive bounds
await foreach (var kv in tree.RangeScanAsync("sku-00100", "sku-00200"))
Console.WriteLine($"{kv.Key} -> {kv.Value}");
// Prefix scan (requires a prefixMatcher at construction)
await using var tree = new LsmTree<string, string?>(
"skus", new Utf8StringCodec(), new Utf8StringCodec()!, options,
tombstoneValue: null, isTombstone: v => v is null,
prefixMatcher: (k, p) => k.StartsWith(p, StringComparison.Ordinal));
await foreach (var kv in tree.PrefixScanAsync("sku-09"))
Console.WriteLine($"{kv.Key} -> {kv.Value}");
Batch mutations
await tree.BatchMutateAsync(
[
new(MutationType.Put, "sku-01", "alpha"),
new(MutationType.Put, "sku-02", "beta"),
new(MutationType.Delete, "sku-03", null),
]);
Maintenance & introspection
await tree.CheckpointAsync(); // flush memtable to disk
await tree.CompactAsync(); // single-flight compaction pass
var integrity = await tree.ValidateIntegrityAsync();
Console.WriteLine($"CRC failures: {integrity.ChecksumFailures}");
var metrics = tree.GetMetrics();
Console.WriteLine($"ops={metrics.TotalOperations} items={metrics.ItemCount} compactions={metrics.CompactionCount}");
Console.WriteLine($"block cache: {metrics.BlockCacheHits} hits / {metrics.BlockCacheMisses} misses");
Console.WriteLine($"bloom: {metrics.BloomFilterNegatives}/{metrics.BloomFilterQueries} probes skipped a segment");
Diagnostics
The tree emits System.Diagnostics.ActivitySource spans for read, write-throttle,
and compaction events. Attach a listener filtered to source ByTech.LsmTree:
using System.Diagnostics;
using ByTech.LsmTree.Diagnostics;
ActivitySource.AddActivityListener(new ActivityListener
{
ShouldListenTo = src => src.Name == LsmTelemetry.SourceName,
Sample = (ref ActivityCreationOptions<ActivityContext> _) => ActivitySamplingResult.AllData,
ActivityStarted = a => Console.WriteLine($"start {a.OperationName}"),
});
Available span names are listed as constants on LsmTelemetry
(ReadGet, ReadRwLockWait, ReadPathWalk, CompactionSwap, ThrottleWait).
Options reference
| Option | Default | Notes |
|---|---|---|
BaseDirectory |
(required) | Root directory for WAL + segments |
DurabilityLevel |
PeriodicSync |
When mutations become crash-safe |
PeriodicSyncInterval |
1 s | How often PeriodicSync fsyncs the WAL in the background |
MemTableSizeThreshold |
64 MB | Bytes before active memtable freezes |
SparseIndexInterval |
128 | Every Nth entry pinned to in-memory sparse index |
Level0CompactionThreshold |
4 | L0 segments before triggering L0→L1 compaction |
SizeMultiplier |
10 | Capacity ratio between adjacent levels |
MaxLevelCount |
5 | Max number of LSM levels |
EnableBloomFilters |
true |
Build bloom filters on disk segments |
BloomFilterFalsePositiveRate |
0.01 | Base FPR (deeper levels use a tighter FPR) |
WriteThrottleLevel0Threshold |
8 | L0 segment count that activates write throttling |
BlockCacheMaxSizeBytes |
64 MB | Block-cache capacity (set to 0 to disable) |
Dependencies
- ByTech.BloomFilter — bloom-filter primitive used by disk-segment readers
System.IO.Hashing— checksums on disk segments and WAL records
License
MIT — see LICENSE.MD.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- ByTech.BloomFilter (>= 1.2.0)
- System.IO.Hashing (>= 10.0.8)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
See CHANGELOG.md. Highlights: all five DurabilityLevel modes now behave as documented; ValidateIntegrityAsync V2-segment false-failure bug fixed; WAL batcher memtable-rotation hang fixed; background flush failures retried with backoff; block-cache and bloom-filter counters exposed via GetMetrics; new PeriodicSyncInterval option.