masstree
A concurrent ordered map for Rust, based on the Masstree algorithm (trie of B+trees).
Status: Alpha
Not production ready. Use for evaluation and feedback only.
| Feature | Status | Notes |
|---|---|---|
| Concurrent get | Works | Lock-free, version-validated |
| Concurrent insert | Works | CAS fast path + locked fallback |
| Split propagation | Works | Leaf and internode splits at any level |
| Concurrency patterns | Tested | Loom tests core patterns (not full tree) |
| Linearizability | Tested | Shuttle tests simplified model |
| Memory safety | Verified | Miri strict provenance |
| Memory reclamation | Partial | Nodes not reclaimed until tree drop |
| Range scans | Missing | Planned for v0.2 |
| Deletion | Missing | Planned for v0.2 |
| Stress testing | Limited | Tested up to 8 threads |
305 tests passing (unit + integration + property + loom + shuttle)
Why This Crate?
Rust lacks a popular concurrent ordered map. The ecosystem:
| Crate | Type | Downloads/month |
|---|---|---|
dashmap |
Unordered HashMap | 10.7 million |
crossbeam-skiplist |
Ordered SkipList | 220k |
masstree |
Ordered B+tree | new |
Skip lists have poor cache locality. B+trees allocate nodes in blocks, improving cache utilization. MassTree brings cache-efficient concurrent ordered maps to Rust.
Quick Start
Concurrent API (recommended)
use MassTree;
use Arc;
use thread;
// MassTree is Send + Sync when V: Send + Sync
let tree = new;
// Spawn concurrent readers and writers
let handles: = .map.collect;
for h in handles
Single-threaded API
use MassTree;
let mut tree: = new;
// insert() requires &mut self - not for concurrent use
let _ = tree.insert?;
let _ = tree.insert?;
// get() returns Arc<V>
assert_eq!;
# Ok::
Note: Keys must be 0-256 bytes. Longer keys will panic.
Performance
Benchmarks vs BTreeMap (single-threaded, cargo bench --bench comparison):
| Operation | MassTree | BTreeMap | Ratio |
|---|---|---|---|
| Get (hit, n=1000) | 21 ns | 54 ns | 2.6x faster |
| Get (miss, n=1000) | 9 ns | 91 ns | 10x faster |
| Insert (populated) | 128 ns | 181 ns | 1.4x faster |
| Mixed 90/10 r/w | 755 ns | 1.87 µs | 2.5x faster |
Where BTreeMap wins:
| Operation | MassTree | BTreeMap | Notes |
|---|---|---|---|
| Insert (empty) | 91 ns | 15 ns | Higher fixed overhead |
| Update existing | 478 ns | 141 ns | Arc swap cost |
Concurrent Scaling
Tested against DashMap (note: different data structure category):
| Threads | MassTree | DashMap | Notes |
|---|---|---|---|
| 2 (reads) | 1.24ms | 1.90ms | MassTree 35% faster |
| 8 (reads) | 5.17ms | 5.49ms | MassTree 6% faster |
| 8 (high contention) | 4.34ms | 2.44ms | DashMap 44% faster |
MassTree scales well for reads. High write contention favors DashMap's sharded design.
Architecture
MassTree implements the Masstree algorithm:
- Trie of B+trees: Keys split into 8-byte chunks, each navigating a B+tree layer
- Optimistic reads: Version validation, retry on concurrent modification
- Fine-grained locking: Per-leaf locks for writes, CAS for simple inserts
- B-link structure: Lock-free traversal during splits
Key: "hello world!"
↓
Layer 0: "hello wo" → B+tree lookup
↓
Layer 1: "rld!\0\0\0\0" → B+tree lookup → Value
Value Storage
Two modes:
// Default: Arc<V> for any value type
let tree: = new;
// Index mode: Copy types (planned optimization)
let index: = new;
Arc<V> enables safe concurrent reads without guard lifetimes. The trade-off is atomic refcount overhead on access.
Known Limitations
- Memory grows monotonically - Split nodes stay allocated until tree drop
- No range scans - Ordered iteration not yet implemented
- No deletion - Keys cannot be removed
- Update overhead -
Arcswap is slower than in-place mutation - Limited stress testing - Verified up to 8 threads
- Key length limit - Keys > 256 bytes will panic (not a Result error)
Roadmap
- v0.1.0 (current): Core concurrent get/insert
- v0.2.0: Range scans, deletion, seize retirement
- v0.3.0: Performance optimization, stress testing
- v1.0.0: Production ready
Contributing
Feedback and bug reports welcome! This is an alpha release—expect rough edges.
# Run tests
# Run benchmarks
# Run with Miri (requires nightly)
References
Disclaimer
This is an independent Rust implementation of the Masstree data structure. It is not affiliated with, endorsed by, or connected to the original authors (Eddie Kohler, Yandong Mao, Robert Morris) or their institutions.
License
MIT