BTreePlus 1.3.1
dotnet add package BTreePlus --version 1.3.1
NuGet\Install-Package BTreePlus -Version 1.3.1
<PackageReference Include="BTreePlus" Version="1.3.1" />
<PackageVersion Include="BTreePlus" Version="1.3.1" />
<PackageReference Include="BTreePlus" />
paket add BTreePlus --version 1.3.1
#r "nuget: BTreePlus, 1.3.1"
#:package BTreePlus@1.3.1
#addin nuget:?package=BTreePlus&version=1.3.1
#tool nuget:?package=BTreePlus&version=1.3.1
BTreePlus
High-performance, file-backed B+Tree engine for .NET — up to 7× faster than SQLite on 1B-row workloads.
2.8–4.0 million inserts/sec on NVMe
Zero dependencies · .NET Standard 2.0 · Embeddable · Deterministic performance
👉 If you’re evaluating BTreePlus for production and want help with design or tuning, email btplus@mmhsys.com.
☕ If this library saves you days of work, consider buying me a coffee: https://buymeacoffee.com/koyllis
Documentation 👉 https://mmhsys.com/BTreePlus.pdf
🚀 Why BTreePlus?
Most storage engines are slow because they are generic.
BTreePlus is purpose-built for high-throughput inserts, sorted key lookups, and range scans — ideal for POS/ERP secondary indexes, logs, scanners, kiosks, IoT, edge devices, analytics, and custom storage engines.
BTreePlus is the core of a database index — available as a lightweight embedded library.
⭐ Fast Benchmark (2025)
Same hardware, NVMe, 32KB pages, .NET 9.0, Linux:
| Rows | SQLite | BTreePlus Pro | Improvement |
|---|---|---|---|
| 4M | 4.53 s | 1.03 s | 4.4× |
| 1B | 2410 s | 346 s | 7× |
PostgreSQL vs BTreePlus (WAL enabled)
Workload: bulk insert of 1,000,000,000 records (14-byte payload each)
Hardware: Intel i9-13900, Samsung 990 PRO NVMe
Durability: WAL enabled for both engines
| Engine | Time |
|---|---|
| PostgreSQL | 6 min 08 s |
| BTreePlus | 5 min 10 s |
➡ BTreePlus is ~16% faster than PostgreSQL under identical WAL/durable settings.
Pro Edition cache required for full performance.
- .NET Standard 2.0 (runs everywhere)
- Zero external dependencies
- Fixed-size pages → deterministic, predictable performance
- Thread-safe
- Fully durable after
Commit() - Designed for high-throughput, low-latency storage workloads
If you know why you need a B+Tree, you already understand what this is.
BTreePlus is ideal for environments where:
- A full database is unnecessary
- In-memory structures are too volatile
- Write throughput and lookup latency are critical
- You need a stable embedded index you control fully
Typical use cases include POS terminals, kiosks, scanners, ERP/POS secondary indexes, industrial controllers, IoT, edge devices, and local-first applications.
🆓 Community Edition vs 🚀 Pro Edition
Community Edition is full CRUD with direct file I/O. Pro Edition adds caching, sharding, and range scans for high-volume workloads.
Community Edition (Free, MIT)
The Community Edition includes the essential functionality for embedded indexes:
| Operation | Description |
|---|---|
Insert() |
Insert or upsert a key/value pair |
Find() |
Lookup a key and read its value |
Bof() |
Move cursor to the first key |
Eof() |
Move cursor to the last key |
Next() |
Move forward in sorted order |
Prev() |
Move backward in sorted order |
Erase() |
Erase a record |
Count |
Number of records |
Performance Model (Community Edition)
- Page cache is disabled
- All operations use direct file I/O
- Ideal for light workloads, read-heavy indexes, embedded controllers, and small datasets
- Fully correct and stable, but not optimized for speed
Pro Edition (Commercial)
The Pro Edition unlocks the full storage engine:
1. High-Performance Page Cache
Enables aggressive caching of internal and leaf pages:
- Hot-node caching
- LRU/clock eviction
- Reduced I/O
- orders-of-magnitude improvement under heavy workloads (up to 8× faster under heavy workloads)
This is the same cache system used in the 1B-row benchmark.
2. Range Scan API
Efficient iteration over a key range:
bt.Range(fromKey, toKey, callback);
Use cases:
- Time-series
- Reporting
- Prefix search
- Pagination
- Secondary indexes
4. Sharding Layer (Horizontal Scaling)
Built-in partitioning for massive datasets:
- Key-range or hash-based sharding
- Transparent cursor merge
- Ideal for 100M → 10B+ key workloads
- Multi-thread friendly
Feature Matrix
| Feature | Community | Pro |
|---|---|---|
| Insert / Find / Next / Prev | ✔ | ✔ |
| Bof / Eof | ✔ | ✔ |
| Direct file I/O (no cache) | ✔ | ✔ |
| High-performance page cache | ✖ | ✔ |
| Erase() deletion | ✔ | ✔ |
| Range scan API | ✖ | ✔ |
| Sharding (horizontal scaling) | ✖ | ✔ |
| Large-scale performance (1B+ rows) | ✖ | ✔ |
| Enterprise support | ✖ | ✔ |
| Check and stats | ✖ | ✔ |
| Bulk Insert | ✖ | ✔ |
For Pro licensing: btplus@mmhsys.com
📏 Page Size Rule
pageSize = number of key/value records per page (not bytes).
Allowed range: 1 to 128
For file-backed trees:
Physical page size = pageSize × 512 bytes
| pageSize | Behavior | Typical Use |
|---|---|---|
| 1–8 | Small pages, small memory footprint | Embedded / resource-constrained systems |
| 16–32 | Balanced depth and performance | General workloads |
| 64-128 | Large pages, minimal tree height | NVMe / SSD, high-throughput workloads |
Default: pageSize: 8 -> 4K
🔧 Quick Start — In-Memory
using mmh;
var bt = BTree.CreateMemory(
keyBytes: 10,
dataBytes: 4,
pageSize: 8,
enableCache: false, // cache disabled in Community Edition
max_recs: 10_000_000,
balance: false);
byte[] k = Encoding.UTF8.GetBytes("1101234567");
byte[] v = BitConverter.GetBytes(1234);
bt.Insert(k, v);
bt.Commit();
bt.Close(); // optional
💾 Quick Start — File Backed
using mmh;
var bt = BTree.CreateOrOpen(
path: "data.btp",
keyBytes: 10,
dataBytes: 4,
pageSize: 16,
enableCache: false, // cache disabled in Community Edition
max_recs: 32_000_000,
balance: true);
byte[] k = Encoding.UTF8.GetBytes("1101234567");
byte[] v = BitConverter.GetBytes(1234);
bt.Insert(k, v);
bt.Commit();
bt.Close();
Reopen later:
var bt = BTree.Open("data.btp", enableCache: false, balance: true);
🔄 Iteration
bt.Bof(); // move to first leaf key
ReadOnlySpan<byte> key;
Span<byte> data = stackalloc byte[4];
while (bt.Next(out key, data))
{
// use 'key' and 'data'
}
🔍 Lookup (Find)
Span<byte> key = stackalloc byte[8];
BitConverter.GetBytes(1234L).CopyTo(key);
Span<byte> value = stackalloc byte[16];
if (bt.Find(key, value))
{
string text = Encoding.ASCII.GetString(value);
Console.WriteLine($"FOUND → {text}");
}
BTree Dictionary (Quick Example)
using mmh;
// Create a BTree with fixed key/value sizes
var tree = BTree.CreateMemory(8, 8);
// Create an Int64 → Int64 dictionary
var dict = BTreeDictionaryFactory.CreateLongToLong(tree);
// Add / overwrite
dict.Add(10L, 100L);
dict[20L] = 200L;
// Read
var v = dict[10L]; // 100
bool ok = dict.ContainsKey(20L);
// Remove
dict.Remove(10L);
// Enumerate
foreach (var kv in dict)
{
Console.WriteLine($"{kv.Key} = {kv.Value}");
}
🔒 Durability & Crash Behavior
- All written data is fully durable after
Commit() - Optional 1-second auto-commit buffer
- Designed to be stable and consistent under normal operation
- Not journaling-based — does not implement WAL or crash-proof atomic commits
- Power loss during an active write may lose the most recent uncommitted operation
- After a successful
Commit(), the tree will reopen in a consistent state
This design keeps the engine extremely fast and lightweight.
💼 Intended Use Cases
- Embedded and edge indexing
- Key-value stores
- POS / ERP secondary indexes
- Local-first and offline-first apps
- High-throughput event pipelines
- Append-only logs and message queues
- Custom storage engines
📄 License
MIT License
🚀 Commercial Edition
For Pro Edition licensing, feature access, or enterprise support:
btplus@mmhsys.com
BTreePlus — When SQLite is too slow, and performance matters.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Memory (>= 4.5.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
- Validated under continuous FileStream workloads with sustained multi-million insert/sec performance on NVMe.
- Stable operation confirmed across Windows, Linux, and ARM edge devices.
- Page-size rule (1–128, ×512 byte physical sizing) finalized for embedded deployments.
- Deferred flush write-back cache proven safe under unexpected power-off scenarios.
- Fully suitable for POS terminals, kiosks, scanners, industrial controllers, and transactional OLTP systems.
- Commercial support, integration services, and embedded device licensing available.
- Support for Dictionary
- Bulk Insert (Bottom-up)