Priority LFU Cache
A high-performance, concurrent, in-memory cache with weight-stratified clock eviction policy and policy-based prioritization.
Features
- π High Performance: Sub-microsecond reads with minimal overhead
- π Size-Bounded: Memory limits in bytes, not item count
- βοΈ Policy-Based Eviction: Prioritize important items with 4 eviction tiers
- π― Weight-Stratified Clock: Predictable priority-based eviction with frequency tracking
- π Thread-Safe: Fine-grained sharding for low contention
- π Async-Friendly: Safe to use in async/await contexts
- π¨ Heterogeneous Storage: Store different key/value types without enums
Quick Start
Add to your Cargo.toml:
[]
= "0.1"
Basic usage:
use ;
// Define your key type
;
// Define your value type
// Implement required traits
Async Usage
The cache is safe to use in async contexts:
async
β οΈ Warning: Don't hold Guard across .await points:
# let cache = new;
// β BAD: Guard holds a lock
let guard = cache.get.unwrap;
some_async_fn.await; // Will fail to compile in Send context
// β
GOOD: Extract data, drop guard, then await
let data = ; // Guard dropped here
some_async_fn.await;
Advanced Configuration
Use CacheBuilder for custom settings:
use CacheBuilder;
let cache = new // 512 MB
.shards // More shards = less contention
.build;
Metrics
The cache provides comprehensive performance metrics for monitoring and debugging.
Note: Metrics tracking is behind the metrics feature flag and not enabled by default to minimize overhead. To use metrics, add the feature to your Cargo.toml:
[]
= { = "0.1", = ["metrics"] }
Example usage:
use Cache;
let cache = new;
// Perform some operations
cache.insert;
cache.insert;
cache.get_clone; // hit
cache.get_clone; // miss
// Get metrics snapshot
let metrics = cache.metrics;
// Access counters
println!;
println!;
println!;
println!;
println!;
println!;
// Computed metrics
println!;
println!;
println!;
println!;
// Size and capacity
println!;
println!;
println!;
Available Metrics
| Metric | Type | Description |
|---|---|---|
hits |
u64 |
Number of successful cache lookups |
misses |
u64 |
Number of failed cache lookups (key not found) |
inserts |
u64 |
Number of new entries inserted |
updates |
u64 |
Number of existing entries updated (key already existed) |
evictions |
u64 |
Number of entries evicted due to capacity constraints |
removals |
u64 |
Number of entries explicitly removed via remove() |
current_size_bytes |
usize |
Current total size in bytes |
capacity_bytes |
usize |
Maximum capacity in bytes |
entry_count |
usize |
Current number of entries |
Computed Metrics
The CacheMetrics struct provides helper methods for computed metrics:
hit_rate()- Returns cache hit rate as a ratio (0.0 to 1.0)utilization()- Returns memory utilization as a ratio (0.0 to 1.0)total_accesses()- Returns total cache accesses (hits + misses)total_writes()- Returns total write operations (inserts + updates)
Integration Example
Example of integrating with a monitoring system:
use Duration;
use Arc;
async
Performance Impact
Metrics tracking adds overhead through atomic operations on every cache access:
- 6+ atomic operations per insert (insert/update/eviction tracking)
- 2 atomic operations per get (hit/miss tracking)
- Additional memory for storing 6
AtomicU64counters
If you don't need metrics, omit the metrics feature for maximum performance. The default build (without metrics) eliminates all tracking overhead.
How It Works
Weight-Stratified Clock Algorithm
The cache uses a weight-stratified clock eviction policy that maintains four priority buckets per shard:
- Critical Bucket (CachePolicy::Critical): Metadata, schemas, indexes - last to evict
- Standard Bucket (CachePolicy::Standard): Normal cacheable data - default priority
- Volatile Bucket (CachePolicy::Volatile): Temp data, intermediate results - first to evict
Eviction Process
When space is needed, the cache uses a clock sweep starting from the lowest priority bucket:
- Start with Volatile bucket, advance clock hand
- For each entry encountered:
- If clock_bit is set β clear it and advance
- If clock_bit is clear and frequency = 0 β evict
- If clock_bit is clear and frequency > 0 β decrement frequency and advance
- If bucket is empty, move to next higher priority bucket (Volatile β Standard β Critical)
Each access sets the clock_bit and increments frequency (saturating at 255).
Policy-Based Eviction
This design provides predictable priority-based eviction:
// Eviction order: Volatile β Standard β Critical
// Within each bucket: Clock sweep with LFU tie-breaking
Volatile // Evicted first
Standard // Normal eviction
Critical // Evicted last
Benefits:
- Predictable: Lower priority items always evicted before higher priority
- Fast: Only scans entries in the lowest-priority non-empty bucket
- Simple: No complex hot/cold promotion logic
Architecture
βββββββββββββββββββββββββββββββββββββββββ
β Cache (Send + Sync) β
β βββββββββββββββββββββββββββββββββββ β
β β Global State (atomics) β β
β β - current_size: AtomicUsize β β
β β - entry_count: AtomicUsize β β
β βββββββββββββββββββββββββββββββββββ β
β ββββββββ ββββββββ ββββββββ β
β βShard0β βShard1β ... βShardNβ β
β βRwLockβ βRwLockβ βRwLockβ β
β ββββββββ ββββββββ ββββββββ β
βββββββββββββββββββββββββββββββββββββββββ
Each shard contains:
- Policy Buckets: Four priority buckets (Critical, Standard, Volatile)
- Clock Hands: One per bucket for efficient clock sweep
- Entry Map: HashMap with pre-computed hashes for O(1) lookup
Performance
- Reads: Sub-microsecond with atomic clock_bit and frequency updates
- Writes: Fast eviction by scanning only lowest priority bucket
- Concurrency: Default 64 shards for low contention
- Memory: ~96 bytes overhead per entry (no ghost list needed)
Thread Safety
The cache is Send + Sync and can be shared via Arc:
use Arc;
use Cache;
let cache = new;
let handles: =
.map
.collect;
for handle in handles
Testing
Run tests:
Run benchmarks:
License
This project is licensed under the MIT License.
Contributing
For maintainers releasing new versions, see RELEASE.md for the release process.
Design
For detailed design documentation, see design/spec.md.
References
- CLOCK-Pro: An Effective Improvement of the CLOCK Replacement - Original paper
- quick_cache - Rust Clock-PRO implementation
- Size-based capacity management with byte-level tracking