diff --git a/Cargo.toml b/Cargo.toml index 890859b..dacce58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,10 +33,49 @@ doc = true crate-type = ["lib"] [features] -default = [] +default = ["policy-s3-fifo", "policy-lru", "policy-fast-lru", "policy-lru-k", "policy-clock"] metrics = [] concurrency = ["parking_lot"] +# Eviction policy feature flags. Enable only the policies you need for smaller builds. +# Use `default-features = false` and select specific policies, or use `policy-all` for every policy. +policy-all = [ + "policy-fifo", + "policy-lru", + "policy-fast-lru", + "policy-lru-k", + "policy-lfu", + "policy-heap-lfu", + "policy-two-q", + "policy-s3-fifo", + "policy-arc", + "policy-lifo", + "policy-mfu", + "policy-mru", + "policy-random", + "policy-slru", + "policy-clock", + "policy-clock-pro", + "policy-nru", +] +policy-fifo = [] +policy-lru = [] +policy-fast-lru = [] +policy-lru-k = [] +policy-lfu = [] +policy-heap-lfu = [] +policy-two-q = [] +policy-s3-fifo = [] +policy-arc = [] +policy-lifo = [] +policy-mfu = [] +policy-mru = [] +policy-random = [] +policy-slru = [] +policy-clock = [] +policy-clock-pro = [] +policy-nru = [] + [dependencies] parking_lot = { version = "0.12", optional = true } rustc-hash = "2.1" diff --git a/README.md b/README.md index 5d03431..2fd8c6f 100644 --- a/README.md +++ b/README.md @@ -33,11 +33,44 @@ cachekit = { git = "https://github.com/OxidizeLabs/cachekit" } ## Feature Flags +### General + | Feature | Enables | |---------|---------| | `metrics` | Hit/miss metrics and snapshots | | `concurrency` | Concurrent wrappers (requires `parking_lot`) | +### Per-Policy (Eviction Policies) + +Each eviction policy is gated behind a feature flag. Use `default-features = false` and enable only the policies you need for smaller builds. + +| Feature | Policy | Description | +|---------|--------|-------------| +| `policy-fifo` | FIFO | First In, First Out | +| `policy-lru` | LRU | Least Recently Used (Arc-wrapped, concurrent wrapper available) | +| `policy-fast-lru` | Fast LRU | Optimized single-threaded LRU (~7–10× faster than LRU) | +| `policy-lru-k` | LRU-K | Scan-resistant with K-th access | +| `policy-lfu` | LFU | Least Frequently Used (bucket-based) | +| `policy-heap-lfu` | Heap LFU | LFU with heap-based eviction | +| `policy-two-q` | 2Q | Two-Queue | +| `policy-s3-fifo` | S3-FIFO | Scan-resistant three-queue FIFO | +| `policy-arc` | ARC | Adaptive Replacement Cache | +| `policy-lifo` | LIFO | Last In, First Out | +| `policy-mfu` | MFU | Most Frequently Used | +| `policy-mru` | MRU | Most Recently Used | +| `policy-random` | Random | Random eviction | +| `policy-slru` | SLRU | Segmented LRU | +| `policy-clock` | Clock | Second-chance clock | +| `policy-clock-pro` | Clock-PRO | Scan-resistant clock | +| `policy-nru` | NRU | Not Recently Used | + +**Convenience:** `policy-all` enables every policy above. + +```toml +# Minimal build: only LRU and S3-FIFO +cachekit = { version = "0.3", default-features = false, features = ["policy-lru", "policy-s3-fifo"] } +``` + ## Overview CacheKit is a Rust library that provides: @@ -85,7 +118,7 @@ fn main() { ### Available Policies -All policies are available through the unified builder API: +All policies are available through the unified builder API. Enable the corresponding feature flag for each policy (e.g. `policy-lru` for `CachePolicy::Lru`). See [Feature Flags](#per-policy-eviction-policies) above. ```rust use cachekit::builder::{CacheBuilder, CachePolicy}; diff --git a/bench-support/Cargo.toml b/bench-support/Cargo.toml index 30b7dad..3c0a5dc 100644 --- a/bench-support/Cargo.toml +++ b/bench-support/Cargo.toml @@ -9,7 +9,7 @@ name = "render_docs" path = "src/bin/render_docs.rs" [dependencies] -cachekit = { path = ".." } +cachekit = { path = "..", features = ["policy-all"] } criterion = "0.8" rand = { version = "0.9", features = ["small_rng"] } rand_distr = "0.5" diff --git a/docs/getting-started/integration.md b/docs/getting-started/integration.md index 2ff7686..195b2ff 100644 --- a/docs/getting-started/integration.md +++ b/docs/getting-started/integration.md @@ -63,15 +63,18 @@ The `Cache` wrapper requires: ### Policy Selection -| Policy | Use Case | Trade-offs | -|--------|----------|------------| -| `Fifo` | Simple, predictable eviction | No recency/frequency tracking | -| `Lru` | Temporal locality | Vulnerable to scans | -| `LruK { k }` | Scan resistance | Extra memory for history | -| `Lfu { bucket_hint }` | Stable hot spots | Slow to adapt to changes | -| `HeapLfu` | Large caches, frequent evictions | O(log n) eviction | -| `TwoQ { probation_frac }` | Mixed workloads | Two-queue overhead | -| `S3Fifo { small_ratio, ghost_ratio }` | Scan-heavy workloads | Small + ghost queues | +Each policy requires its feature flag (e.g. `policy-lru` for `CachePolicy::Lru`). See [Compatibility and Features](../guides/compatibility-and-features.md). + +| Policy | Feature | Use Case | Trade-offs | +|--------|---------|----------|------------| +| `Fifo` | `policy-fifo` | Simple, predictable eviction | No recency/frequency tracking | +| `Lru` | `policy-lru` | Temporal locality | Vulnerable to scans | +| `FastLru` | `policy-fast-lru` | Maximum single-threaded speed | No Arc wrapping, no concurrent wrapper | +| `LruK { k }` | `policy-lru-k` | Scan resistance | Extra memory for history | +| `Lfu { bucket_hint }` | `policy-lfu` | Stable hot spots | Slow to adapt to changes | +| `HeapLfu` | `policy-heap-lfu` | Large caches, frequent evictions | O(log n) eviction | +| `TwoQ { probation_frac }` | `policy-two-q` | Mixed workloads | Two-queue overhead | +| `S3Fifo { small_ratio, ghost_ratio }` | `policy-s3-fifo` | Scan-heavy workloads | Small + ghost queues | ## Direct Policy Access diff --git a/docs/getting-started/quickstart.md b/docs/getting-started/quickstart.md index ee74da3..6254e98 100644 --- a/docs/getting-started/quickstart.md +++ b/docs/getting-started/quickstart.md @@ -8,9 +8,18 @@ Add CacheKit to your `Cargo.toml`: ```toml [dependencies] -cachekit = "0.2.0-alpha" +cachekit = "0.3" ``` +Each eviction policy is gated behind a feature flag. The default features include `policy-s3-fifo`, `policy-lru`, `policy-fast-lru`, `policy-lru-k`, and `policy-clock`. For minimal builds, use `default-features = false` and enable only the policies you need: + +```toml +[dependencies] +cachekit = { version = "0.3", default-features = false, features = ["policy-lru"] } +``` + +See [Compatibility and Features](../guides/compatibility-and-features.md) for the full list of per-policy feature flags. + ## Build Your First Cache Use `CacheBuilder` with an eviction policy: diff --git a/docs/guides/api-surface.md b/docs/guides/api-surface.md index bb8117d..033cfae 100644 --- a/docs/guides/api-surface.md +++ b/docs/guides/api-surface.md @@ -17,6 +17,10 @@ This page maps the major modules and how they fit together. 3. Use the unified `Cache` API for standard operations. 4. Drop into `policy::*` or `ds::*` for advanced or policy-specific operations. +## Feature Flags + +Policies are gated behind feature flags (e.g. `policy-lru`, `policy-s3-fifo`). Use `default-features = false` and enable only the policies you need. See [Compatibility and Features](compatibility-and-features.md). + ## Where to Start - [Builder overview](../getting-started/integration.md) diff --git a/docs/guides/choosing-a-policy.md b/docs/guides/choosing-a-policy.md index fdedfc1..51f1ee7 100644 --- a/docs/guides/choosing-a-policy.md +++ b/docs/guides/choosing-a-policy.md @@ -3,6 +3,8 @@ This guide summarizes practical trade-offs and mirrors the benchmark-driven guidance in the [latest benchmark guide](../benchmarks/latest/index.md). +**Feature flags:** Each policy is gated behind a feature flag (e.g. `policy-lru`, `policy-s3-fifo`). Enable only the policies you need for smaller builds. See [Compatibility and Features](compatibility-and-features.md). + ## Quick Picks - **General purpose, skewed workloads**: `LRU` or `S3-FIFO` diff --git a/docs/guides/compatibility-and-features.md b/docs/guides/compatibility-and-features.md index 25588a4..070c267 100644 --- a/docs/guides/compatibility-and-features.md +++ b/docs/guides/compatibility-and-features.md @@ -6,9 +6,46 @@ CacheKit targets the Rust MSRV listed in `Cargo.toml` and reflected in the READM ## Feature Flags +### General + - `metrics` — Enables hit/miss metrics and snapshots. - `concurrency` — Enables concurrent wrappers (requires `parking_lot`). +### Eviction Policies (Per-Policy Feature Flags) + +Each eviction policy can be enabled or disabled via its own feature flag. This keeps builds smaller when you only need specific policies. + +| Feature | Policy | Description | +|---------|--------|-------------| +| `policy-fifo` | FIFO | First In, First Out | +| `policy-lru` | LRU | Least Recently Used (Arc-wrapped, `ConcurrentLruCache` available) | +| `policy-fast-lru` | Fast LRU | Optimized single-threaded LRU (~7–10× faster than LRU) | +| `policy-lru-k` | LRU-K | Scan-resistant with K-th access | +| `policy-lfu` | LFU | Least Frequently Used (bucket-based) | +| `policy-heap-lfu` | Heap LFU | LFU with heap-based eviction | +| `policy-two-q` | 2Q | Two-Queue | +| `policy-s3-fifo` | S3-FIFO | Scan-resistant three-queue FIFO | +| `policy-arc` | ARC | Adaptive Replacement Cache | +| `policy-lifo` | LIFO | Last In, First Out | +| `policy-mfu` | MFU | Most Frequently Used | +| `policy-mru` | MRU | Most Recently Used | +| `policy-random` | Random | Random eviction | +| `policy-slru` | SLRU | Segmented LRU | +| `policy-clock` | Clock | Second-chance clock | +| `policy-clock-pro` | Clock-PRO | Scan-resistant clock | +| `policy-nru` | NRU | Not Recently Used | + +**Default features** include `policy-s3-fifo`, `policy-lru`, `policy-fast-lru`, `policy-lru-k`, and `policy-clock`. + +**Convenience feature:** `policy-all` enables every policy above. + +**Minimal builds:** Use `default-features = false` and select only the policies you need: + +```toml +[dependencies] +cachekit = { version = "0.3", default-features = false, features = ["policy-lru", "policy-s3-fifo"] } +``` + ## Optional Dependencies - `parking_lot` — Used for concurrent wrappers behind the `concurrency` feature. diff --git a/docs/policies/2q.md b/docs/policies/2q.md index 9abef74..d3e4c42 100644 --- a/docs/policies/2q.md +++ b/docs/policies/2q.md @@ -1,5 +1,7 @@ # 2Q +**Feature:** `policy-two-q` + ## Goal Reduce scan pollution with a simple two-queue design that approximates "access twice before protection". diff --git a/docs/policies/README.md b/docs/policies/README.md index 5b0f183..7c32c81 100644 --- a/docs/policies/README.md +++ b/docs/policies/README.md @@ -34,24 +34,27 @@ If you can only implement one “general purpose” policy for mixed workloads, ### Implemented Policies (CacheKit) -| Policy | Summary | Doc | -|--------|---------|-----| -| LRU | Strong default for temporal locality | [LRU doc](lru.md) | -| MRU | Evicts most recent (niche: cyclic patterns) | [MRU doc](mru.md) | -| SLRU | Segmented LRU with probation/protected | [SLRU doc](slru.md) | -| LFU | Frequency-driven, stable hot sets | [LFU doc](lfu.md) | -| Heap-LFU | LFU with heap eviction | [Heap-LFU doc](heap-lfu.md) | -| MFU | Evicts highest frequency (niche/baseline) | [MFU doc](mfu.md) | -| LRU-K | Scan-resistant recency | [LRU-K doc](lru-k.md) | -| 2Q | Probation + protected queues | [2Q doc](2q.md) | -| ARC | Adaptive recency/frequency balance | [ARC doc](arc.md) | -| FIFO | Simple insertion-order (oldest first) | [FIFO doc](fifo.md) | -| LIFO | Stack-based (newest first) | [LIFO doc](lifo.md) | -| Clock | Approximate LRU | [Clock doc](clock.md) | -| Clock-PRO | Scan-resistant Clock variant | [Clock-PRO doc](clock-pro.md) | -| NRU | Coarse recency tracking | [NRU doc](nru.md) | -| S3-FIFO | Scan-resistant FIFO | [S3-FIFO doc](s3-fifo.md) | -| Random | Baseline: uniform random eviction | [Random doc](random.md) | +Enable the corresponding feature flag for each policy. See [Compatibility and Features](../guides/compatibility-and-features.md). + +| Policy | Feature | Summary | Doc | +|--------|---------|---------|-----| +| LRU | `policy-lru` | Strong default for temporal locality | [LRU doc](lru.md) | +| Fast LRU | `policy-fast-lru` | Optimized single-threaded LRU | — | +| MRU | `policy-mru` | Evicts most recent (niche: cyclic patterns) | [MRU doc](mru.md) | +| SLRU | `policy-slru` | Segmented LRU with probation/protected | [SLRU doc](slru.md) | +| LFU | `policy-lfu` | Frequency-driven, stable hot sets | [LFU doc](lfu.md) | +| Heap-LFU | `policy-heap-lfu` | LFU with heap eviction | [Heap-LFU doc](heap-lfu.md) | +| MFU | `policy-mfu` | Evicts highest frequency (niche/baseline) | [MFU doc](mfu.md) | +| LRU-K | `policy-lru-k` | Scan-resistant recency | [LRU-K doc](lru-k.md) | +| 2Q | `policy-two-q` | Probation + protected queues | [2Q doc](2q.md) | +| ARC | `policy-arc` | Adaptive recency/frequency balance | [ARC doc](arc.md) | +| FIFO | `policy-fifo` | Simple insertion-order (oldest first) | [FIFO doc](fifo.md) | +| LIFO | `policy-lifo` | Stack-based (newest first) | [LIFO doc](lifo.md) | +| Clock | `policy-clock` | Approximate LRU | [Clock doc](clock.md) | +| Clock-PRO | `policy-clock-pro` | Scan-resistant Clock variant | [Clock-PRO doc](clock-pro.md) | +| NRU | `policy-nru` | Coarse recency tracking | [NRU doc](nru.md) | +| S3-FIFO | `policy-s3-fifo` | Scan-resistant FIFO | [S3-FIFO doc](s3-fifo.md) | +| Random | `policy-random` | Baseline: uniform random eviction | [Random doc](random.md) | ### Roadmap Policies (Planned) diff --git a/docs/policies/arc.md b/docs/policies/arc.md index 5807e12..45b99e9 100644 --- a/docs/policies/arc.md +++ b/docs/policies/arc.md @@ -1,5 +1,7 @@ # ARC (Adaptive Replacement Cache) +**Feature:** `policy-arc` + ## Status **Implemented** in `src/policy/arc.rs` diff --git a/docs/policies/clock-pro.md b/docs/policies/clock-pro.md index ec3f1e5..8a660cf 100644 --- a/docs/policies/clock-pro.md +++ b/docs/policies/clock-pro.md @@ -1,5 +1,7 @@ # CLOCK-Pro +**Feature:** `policy-clock-pro` + ## Goal Improve Clock's scan behavior by tracking hot/cold classification and ghost entries using Clock-style hands. diff --git a/docs/policies/clock.md b/docs/policies/clock.md index 284c6ae..bbb99a8 100644 --- a/docs/policies/clock.md +++ b/docs/policies/clock.md @@ -1,5 +1,7 @@ # Second-Chance / Clock +**Feature:** `policy-clock` + ## Goal Approximate LRU with lower overhead by avoiding strict recency ordering and linked list manipulation. diff --git a/docs/policies/fifo.md b/docs/policies/fifo.md index 27e0eaf..176791f 100644 --- a/docs/policies/fifo.md +++ b/docs/policies/fifo.md @@ -1,5 +1,7 @@ # FIFO (First-In, First-Out) +**Feature:** `policy-fifo` + ## Goal Evict the oldest inserted resident entry when the cache is full. diff --git a/docs/policies/heap-lfu.md b/docs/policies/heap-lfu.md index 0ff21a1..e476235 100644 --- a/docs/policies/heap-lfu.md +++ b/docs/policies/heap-lfu.md @@ -1,5 +1,7 @@ # Heap LFU (Priority Queue LFU) +**Feature:** `policy-heap-lfu` + ## Goal Implement LFU using a heap to choose the minimum frequency victim, trading O(1) for simpler structure and O(log n) operations. diff --git a/docs/policies/lfu.md b/docs/policies/lfu.md index c627720..8c4374f 100644 --- a/docs/policies/lfu.md +++ b/docs/policies/lfu.md @@ -1,5 +1,7 @@ # LFU (Least Frequently Used) +**Feature:** `policy-lfu` + ## Goal Evict the entry with the lowest access frequency; break ties by recency (common) or arbitrarily. diff --git a/docs/policies/lifo.md b/docs/policies/lifo.md index 0893195..9ebeacc 100644 --- a/docs/policies/lifo.md +++ b/docs/policies/lifo.md @@ -1,5 +1,7 @@ # LIFO (Last In, First Out) +**Feature:** `policy-lifo` + ## Goal Evict the most recently inserted entry. diff --git a/docs/policies/lru-k.md b/docs/policies/lru-k.md index eb076e4..685df15 100644 --- a/docs/policies/lru-k.md +++ b/docs/policies/lru-k.md @@ -1,5 +1,7 @@ # LRU-K +**Feature:** `policy-lru-k` + ## Goal Improve scan resistance by evicting based on the K-th most recent access time, rather than last access time. diff --git a/docs/policies/lru.md b/docs/policies/lru.md index f10ba89..0e46ad1 100644 --- a/docs/policies/lru.md +++ b/docs/policies/lru.md @@ -1,5 +1,7 @@ # LRU (Least Recently Used) +**Feature:** `policy-lru` + ## Goal Evict the entry that has not been accessed for the longest time. diff --git a/docs/policies/mfu.md b/docs/policies/mfu.md index 63b43f3..01338bf 100644 --- a/docs/policies/mfu.md +++ b/docs/policies/mfu.md @@ -1,5 +1,7 @@ # MFU (Most Frequently Used) +**Feature:** `policy-mfu` + ## Goal Evict the entry with the highest access frequency, opposite of LFU. diff --git a/docs/policies/mru.md b/docs/policies/mru.md index 8ac6092..596097d 100644 --- a/docs/policies/mru.md +++ b/docs/policies/mru.md @@ -1,5 +1,7 @@ # MRU (Most Recently Used) +**Feature:** `policy-mru` + ## Goal Evict the **most** recently accessed entry. diff --git a/docs/policies/nru.md b/docs/policies/nru.md index d6a907c..f57198f 100644 --- a/docs/policies/nru.md +++ b/docs/policies/nru.md @@ -1,5 +1,7 @@ # NRU (Not Recently Used) +**Feature:** `policy-nru` + ## Goal Cheap eviction using a coarse "recently used" signal rather than a full ordering. Approximate LRU with minimal overhead and simpler implementation than Clock. diff --git a/docs/policies/random.md b/docs/policies/random.md index d27cf7d..4656d59 100644 --- a/docs/policies/random.md +++ b/docs/policies/random.md @@ -1,5 +1,7 @@ # Random Eviction +**Feature:** `policy-random` + ## Goal Evict a uniformly random resident entry when capacity is reached. diff --git a/docs/policies/s3-fifo.md b/docs/policies/s3-fifo.md index 1ea4e04..c63b25a 100644 --- a/docs/policies/s3-fifo.md +++ b/docs/policies/s3-fifo.md @@ -1,5 +1,7 @@ # S3-FIFO +**Feature:** `policy-s3-fifo` + ## Goal Achieve scan resistance with O(1) operations using simple FIFO queues and minimal metadata. diff --git a/docs/policies/slru.md b/docs/policies/slru.md index 2c45782..70965a4 100644 --- a/docs/policies/slru.md +++ b/docs/policies/slru.md @@ -1,5 +1,7 @@ # SLRU (Segmented LRU) +**Feature:** `policy-slru` + ## Goal Reduce scan pollution by separating "probationary" entries from "protected" entries. diff --git a/src/builder.rs b/src/builder.rs index 2eb524b..d5b29aa 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -104,23 +104,41 @@ use std::fmt::Debug; use std::hash::Hash; use std::sync::Arc; +#[cfg(feature = "policy-lfu")] use crate::ds::frequency_buckets::DEFAULT_BUCKET_PREALLOC; +#[cfg(feature = "policy-arc")] use crate::policy::arc::ARCCore; +#[cfg(feature = "policy-clock")] use crate::policy::clock::ClockCache; +#[cfg(feature = "policy-clock-pro")] use crate::policy::clock_pro::ClockProCache; +#[cfg(feature = "policy-fast-lru")] use crate::policy::fast_lru::FastLru; +#[cfg(feature = "policy-fifo")] use crate::policy::fifo::FifoCache; +#[cfg(feature = "policy-heap-lfu")] use crate::policy::heap_lfu::HeapLfuCache; +#[cfg(feature = "policy-lfu")] use crate::policy::lfu::LfuCache; +#[cfg(feature = "policy-lifo")] use crate::policy::lifo::LifoCore; +#[cfg(feature = "policy-lru")] use crate::policy::lru::LruCore; +#[cfg(feature = "policy-lru-k")] use crate::policy::lru_k::LrukCache; +#[cfg(feature = "policy-mfu")] use crate::policy::mfu::MfuCore; +#[cfg(feature = "policy-mru")] use crate::policy::mru::MruCore; +#[cfg(feature = "policy-nru")] use crate::policy::nru::NruCache; +#[cfg(feature = "policy-random")] use crate::policy::random::RandomCore; +#[cfg(feature = "policy-s3-fifo")] use crate::policy::s3_fifo::S3FifoCache; +#[cfg(feature = "policy-slru")] use crate::policy::slru::SlruCore; +#[cfg(feature = "policy-two-q")] use crate::policy::two_q::TwoQCore; use crate::traits::{CoreCache, ReadOnlyCache}; @@ -188,12 +206,14 @@ pub enum CachePolicy { /// /// Evicts the oldest inserted item. Simple and predictable. /// Good for: streaming data, simple caching needs. + #[cfg(feature = "policy-fifo")] Fifo, /// Least Recently Used eviction. /// /// Evicts the item that hasn't been accessed for the longest time. /// Good for: temporal locality, general-purpose caching. + #[cfg(feature = "policy-lru")] Lru, /// Fast LRU eviction (optimized for single-threaded performance). @@ -201,6 +221,7 @@ pub enum CachePolicy { /// Like LRU but stores values directly without Arc wrapping, /// using FxHash for faster operations (~7-10x faster than standard LRU). /// Good for: maximum single-threaded performance, values don't need to outlive eviction. + #[cfg(feature = "policy-fast-lru")] FastLru, /// LRU-K policy with configurable K value. @@ -211,6 +232,7 @@ pub enum CachePolicy { /// - `k: usize` - Number of accesses to track (K=2 is common) /// /// Good for: database buffer pools, scan-heavy workloads. + #[cfg(feature = "policy-lru-k")] LruK { k: usize }, /// Least Frequently Used eviction (bucket-based, O(1)). @@ -221,6 +243,7 @@ pub enum CachePolicy { /// - `bucket_hint: Option` - Pre-allocated frequency buckets (default: 32) /// /// Good for: stable access patterns, reference data. + #[cfg(feature = "policy-lfu")] Lfu { /// Pre-allocated frequency buckets. Most items cluster at low frequencies, /// so the default (32) covers typical workloads. Increase for long-running @@ -234,6 +257,7 @@ pub enum CachePolicy { /// Better for large caches with frequent evictions. /// /// Good for: high-throughput systems, large caches. + #[cfg(feature = "policy-heap-lfu")] HeapLfu, /// Two-Queue policy with configurable probation fraction. @@ -244,6 +268,7 @@ pub enum CachePolicy { /// - `probation_frac: f64` - Fraction of capacity for probation queue (0.0-1.0) /// /// Good for: mixed workloads, scan resistance. + #[cfg(feature = "policy-two-q")] TwoQ { probation_frac: f64 }, /// S3-FIFO (Simple, Scalable, Scan-resistant FIFO) policy. @@ -256,6 +281,7 @@ pub enum CachePolicy { /// - `ghost_ratio: f64` - Fraction of capacity for Ghost list (default 0.9) /// /// Good for: CDN caches, scan-heavy workloads, database buffer pools. + #[cfg(feature = "policy-s3-fifo")] S3Fifo { /// Fraction of capacity for the Small queue (filters one-hit wonders). small_ratio: f64, @@ -270,12 +296,14 @@ pub enum CachePolicy { /// target parameter. Provides excellent performance across diverse workloads. /// /// Good for: unknown or changing workloads, self-tuning caches. + #[cfg(feature = "policy-arc")] Arc, /// Last In, First Out eviction. /// /// Evicts the most recently inserted item (stack-like behavior). /// Good for: Undo buffers, temporary scratch space. + #[cfg(feature = "policy-lifo")] Lifo, /// Most Frequently Used eviction (bucket-based, O(1)). @@ -286,6 +314,7 @@ pub enum CachePolicy { /// - `bucket_hint: Option` - Pre-allocated frequency buckets (default: 32) /// /// Good for: Niche cases where most frequent = least needed next. + #[cfg(feature = "policy-mfu")] Mfu { /// Pre-allocated frequency buckets for high-frequency items. bucket_hint: Option, @@ -295,12 +324,14 @@ pub enum CachePolicy { /// /// Evicts the most recently accessed item (opposite of LRU). /// Good for: Cyclic access patterns, sequential scans. + #[cfg(feature = "policy-mru")] Mru, /// Random eviction. /// /// Evicts a uniformly random item when capacity is reached. /// Good for: Baseline comparisons, truly random workloads. + #[cfg(feature = "policy-random")] Random, /// Segmented LRU with probationary and protected segments. @@ -311,6 +342,7 @@ pub enum CachePolicy { /// - `probationary_frac: f64` - Fraction of capacity for probationary queue (0.0-1.0) /// /// Good for: Database buffer pools, scan-resistant workloads. + #[cfg(feature = "policy-slru")] Slru { /// Fraction of capacity for the probationary segment. probationary_frac: f64, @@ -322,6 +354,7 @@ pub enum CachePolicy { /// Lower overhead than full LRU (no list manipulation on access). /// /// Good for: Low-latency caching, LRU approximation with lower overhead. + #[cfg(feature = "policy-clock")] Clock, /// Clock-PRO eviction. @@ -330,6 +363,7 @@ pub enum CachePolicy { /// Combines Clock mechanics with ghost history tracking. /// /// Good for: Scan-heavy workloads, adaptive caching needs. + #[cfg(feature = "policy-clock-pro")] ClockPro, /// NRU (Not Recently Used) eviction. @@ -338,6 +372,7 @@ pub enum CachePolicy { /// Coarser granularity than Clock, simpler implementation. /// /// Good for: Small-to-medium caches, simple coarse recency tracking. + #[cfg(feature = "policy-nru")] Nru, } @@ -396,22 +431,39 @@ where K: Copy + Eq + Hash + Ord, V: Clone + Debug, { + #[cfg(feature = "policy-fifo")] Fifo(FifoCache), + #[cfg(feature = "policy-lru")] Lru(LruCore), + #[cfg(feature = "policy-fast-lru")] FastLru(FastLru), + #[cfg(feature = "policy-lru-k")] LruK(LrukCache), + #[cfg(feature = "policy-lfu")] Lfu(LfuCache), + #[cfg(feature = "policy-heap-lfu")] HeapLfu(HeapLfuCache), + #[cfg(feature = "policy-two-q")] TwoQ(TwoQCore), + #[cfg(feature = "policy-s3-fifo")] S3Fifo(S3FifoCache), + #[cfg(feature = "policy-arc")] Arc(ARCCore), + #[cfg(feature = "policy-lifo")] Lifo(LifoCore), + #[cfg(feature = "policy-mfu")] Mfu(MfuCore), + #[cfg(feature = "policy-mru")] Mru(MruCore), + #[cfg(feature = "policy-random")] Random(RandomCore), + #[cfg(feature = "policy-slru")] Slru(SlruCore), + #[cfg(feature = "policy-clock")] Clock(ClockCache), + #[cfg(feature = "policy-clock-pro")] ClockPro(ClockProCache), + #[cfg(feature = "policy-nru")] Nru(NruCache), } @@ -440,35 +492,52 @@ where /// ``` pub fn insert(&mut self, key: K, value: V) -> Option { match &mut self.inner { + #[cfg(feature = "policy-fifo")] CacheInner::Fifo(fifo) => CoreCache::insert(fifo, key, value), + #[cfg(feature = "policy-lru")] CacheInner::Lru(lru) => { let arc_value = Arc::new(value); lru.insert(key, arc_value) .map(|arc| Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone())) }, + #[cfg(feature = "policy-fast-lru")] CacheInner::FastLru(fast_lru) => fast_lru.insert(key, value), + #[cfg(feature = "policy-lru-k")] CacheInner::LruK(lruk) => CoreCache::insert(lruk, key, value), + #[cfg(feature = "policy-lfu")] CacheInner::Lfu(lfu) => { let arc_value = Arc::new(value); lfu.insert(key, arc_value) .map(|arc| Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone())) }, + #[cfg(feature = "policy-heap-lfu")] CacheInner::HeapLfu(heap_lfu) => { let arc_value = Arc::new(value); heap_lfu .insert(key, arc_value) .map(|arc| Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone())) }, + #[cfg(feature = "policy-two-q")] CacheInner::TwoQ(twoq) => CoreCache::insert(twoq, key, value), + #[cfg(feature = "policy-s3-fifo")] CacheInner::S3Fifo(s3fifo) => CoreCache::insert(s3fifo, key, value), + #[cfg(feature = "policy-arc")] CacheInner::Arc(arc) => CoreCache::insert(arc, key, value), + #[cfg(feature = "policy-lifo")] CacheInner::Lifo(lifo) => CoreCache::insert(lifo, key, value), + #[cfg(feature = "policy-mfu")] CacheInner::Mfu(mfu) => CoreCache::insert(mfu, key, value), + #[cfg(feature = "policy-mru")] CacheInner::Mru(mru) => CoreCache::insert(mru, key, value), + #[cfg(feature = "policy-random")] CacheInner::Random(random) => CoreCache::insert(random, key, value), + #[cfg(feature = "policy-slru")] CacheInner::Slru(slru) => CoreCache::insert(slru, key, value), + #[cfg(feature = "policy-clock")] CacheInner::Clock(clock) => CoreCache::insert(clock, key, value), + #[cfg(feature = "policy-clock-pro")] CacheInner::ClockPro(clock_pro) => CoreCache::insert(clock_pro, key, value), + #[cfg(feature = "policy-nru")] CacheInner::Nru(nru) => CoreCache::insert(nru, key, value), } } @@ -490,22 +559,39 @@ where /// ``` pub fn get(&mut self, key: &K) -> Option<&V> { match &mut self.inner { + #[cfg(feature = "policy-fifo")] CacheInner::Fifo(fifo) => fifo.get(key), + #[cfg(feature = "policy-lru")] CacheInner::Lru(lru) => lru.get(key).map(|arc| arc.as_ref()), + #[cfg(feature = "policy-fast-lru")] CacheInner::FastLru(fast_lru) => fast_lru.get(key), + #[cfg(feature = "policy-lru-k")] CacheInner::LruK(lruk) => lruk.get(key), + #[cfg(feature = "policy-lfu")] CacheInner::Lfu(lfu) => lfu.get(key).map(|arc| arc.as_ref()), + #[cfg(feature = "policy-heap-lfu")] CacheInner::HeapLfu(heap_lfu) => heap_lfu.get(key).map(|arc| arc.as_ref()), + #[cfg(feature = "policy-two-q")] CacheInner::TwoQ(twoq) => twoq.get(key), + #[cfg(feature = "policy-s3-fifo")] CacheInner::S3Fifo(s3fifo) => s3fifo.get(key), + #[cfg(feature = "policy-arc")] CacheInner::Arc(arc) => arc.get(key), + #[cfg(feature = "policy-lifo")] CacheInner::Lifo(lifo) => lifo.get(key), + #[cfg(feature = "policy-mfu")] CacheInner::Mfu(mfu) => mfu.get(key), + #[cfg(feature = "policy-mru")] CacheInner::Mru(mru) => mru.get(key), + #[cfg(feature = "policy-random")] CacheInner::Random(random) => random.get(key), + #[cfg(feature = "policy-slru")] CacheInner::Slru(slru) => slru.get(key), + #[cfg(feature = "policy-clock")] CacheInner::Clock(clock) => clock.get(key), + #[cfg(feature = "policy-clock-pro")] CacheInner::ClockPro(clock_pro) => clock_pro.get(key), + #[cfg(feature = "policy-nru")] CacheInner::Nru(nru) => nru.get(key), } } @@ -527,22 +613,39 @@ where /// ``` pub fn contains(&self, key: &K) -> bool { match &self.inner { + #[cfg(feature = "policy-fifo")] CacheInner::Fifo(fifo) => fifo.contains(key), + #[cfg(feature = "policy-lru")] CacheInner::Lru(lru) => lru.contains(key), + #[cfg(feature = "policy-fast-lru")] CacheInner::FastLru(fast_lru) => fast_lru.contains(key), + #[cfg(feature = "policy-lru-k")] CacheInner::LruK(lruk) => lruk.contains(key), + #[cfg(feature = "policy-lfu")] CacheInner::Lfu(lfu) => lfu.contains(key), + #[cfg(feature = "policy-heap-lfu")] CacheInner::HeapLfu(heap_lfu) => heap_lfu.contains(key), + #[cfg(feature = "policy-two-q")] CacheInner::TwoQ(twoq) => twoq.contains(key), + #[cfg(feature = "policy-s3-fifo")] CacheInner::S3Fifo(s3fifo) => s3fifo.contains(key), + #[cfg(feature = "policy-arc")] CacheInner::Arc(arc) => arc.contains(key), + #[cfg(feature = "policy-lifo")] CacheInner::Lifo(lifo) => lifo.contains(key), + #[cfg(feature = "policy-mfu")] CacheInner::Mfu(mfu) => mfu.contains(key), + #[cfg(feature = "policy-mru")] CacheInner::Mru(mru) => mru.contains(key), + #[cfg(feature = "policy-random")] CacheInner::Random(random) => random.contains(key), + #[cfg(feature = "policy-slru")] CacheInner::Slru(slru) => slru.contains(key), + #[cfg(feature = "policy-clock")] CacheInner::Clock(clock) => clock.contains(key), + #[cfg(feature = "policy-clock-pro")] CacheInner::ClockPro(clock_pro) => clock_pro.contains(key), + #[cfg(feature = "policy-nru")] CacheInner::Nru(nru) => nru.contains(key), } } @@ -563,22 +666,39 @@ where /// ``` pub fn len(&self) -> usize { match &self.inner { + #[cfg(feature = "policy-fifo")] CacheInner::Fifo(fifo) => >::len(fifo), + #[cfg(feature = "policy-lru")] CacheInner::Lru(lru) => lru.len(), + #[cfg(feature = "policy-fast-lru")] CacheInner::FastLru(fast_lru) => fast_lru.len(), + #[cfg(feature = "policy-lru-k")] CacheInner::LruK(lruk) => >::len(lruk), + #[cfg(feature = "policy-lfu")] CacheInner::Lfu(lfu) => lfu.len(), + #[cfg(feature = "policy-heap-lfu")] CacheInner::HeapLfu(heap_lfu) => heap_lfu.len(), + #[cfg(feature = "policy-two-q")] CacheInner::TwoQ(twoq) => twoq.len(), + #[cfg(feature = "policy-s3-fifo")] CacheInner::S3Fifo(s3fifo) => s3fifo.len(), + #[cfg(feature = "policy-arc")] CacheInner::Arc(arc) => arc.len(), + #[cfg(feature = "policy-lifo")] CacheInner::Lifo(lifo) => >::len(lifo), + #[cfg(feature = "policy-mfu")] CacheInner::Mfu(mfu) => mfu.len(), + #[cfg(feature = "policy-mru")] CacheInner::Mru(mru) => mru.len(), + #[cfg(feature = "policy-random")] CacheInner::Random(random) => >::len(random), + #[cfg(feature = "policy-slru")] CacheInner::Slru(slru) => slru.len(), + #[cfg(feature = "policy-clock")] CacheInner::Clock(clock) => >::len(clock), + #[cfg(feature = "policy-clock-pro")] CacheInner::ClockPro(clock_pro) => >::len(clock_pro), + #[cfg(feature = "policy-nru")] CacheInner::Nru(nru) => >::len(nru), } } @@ -612,22 +732,39 @@ where /// ``` pub fn capacity(&self) -> usize { match &self.inner { + #[cfg(feature = "policy-fifo")] CacheInner::Fifo(fifo) => >::capacity(fifo), + #[cfg(feature = "policy-lru")] CacheInner::Lru(lru) => lru.capacity(), + #[cfg(feature = "policy-fast-lru")] CacheInner::FastLru(fast_lru) => fast_lru.capacity(), + #[cfg(feature = "policy-lru-k")] CacheInner::LruK(lruk) => >::capacity(lruk), + #[cfg(feature = "policy-lfu")] CacheInner::Lfu(lfu) => lfu.capacity(), + #[cfg(feature = "policy-heap-lfu")] CacheInner::HeapLfu(heap_lfu) => heap_lfu.capacity(), + #[cfg(feature = "policy-two-q")] CacheInner::TwoQ(twoq) => twoq.capacity(), + #[cfg(feature = "policy-s3-fifo")] CacheInner::S3Fifo(s3fifo) => s3fifo.capacity(), + #[cfg(feature = "policy-arc")] CacheInner::Arc(arc) => arc.capacity(), + #[cfg(feature = "policy-lifo")] CacheInner::Lifo(lifo) => >::capacity(lifo), + #[cfg(feature = "policy-mfu")] CacheInner::Mfu(mfu) => mfu.capacity(), + #[cfg(feature = "policy-mru")] CacheInner::Mru(mru) => mru.capacity(), + #[cfg(feature = "policy-random")] CacheInner::Random(random) => >::capacity(random), + #[cfg(feature = "policy-slru")] CacheInner::Slru(slru) => slru.capacity(), + #[cfg(feature = "policy-clock")] CacheInner::Clock(clock) => >::capacity(clock), + #[cfg(feature = "policy-clock-pro")] CacheInner::ClockPro(clock_pro) => >::capacity(clock_pro), + #[cfg(feature = "policy-nru")] CacheInner::Nru(nru) => >::capacity(nru), } } @@ -650,22 +787,39 @@ where /// ``` pub fn clear(&mut self) { match &mut self.inner { + #[cfg(feature = "policy-fifo")] CacheInner::Fifo(fifo) => fifo.clear(), + #[cfg(feature = "policy-lru")] CacheInner::Lru(lru) => lru.clear(), + #[cfg(feature = "policy-fast-lru")] CacheInner::FastLru(fast_lru) => fast_lru.clear(), + #[cfg(feature = "policy-lru-k")] CacheInner::LruK(lruk) => lruk.clear(), + #[cfg(feature = "policy-lfu")] CacheInner::Lfu(lfu) => lfu.clear(), + #[cfg(feature = "policy-heap-lfu")] CacheInner::HeapLfu(heap_lfu) => heap_lfu.clear(), + #[cfg(feature = "policy-two-q")] CacheInner::TwoQ(twoq) => twoq.clear(), + #[cfg(feature = "policy-s3-fifo")] CacheInner::S3Fifo(s3fifo) => s3fifo.clear(), + #[cfg(feature = "policy-arc")] CacheInner::Arc(arc) => arc.clear(), + #[cfg(feature = "policy-lifo")] CacheInner::Lifo(lifo) => lifo.clear(), + #[cfg(feature = "policy-mfu")] CacheInner::Mfu(mfu) => mfu.clear(), + #[cfg(feature = "policy-mru")] CacheInner::Mru(mru) => mru.clear(), + #[cfg(feature = "policy-random")] CacheInner::Random(random) => random.clear(), + #[cfg(feature = "policy-slru")] CacheInner::Slru(slru) => slru.clear(), + #[cfg(feature = "policy-clock")] CacheInner::Clock(clock) => clock.clear(), + #[cfg(feature = "policy-clock-pro")] CacheInner::ClockPro(clock_pro) => clock_pro.clear(), + #[cfg(feature = "policy-nru")] CacheInner::Nru(nru) => nru.clear(), } } @@ -730,18 +884,26 @@ impl CacheBuilder { V: Clone + Debug, { let inner = match policy { + #[cfg(feature = "policy-fifo")] CachePolicy::Fifo => CacheInner::Fifo(FifoCache::new(self.capacity)), + #[cfg(feature = "policy-lru")] CachePolicy::Lru => CacheInner::Lru(LruCore::new(self.capacity)), + #[cfg(feature = "policy-fast-lru")] CachePolicy::FastLru => CacheInner::FastLru(FastLru::new(self.capacity)), + #[cfg(feature = "policy-lru-k")] CachePolicy::LruK { k } => CacheInner::LruK(LrukCache::with_k(self.capacity, k)), + #[cfg(feature = "policy-lfu")] CachePolicy::Lfu { bucket_hint } => { let hint = bucket_hint.unwrap_or(DEFAULT_BUCKET_PREALLOC); CacheInner::Lfu(LfuCache::with_bucket_hint(self.capacity, hint)) }, + #[cfg(feature = "policy-heap-lfu")] CachePolicy::HeapLfu => CacheInner::HeapLfu(HeapLfuCache::new(self.capacity)), + #[cfg(feature = "policy-two-q")] CachePolicy::TwoQ { probation_frac } => { CacheInner::TwoQ(TwoQCore::new(self.capacity, probation_frac)) }, + #[cfg(feature = "policy-s3-fifo")] CachePolicy::S3Fifo { small_ratio, ghost_ratio, @@ -750,19 +912,28 @@ impl CacheBuilder { small_ratio, ghost_ratio, )), + #[cfg(feature = "policy-arc")] CachePolicy::Arc => CacheInner::Arc(ARCCore::new(self.capacity)), + #[cfg(feature = "policy-lifo")] CachePolicy::Lifo => CacheInner::Lifo(LifoCore::new(self.capacity)), + #[cfg(feature = "policy-mfu")] CachePolicy::Mfu { bucket_hint: _ } => { // MfuCore uses heap internally, bucket_hint is ignored CacheInner::Mfu(MfuCore::new(self.capacity)) }, + #[cfg(feature = "policy-mru")] CachePolicy::Mru => CacheInner::Mru(MruCore::new(self.capacity)), + #[cfg(feature = "policy-random")] CachePolicy::Random => CacheInner::Random(RandomCore::new(self.capacity)), + #[cfg(feature = "policy-slru")] CachePolicy::Slru { probationary_frac } => { CacheInner::Slru(SlruCore::new(self.capacity, probationary_frac)) }, + #[cfg(feature = "policy-clock")] CachePolicy::Clock => CacheInner::Clock(ClockCache::new(self.capacity)), + #[cfg(feature = "policy-clock-pro")] CachePolicy::ClockPro => CacheInner::ClockPro(ClockProCache::new(self.capacity)), + #[cfg(feature = "policy-nru")] CachePolicy::Nru => CacheInner::Nru(NruCache::new(self.capacity)), }; @@ -774,37 +945,62 @@ impl CacheBuilder { mod tests { use super::*; - #[test] - fn test_all_policies_basic_ops() { - let policies = [ + fn all_enabled_policies() -> Vec { + vec![ + #[cfg(feature = "policy-fifo")] CachePolicy::Fifo, + #[cfg(feature = "policy-lru")] CachePolicy::Lru, + #[cfg(feature = "policy-fast-lru")] CachePolicy::FastLru, + #[cfg(feature = "policy-lru-k")] CachePolicy::LruK { k: 2 }, + #[cfg(feature = "policy-lfu")] CachePolicy::Lfu { bucket_hint: None }, + #[cfg(feature = "policy-heap-lfu")] CachePolicy::HeapLfu, + #[cfg(feature = "policy-two-q")] CachePolicy::TwoQ { probation_frac: 0.25, }, + #[cfg(feature = "policy-s3-fifo")] CachePolicy::S3Fifo { small_ratio: 0.1, ghost_ratio: 0.9, }, + #[cfg(feature = "policy-arc")] CachePolicy::Arc, + #[cfg(feature = "policy-lifo")] CachePolicy::Lifo, + #[cfg(feature = "policy-mfu")] CachePolicy::Mfu { bucket_hint: None }, + #[cfg(feature = "policy-mru")] CachePolicy::Mru, + #[cfg(feature = "policy-random")] CachePolicy::Random, + #[cfg(feature = "policy-slru")] CachePolicy::Slru { probationary_frac: 0.25, }, + #[cfg(feature = "policy-clock")] CachePolicy::Clock, + #[cfg(feature = "policy-clock-pro")] CachePolicy::ClockPro, + #[cfg(feature = "policy-nru")] CachePolicy::Nru, - ]; + ] + } + + #[test] + fn test_all_policies_basic_ops() { + let policies = all_enabled_policies(); + assert!( + !policies.is_empty(), + "At least one policy feature must be enabled" + ); for policy in policies { - let mut cache = CacheBuilder::new(10).build::(policy.clone()); + let mut cache = CacheBuilder::new(10).build::(policy); // Insert assert_eq!(cache.insert(1, "one".to_string()), None); @@ -834,6 +1030,7 @@ mod tests { } #[test] + #[cfg(feature = "policy-lru")] fn test_capacity_enforcement() { let mut cache = CacheBuilder::new(2).build::(CachePolicy::Lru); diff --git a/src/policy/arc.rs b/src/policy/arc.rs index ec31e51..885b118 100644 --- a/src/policy/arc.rs +++ b/src/policy/arc.rs @@ -25,7 +25,7 @@ //! │ ┌─────────────────────────────────────────────────────────────────────┐ │ //! │ │ List Organization │ │ //! │ │ │ │ -//! │ │ T1 (Recency - Recent Once) T2 (Frequency - Repeated) │ │ +//! │ │ T1 (Recency - Recent Once) T2 (Frequency - Repeated) │ │ //! │ │ ┌─────────────────────────┐ ┌─────────────────────────┐ │ │ //! │ │ │ MRU LRU │ │ MRU LRU │ │ │ //! │ │ │ ▼ ▼ │ │ ▼ ▼ │ │ │ @@ -33,7 +33,7 @@ //! │ │ │ new older evict │ │ hot cold evict │ │ │ //! │ │ └─────────────────────────┘ └─────────────────────────┘ │ │ //! │ │ │ │ -//! │ │ B1 (Ghost - evicted from T1) B2 (Ghost - evicted from T2) │ │ +//! │ │ B1 (Ghost - evicted from T1) B2 (Ghost - evicted from T2) │ │ //! │ │ ┌─────────────────────────┐ ┌─────────────────────────┐ │ │ //! │ │ │ Keys only (no values) │ │ Keys only (no values) │ │ │ //! │ │ └─────────────────────────┘ └─────────────────────────┘ │ │ diff --git a/src/policy/mod.rs b/src/policy/mod.rs index 8b4606c..5b16ba0 100644 --- a/src/policy/mod.rs +++ b/src/policy/mod.rs @@ -1,17 +1,34 @@ +#[cfg(feature = "policy-arc")] pub mod arc; +#[cfg(feature = "policy-clock")] pub mod clock; +#[cfg(feature = "policy-clock-pro")] pub mod clock_pro; +#[cfg(feature = "policy-fast-lru")] pub mod fast_lru; +#[cfg(feature = "policy-fifo")] pub mod fifo; +#[cfg(feature = "policy-heap-lfu")] pub mod heap_lfu; +#[cfg(feature = "policy-lfu")] pub mod lfu; +#[cfg(feature = "policy-lifo")] pub mod lifo; +#[cfg(feature = "policy-lru")] pub mod lru; +#[cfg(feature = "policy-lru-k")] pub mod lru_k; +#[cfg(feature = "policy-mfu")] pub mod mfu; +#[cfg(feature = "policy-mru")] pub mod mru; +#[cfg(feature = "policy-nru")] pub mod nru; +#[cfg(feature = "policy-random")] pub mod random; +#[cfg(feature = "policy-s3-fifo")] pub mod s3_fifo; +#[cfg(feature = "policy-slru")] pub mod slru; +#[cfg(feature = "policy-two-q")] pub mod two_q; diff --git a/src/prelude.rs b/src/prelude.rs index 0302de5..5f14a97 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -10,6 +10,7 @@ pub use crate::ds::{ }; #[cfg(feature = "metrics")] pub use crate::metrics::snapshot::CacheMetricsSnapshot; +#[cfg(feature = "policy-fifo")] pub use crate::policy::fifo::FifoCache; pub use crate::traits::{ AsyncCacheFuture, CacheConfig, CacheFactory, CacheTier, CacheTierManager, ConcurrentCache,