What is Kovan?
Kovan solves the hardest problem in lock-free programming: when is it safe to free memory?
When multiple threads access shared data without locks, you can't just drop() or free(), while another thread might still be using it.
Kovan tracks this automatically with near-zero overhead on reads.
Why Kovan?
- Near-zero read overhead: One atomic load & one comparison
- Bounded memory: Never grows unbounded like epoch-based schemes
- Simple API:
Atom<T>for safe usage,pin()/load()/retire()for low-level control
Quick Start
[]
= "0.1"
Ecosystem
| Crate | Description |
|---|---|
kovan-channel |
Multi-producer multi-consumer channels using Kovan |
kovan-map |
Concurrent hash maps using kovan memory reclamation |
kovan-mvcc |
Multi-Version Concurrency Control (MVCC) implementation based on the Percolator model using Kovan |
kovan-queue |
High-performance queue primitives and disruptor implementation for Kovan |
kovan-stm |
TL2-style Software Transactional Memory (STM) using Kovan |
Basic MR Usage
The easiest way to use Kovan is through Atom<T>, which handles memory reclamation automatically:
use Atom;
// Create a shared atomic value
let shared = new;
// Read safely
let guard = shared.load;
println!;
drop;
// Update safely (old value is reclaimed automatically)
let old = shared.swap;
For low-level control, use the pin()/load()/retire() API with types that
embed RetiredNode at the beginning:
use ;
use Ordering;
let node = Boxinto_raw;
let shared = new;
// Read
let guard = pin;
let ptr = shared.load;
// ptr is valid for the lifetime of guard
// Swap and retire old value
let new_node = Boxinto_raw;
let old = shared.swap;
if !old.is_null
How It Works
pin()- Enter critical section, get a guardload()- Read pointer with epoch trackingretire()- Schedule memory for safe reclamation
The guard ensures any pointers you load stay valid. When all guards are dropped, retired memory is freed automatically.
Examples
See the examples/ directory for complete implementations.
Performance
Comparison against the major memory reclamation approaches: epoch-based (crossbeam-epoch 0.9.18), hyaline-based (seize 0.5.1), and hazard pointers (haphazard 0.1.8).
- Stable Rust
- Intel Xeon W-2295 (18x Sky Lake)
Pin Overhead
| kovan 0.1.9 | crossbeam 0.9.18 | seize 0.5.1 | haphazard 0.1.8 | |
|---|---|---|---|---|
| pin + drop | 3.8 ns | 14.7 ns | 9.5 ns | 19.1 ns |
Treiber Stack (push+pop, 5k ops/thread)
| Threads | kovan 0.1.9 | crossbeam 0.9.18 | seize 0.5.1 | haphazard 0.1.8 |
|---|---|---|---|---|
| 1 | 579 us | 573 us | 597 us | 956 us |
| 2 | 1.49 ms | 1.60 ms | 1.73 ms | 3.09 ms |
| 4 | 2.69 ms | 3.57 ms | 4.14 ms | 7.03 ms |
| 8 | 9.28 ms | 11.03 ms | 11.35 ms | 19.65 ms |
Read-Heavy (95% load, 5% swap, 10k ops/thread)
| Threads | kovan 0.1.9 | crossbeam 0.9.18 | seize 0.5.1 | haphazard 0.1.8 |
|---|---|---|---|---|
| 2 | 301 us | 440 us | 428 us | 1.16 ms |
| 4 | 446 us | 614 us | 610 us | 4.65 ms |
| 8 | 647 us | 970 us | 1.03 ms | 20.25 ms |
Run your own benchmarks, workloads differ:
# For stable benchmarks
# For nightly benchmarks
Optional Features
# Nightly optimizations (~5% faster)
= { = "0.1", = ["nightly"] }
Supported Platforms
Operating Systems:
- Linux (Natively tested)
- macOS (Natively tested)
- Windows (Natively tested)
Architectures:
Supported list:
- Native Wait-Free (128-bit atomics):
x86_64: Requires compilation target feature+cmpxchg16b.aarch64/arm64: Supported out of the box.s390x: Supported natively.
- Lock-Based Fallback (via
portable-atomic):- Other 64-bit architectures without 128-bit atomic instructions (e.g.,
riscv64,mips64). - On these platforms, 128-bit operations fall back to spinlocks.
- IMPORTANT: Also on these platforms data structures function correctly but drop their wait-free guarantees.
- Other 64-bit architectures without 128-bit atomic instructions (e.g.,
Not supported list:
- Not supported on 32-bit architectures. high and low nibbles for WORD split won't be sufficient. That's why.
License
Licensed under Apache License 2.0.