| Crates.io | swmr-epoch |
| lib.rs | swmr-epoch |
| version | 0.3.12 |
| created_at | 2025-11-13 05:57:05.517754+00 |
| updated_at | 2025-11-25 06:11:44.270874+00 |
| description | Single-writer multi-reader epoch-based garbage collection system with minimal locking |
| homepage | https://github.com/ShaoG-R/swmr-epoch |
| repository | https://github.com/ShaoG-R/swmr-epoch |
| max_upload_size | |
| id | 1930463 |
| size | 184,367 |
A high-performance garbage collection system for Rust implementing Single-Writer Multi-Reader (SWMR) epoch-based memory reclamation. Designed for concurrent data structures requiring safe, efficient memory management. Uses minimal locking (a single Mutex for reader tracking) combined with atomic operations for the core epoch mechanism.
EpochPtr<T> wrapper for safe concurrent accessEpochGcDomain
GcHandle
LocalEpoch
Sync (due to Cell) and must be stored per-threadPinGuard for safe accessPinGuard
LocalEpoch it came fromEpochPtr
PinGuarduse swmr_epoch::{EpochGcDomain, EpochPtr};
use std::sync::Arc;
fn main() {
// 1. Create a shared GC domain and get the garbage collector
let (mut gc, domain) = EpochGcDomain::new();
// 2. Create an epoch-protected pointer wrapped in Arc for thread-safe sharing
let data = Arc::new(EpochPtr::new(42i32));
// 3. Reader thread
let domain_clone = domain.clone();
let data_clone = data.clone();
let reader_thread = std::thread::spawn(move || {
let local_epoch = domain_clone.register_reader();
let guard = local_epoch.pin();
let value = data_clone.load(&guard);
println!("Read value: {}", value);
});
// 4. Writer thread: update and collect garbage
data.store(100, &mut gc);
gc.collect();
reader_thread.join().unwrap();
}
Use the builder pattern to customize GC behavior:
use swmr_epoch::EpochGcDomain;
// Configure with builder pattern
let (mut gc, domain) = EpochGcDomain::builder()
.auto_reclaim_threshold(128) // Trigger collection at 128 items
.cleanup_interval(32) // Clean up dead readers every 32 collections
.build();
// Disable automatic collection entirely
let (mut gc, domain) = EpochGcDomain::builder()
.auto_reclaim_threshold(None) // No automatic collection
.build();
gc.collect(); // Manually trigger collection when needed
Configuration Options:
auto_reclaim_threshold(n): Trigger automatic GC when garbage count exceeds n (default: 64). Pass None to disable.cleanup_interval(n): Clean up dead reader slots every n collection cycles (default: 16)PinGuard supports cloning for nested pinning scenarios:
let guard1 = local_epoch.pin();
let guard2 = guard1.clone(); // Nested pin - thread remains pinned
let guard3 = guard1.clone(); // Multiple nested pins are supported
// Thread remains pinned until all guards are dropped
drop(guard3);
drop(guard2);
drop(guard1);
A logical timestamp that advances monotonically. The writer increments the epoch during garbage collection cycles. Readers "pin" themselves to an epoch, declaring that they are actively reading data from that epoch.
When a reader calls pin(), it records the current epoch in its slot. This tells the writer: "I am reading data from this epoch; do not reclaim it yet."
The writer collects retired objects and reclaims those from epochs that are older than the minimum epoch of all active readers.
usize for epochs; overflow is theoretically possible but impracticalcleanup_interval in the builder)# Build the library
cargo build --release
# Run tests
cargo test
# Run benchmarks
cargo bench --bench epoch_comparison
cargo bench --bench concurrent_workload
criterion: Benchmarking framework (dev-dependency)Licensed under either of Apache License, Version 2.0 or MIT license at your option.