Skip to main content

MetricsCache

Struct MetricsCache 

Source
pub struct MetricsCache<K, V> { /* private fields */ }
Expand description

Counter-wrapped block cache.

Implementations§

Source§

impl<K: Hash + Eq + Clone, V> MetricsCache<K, V>

Source

pub fn with_capacity(capacity: usize) -> Self

Examples found in repository?
examples/sample_app.rs (line 219)
216fn metrics_hit_ratio() {
217    use subms_block_cache::MetricsCache;
218    println!("\n== metrics: hit-ratio observability ==");
219    let mut cache: MetricsCache<u64, String> = MetricsCache::with_capacity(4);
220    for id in 0u64..4 {
221        cache.put(id, read_block(id));
222    }
223    let _ = cache.get(&0);
224    let _ = cache.get(&1);
225    let _ = cache.get(&2);
226    let _ = cache.get(&99);
227    let m = cache.metrics();
228    println!(
229        "  hits {}, misses {}, hit ratio {:.2}",
230        m.hits(),
231        m.misses(),
232        m.hit_ratio()
233    );
234    assert_eq!(m.hits(), 3);
235    assert_eq!(m.misses(), 1);
236    assert!((m.hit_ratio() - 0.75).abs() < 1e-9);
237}
More examples
Hide additional examples
examples/perf_features.rs (line 254)
82fn main() -> io::Result<()> {
83    let canon = SIZES[SIZES.len() - 1];
84
85    let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
86        .join("..")
87        .join(".subms")
88        .join("features")
89        .join("rust.json");
90    let existing = std::fs::read_to_string(&path).unwrap_or_default();
91    let mut manifest = SubMsFeatureManifest::load_str("rust", &existing);
92    // Stamp the box these numbers came from. The bench runs wherever it is
93    // invoked, so an unstamped manifest is indistinguishable from a fleet
94    // capture; the renderer will not publish one it cannot attribute.
95    let (source, instance) = SubMsP99Source::from_env();
96    manifest.set_p99_source(source, instance.as_deref());
97
98    // ---------- base (clock-sweep): the baseline, not a feature ----------
99    // Every feature is classified against this. A variant whose lookup lands
100    // within a whisker of the base is a capability, not a latency change, and
101    // classify_feature says so rather than calling it hot-path by default.
102    // The baseline is a p50, because the sweep values are p50s. Handing
103    // classify_feature a base p99 against p50 sweep points compares two
104    // different statistics: the p50 sits below the p99 almost by construction,
105    // so every feature reads as "within 10% of base" and lands auxiliary.
106    let base_p50 = {
107        use subms_block_cache::BlockCache;
108        let mut c: BlockCache<u32, u64> = BlockCache::with_capacity(canon);
109        for k in 0..canon as u32 {
110            c.put(k, k as u64);
111        }
112        let (p50, _) = get_hit(canon, |key| c.get(&key).is_some());
113        p50
114    };
115
116    // ---------- arc: adaptive replacement, recency + frequency lists ----------
117    #[cfg(feature = "arc")]
118    {
119        use subms_block_cache::ArcCache;
120        let sweep: Vec<(usize, u64)> = SIZES
121            .iter()
122            .map(|&n| {
123                let mut c: ArcCache<u32, u64> = ArcCache::with_capacity(n);
124                for k in 0..n as u32 {
125                    c.put(k, k as u64);
126                }
127                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
128                (n, p50)
129            })
130            .collect();
131        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
132
133        let mut c: ArcCache<u32, u64> = ArcCache::with_capacity(canon);
134        for k in 0..canon as u32 {
135            c.put(k, k as u64);
136        }
137        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
138        let (_, put99) = put_evicting(canon, |key| {
139            c.put(key, key as u64);
140        });
141        let mut p99 = BTreeMap::new();
142        p99.insert("get_hit".to_string(), get99);
143        p99.insert("put".to_string(), put99);
144        manifest.set_feature("arc", cat, &p99, &reason);
145    }
146
147    // ---------- tinylfu: frequency-sketch admission ----------
148    #[cfg(feature = "tinylfu")]
149    {
150        use subms_block_cache::TinyLfuCache;
151        let sweep: Vec<(usize, u64)> = SIZES
152            .iter()
153            .map(|&n| {
154                let mut c: TinyLfuCache<u32, u64> = TinyLfuCache::with_capacity(n);
155                for k in 0..n as u32 {
156                    c.put(k, k as u64);
157                }
158                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
159                (n, p50)
160            })
161            .collect();
162        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
163
164        let mut c: TinyLfuCache<u32, u64> = TinyLfuCache::with_capacity(canon);
165        for k in 0..canon as u32 {
166            c.put(k, k as u64);
167        }
168        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
169        let (_, put99) = put_evicting(canon, |key| {
170            c.put(key, key as u64);
171        });
172        let mut p99 = BTreeMap::new();
173        p99.insert("get_hit".to_string(), get99);
174        p99.insert("put".to_string(), put99);
175        manifest.set_feature("tinylfu", cat, &p99, &reason);
176    }
177
178    // ---------- weighted: a byte budget rather than a slot count ----------
179    #[cfg(feature = "weighted")]
180    {
181        use subms_block_cache::WeightedCache;
182        // 1 byte per entry so capacity_bytes == slot capacity; eviction behaves
183        // like the base cache, which isolates the weight bookkeeping itself.
184        let sweep: Vec<(usize, u64)> = SIZES
185            .iter()
186            .map(|&n| {
187                let mut c: WeightedCache<u32, u64> =
188                    WeightedCache::with_capacity_bytes(n, |_v: &u64| 1);
189                for k in 0..n as u32 {
190                    c.put(k, k as u64);
191                }
192                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
193                (n, p50)
194            })
195            .collect();
196        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
197
198        let mut c: WeightedCache<u32, u64> =
199            WeightedCache::with_capacity_bytes(canon, |_v: &u64| 1);
200        for k in 0..canon as u32 {
201            c.put(k, k as u64);
202        }
203        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
204        let (_, put99) = put_evicting(canon, |key| {
205            let _ = c.put(key, key as u64);
206        });
207        let mut p99 = BTreeMap::new();
208        p99.insert("get_hit".to_string(), get99);
209        p99.insert("put".to_string(), put99);
210        manifest.set_feature("weighted", cat, &p99, &reason);
211    }
212
213    // ---------- concurrent-shards: measured single-threaded ----------
214    // Uncontended on purpose. This isolates the sharding INDIRECTION from the
215    // contention it exists to relieve; a multi-threaded number here would say
216    // more about the thread count than about the feature.
217    #[cfg(feature = "concurrent-shards")]
218    {
219        use subms_block_cache::ShardedCache;
220        let sweep: Vec<(usize, u64)> = SIZES
221            .iter()
222            .map(|&n| {
223                let c: ShardedCache<u32, u64> = ShardedCache::with_capacity(n, 16);
224                for k in 0..n as u32 {
225                    c.put(k, k as u64);
226                }
227                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
228                (n, p50)
229            })
230            .collect();
231        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
232
233        let c: ShardedCache<u32, u64> = ShardedCache::with_capacity(canon, 16);
234        for k in 0..canon as u32 {
235            c.put(k, k as u64);
236        }
237        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
238        let (_, put99) = put_evicting(canon, |key| {
239            c.put(key, key as u64);
240        });
241        let mut p99 = BTreeMap::new();
242        p99.insert("get_hit".to_string(), get99);
243        p99.insert("put".to_string(), put99);
244        manifest.set_feature("concurrent-shards", cat, &p99, &reason);
245    }
246
247    // ---------- metrics: hit/miss counters on the lookup path ----------
248    #[cfg(feature = "metrics")]
249    {
250        use subms_block_cache::MetricsCache;
251        let sweep: Vec<(usize, u64)> = SIZES
252            .iter()
253            .map(|&n| {
254                let mut c: MetricsCache<u32, u64> = MetricsCache::with_capacity(n);
255                for k in 0..n as u32 {
256                    c.put(k, k as u64);
257                }
258                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
259                (n, p50)
260            })
261            .collect();
262        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
263
264        let mut c: MetricsCache<u32, u64> = MetricsCache::with_capacity(canon);
265        for k in 0..canon as u32 {
266            c.put(k, k as u64);
267        }
268        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
269        let (_, put99) = put_evicting(canon, |key| {
270            c.put(key, key as u64);
271        });
272        let mut p99 = BTreeMap::new();
273        p99.insert("get_hit".to_string(), get99);
274        p99.insert("put".to_string(), put99);
275        manifest.set_feature("metrics", cat, &p99, &reason);
276    }
277
278    std::fs::create_dir_all(path.parent().unwrap())?;
279    std::fs::write(&path, manifest.to_json())?;
280    io::stdout().write_all(manifest.to_json().as_bytes())?;
281    Ok(())
282}
Source

pub fn capacity(&self) -> usize

Source

pub fn len(&self) -> usize

Source

pub fn is_empty(&self) -> bool

Source

pub fn metrics(&self) -> &CacheMetrics

Examples found in repository?
examples/sample_app.rs (line 227)
216fn metrics_hit_ratio() {
217    use subms_block_cache::MetricsCache;
218    println!("\n== metrics: hit-ratio observability ==");
219    let mut cache: MetricsCache<u64, String> = MetricsCache::with_capacity(4);
220    for id in 0u64..4 {
221        cache.put(id, read_block(id));
222    }
223    let _ = cache.get(&0);
224    let _ = cache.get(&1);
225    let _ = cache.get(&2);
226    let _ = cache.get(&99);
227    let m = cache.metrics();
228    println!(
229        "  hits {}, misses {}, hit ratio {:.2}",
230        m.hits(),
231        m.misses(),
232        m.hit_ratio()
233    );
234    assert_eq!(m.hits(), 3);
235    assert_eq!(m.misses(), 1);
236    assert!((m.hit_ratio() - 0.75).abs() < 1e-9);
237}
Source

pub fn get(&mut self, key: &K) -> Option<&V>

Examples found in repository?
examples/sample_app.rs (line 223)
216fn metrics_hit_ratio() {
217    use subms_block_cache::MetricsCache;
218    println!("\n== metrics: hit-ratio observability ==");
219    let mut cache: MetricsCache<u64, String> = MetricsCache::with_capacity(4);
220    for id in 0u64..4 {
221        cache.put(id, read_block(id));
222    }
223    let _ = cache.get(&0);
224    let _ = cache.get(&1);
225    let _ = cache.get(&2);
226    let _ = cache.get(&99);
227    let m = cache.metrics();
228    println!(
229        "  hits {}, misses {}, hit ratio {:.2}",
230        m.hits(),
231        m.misses(),
232        m.hit_ratio()
233    );
234    assert_eq!(m.hits(), 3);
235    assert_eq!(m.misses(), 1);
236    assert!((m.hit_ratio() - 0.75).abs() < 1e-9);
237}
More examples
Hide additional examples
examples/perf_features.rs (line 258)
82fn main() -> io::Result<()> {
83    let canon = SIZES[SIZES.len() - 1];
84
85    let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
86        .join("..")
87        .join(".subms")
88        .join("features")
89        .join("rust.json");
90    let existing = std::fs::read_to_string(&path).unwrap_or_default();
91    let mut manifest = SubMsFeatureManifest::load_str("rust", &existing);
92    // Stamp the box these numbers came from. The bench runs wherever it is
93    // invoked, so an unstamped manifest is indistinguishable from a fleet
94    // capture; the renderer will not publish one it cannot attribute.
95    let (source, instance) = SubMsP99Source::from_env();
96    manifest.set_p99_source(source, instance.as_deref());
97
98    // ---------- base (clock-sweep): the baseline, not a feature ----------
99    // Every feature is classified against this. A variant whose lookup lands
100    // within a whisker of the base is a capability, not a latency change, and
101    // classify_feature says so rather than calling it hot-path by default.
102    // The baseline is a p50, because the sweep values are p50s. Handing
103    // classify_feature a base p99 against p50 sweep points compares two
104    // different statistics: the p50 sits below the p99 almost by construction,
105    // so every feature reads as "within 10% of base" and lands auxiliary.
106    let base_p50 = {
107        use subms_block_cache::BlockCache;
108        let mut c: BlockCache<u32, u64> = BlockCache::with_capacity(canon);
109        for k in 0..canon as u32 {
110            c.put(k, k as u64);
111        }
112        let (p50, _) = get_hit(canon, |key| c.get(&key).is_some());
113        p50
114    };
115
116    // ---------- arc: adaptive replacement, recency + frequency lists ----------
117    #[cfg(feature = "arc")]
118    {
119        use subms_block_cache::ArcCache;
120        let sweep: Vec<(usize, u64)> = SIZES
121            .iter()
122            .map(|&n| {
123                let mut c: ArcCache<u32, u64> = ArcCache::with_capacity(n);
124                for k in 0..n as u32 {
125                    c.put(k, k as u64);
126                }
127                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
128                (n, p50)
129            })
130            .collect();
131        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
132
133        let mut c: ArcCache<u32, u64> = ArcCache::with_capacity(canon);
134        for k in 0..canon as u32 {
135            c.put(k, k as u64);
136        }
137        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
138        let (_, put99) = put_evicting(canon, |key| {
139            c.put(key, key as u64);
140        });
141        let mut p99 = BTreeMap::new();
142        p99.insert("get_hit".to_string(), get99);
143        p99.insert("put".to_string(), put99);
144        manifest.set_feature("arc", cat, &p99, &reason);
145    }
146
147    // ---------- tinylfu: frequency-sketch admission ----------
148    #[cfg(feature = "tinylfu")]
149    {
150        use subms_block_cache::TinyLfuCache;
151        let sweep: Vec<(usize, u64)> = SIZES
152            .iter()
153            .map(|&n| {
154                let mut c: TinyLfuCache<u32, u64> = TinyLfuCache::with_capacity(n);
155                for k in 0..n as u32 {
156                    c.put(k, k as u64);
157                }
158                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
159                (n, p50)
160            })
161            .collect();
162        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
163
164        let mut c: TinyLfuCache<u32, u64> = TinyLfuCache::with_capacity(canon);
165        for k in 0..canon as u32 {
166            c.put(k, k as u64);
167        }
168        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
169        let (_, put99) = put_evicting(canon, |key| {
170            c.put(key, key as u64);
171        });
172        let mut p99 = BTreeMap::new();
173        p99.insert("get_hit".to_string(), get99);
174        p99.insert("put".to_string(), put99);
175        manifest.set_feature("tinylfu", cat, &p99, &reason);
176    }
177
178    // ---------- weighted: a byte budget rather than a slot count ----------
179    #[cfg(feature = "weighted")]
180    {
181        use subms_block_cache::WeightedCache;
182        // 1 byte per entry so capacity_bytes == slot capacity; eviction behaves
183        // like the base cache, which isolates the weight bookkeeping itself.
184        let sweep: Vec<(usize, u64)> = SIZES
185            .iter()
186            .map(|&n| {
187                let mut c: WeightedCache<u32, u64> =
188                    WeightedCache::with_capacity_bytes(n, |_v: &u64| 1);
189                for k in 0..n as u32 {
190                    c.put(k, k as u64);
191                }
192                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
193                (n, p50)
194            })
195            .collect();
196        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
197
198        let mut c: WeightedCache<u32, u64> =
199            WeightedCache::with_capacity_bytes(canon, |_v: &u64| 1);
200        for k in 0..canon as u32 {
201            c.put(k, k as u64);
202        }
203        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
204        let (_, put99) = put_evicting(canon, |key| {
205            let _ = c.put(key, key as u64);
206        });
207        let mut p99 = BTreeMap::new();
208        p99.insert("get_hit".to_string(), get99);
209        p99.insert("put".to_string(), put99);
210        manifest.set_feature("weighted", cat, &p99, &reason);
211    }
212
213    // ---------- concurrent-shards: measured single-threaded ----------
214    // Uncontended on purpose. This isolates the sharding INDIRECTION from the
215    // contention it exists to relieve; a multi-threaded number here would say
216    // more about the thread count than about the feature.
217    #[cfg(feature = "concurrent-shards")]
218    {
219        use subms_block_cache::ShardedCache;
220        let sweep: Vec<(usize, u64)> = SIZES
221            .iter()
222            .map(|&n| {
223                let c: ShardedCache<u32, u64> = ShardedCache::with_capacity(n, 16);
224                for k in 0..n as u32 {
225                    c.put(k, k as u64);
226                }
227                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
228                (n, p50)
229            })
230            .collect();
231        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
232
233        let c: ShardedCache<u32, u64> = ShardedCache::with_capacity(canon, 16);
234        for k in 0..canon as u32 {
235            c.put(k, k as u64);
236        }
237        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
238        let (_, put99) = put_evicting(canon, |key| {
239            c.put(key, key as u64);
240        });
241        let mut p99 = BTreeMap::new();
242        p99.insert("get_hit".to_string(), get99);
243        p99.insert("put".to_string(), put99);
244        manifest.set_feature("concurrent-shards", cat, &p99, &reason);
245    }
246
247    // ---------- metrics: hit/miss counters on the lookup path ----------
248    #[cfg(feature = "metrics")]
249    {
250        use subms_block_cache::MetricsCache;
251        let sweep: Vec<(usize, u64)> = SIZES
252            .iter()
253            .map(|&n| {
254                let mut c: MetricsCache<u32, u64> = MetricsCache::with_capacity(n);
255                for k in 0..n as u32 {
256                    c.put(k, k as u64);
257                }
258                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
259                (n, p50)
260            })
261            .collect();
262        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
263
264        let mut c: MetricsCache<u32, u64> = MetricsCache::with_capacity(canon);
265        for k in 0..canon as u32 {
266            c.put(k, k as u64);
267        }
268        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
269        let (_, put99) = put_evicting(canon, |key| {
270            c.put(key, key as u64);
271        });
272        let mut p99 = BTreeMap::new();
273        p99.insert("get_hit".to_string(), get99);
274        p99.insert("put".to_string(), put99);
275        manifest.set_feature("metrics", cat, &p99, &reason);
276    }
277
278    std::fs::create_dir_all(path.parent().unwrap())?;
279    std::fs::write(&path, manifest.to_json())?;
280    io::stdout().write_all(manifest.to_json().as_bytes())?;
281    Ok(())
282}
Source

pub fn put(&mut self, key: K, value: V) -> Option<(K, V)>

Examples found in repository?
examples/sample_app.rs (line 221)
216fn metrics_hit_ratio() {
217    use subms_block_cache::MetricsCache;
218    println!("\n== metrics: hit-ratio observability ==");
219    let mut cache: MetricsCache<u64, String> = MetricsCache::with_capacity(4);
220    for id in 0u64..4 {
221        cache.put(id, read_block(id));
222    }
223    let _ = cache.get(&0);
224    let _ = cache.get(&1);
225    let _ = cache.get(&2);
226    let _ = cache.get(&99);
227    let m = cache.metrics();
228    println!(
229        "  hits {}, misses {}, hit ratio {:.2}",
230        m.hits(),
231        m.misses(),
232        m.hit_ratio()
233    );
234    assert_eq!(m.hits(), 3);
235    assert_eq!(m.misses(), 1);
236    assert!((m.hit_ratio() - 0.75).abs() < 1e-9);
237}
More examples
Hide additional examples
examples/perf_features.rs (line 256)
82fn main() -> io::Result<()> {
83    let canon = SIZES[SIZES.len() - 1];
84
85    let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
86        .join("..")
87        .join(".subms")
88        .join("features")
89        .join("rust.json");
90    let existing = std::fs::read_to_string(&path).unwrap_or_default();
91    let mut manifest = SubMsFeatureManifest::load_str("rust", &existing);
92    // Stamp the box these numbers came from. The bench runs wherever it is
93    // invoked, so an unstamped manifest is indistinguishable from a fleet
94    // capture; the renderer will not publish one it cannot attribute.
95    let (source, instance) = SubMsP99Source::from_env();
96    manifest.set_p99_source(source, instance.as_deref());
97
98    // ---------- base (clock-sweep): the baseline, not a feature ----------
99    // Every feature is classified against this. A variant whose lookup lands
100    // within a whisker of the base is a capability, not a latency change, and
101    // classify_feature says so rather than calling it hot-path by default.
102    // The baseline is a p50, because the sweep values are p50s. Handing
103    // classify_feature a base p99 against p50 sweep points compares two
104    // different statistics: the p50 sits below the p99 almost by construction,
105    // so every feature reads as "within 10% of base" and lands auxiliary.
106    let base_p50 = {
107        use subms_block_cache::BlockCache;
108        let mut c: BlockCache<u32, u64> = BlockCache::with_capacity(canon);
109        for k in 0..canon as u32 {
110            c.put(k, k as u64);
111        }
112        let (p50, _) = get_hit(canon, |key| c.get(&key).is_some());
113        p50
114    };
115
116    // ---------- arc: adaptive replacement, recency + frequency lists ----------
117    #[cfg(feature = "arc")]
118    {
119        use subms_block_cache::ArcCache;
120        let sweep: Vec<(usize, u64)> = SIZES
121            .iter()
122            .map(|&n| {
123                let mut c: ArcCache<u32, u64> = ArcCache::with_capacity(n);
124                for k in 0..n as u32 {
125                    c.put(k, k as u64);
126                }
127                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
128                (n, p50)
129            })
130            .collect();
131        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
132
133        let mut c: ArcCache<u32, u64> = ArcCache::with_capacity(canon);
134        for k in 0..canon as u32 {
135            c.put(k, k as u64);
136        }
137        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
138        let (_, put99) = put_evicting(canon, |key| {
139            c.put(key, key as u64);
140        });
141        let mut p99 = BTreeMap::new();
142        p99.insert("get_hit".to_string(), get99);
143        p99.insert("put".to_string(), put99);
144        manifest.set_feature("arc", cat, &p99, &reason);
145    }
146
147    // ---------- tinylfu: frequency-sketch admission ----------
148    #[cfg(feature = "tinylfu")]
149    {
150        use subms_block_cache::TinyLfuCache;
151        let sweep: Vec<(usize, u64)> = SIZES
152            .iter()
153            .map(|&n| {
154                let mut c: TinyLfuCache<u32, u64> = TinyLfuCache::with_capacity(n);
155                for k in 0..n as u32 {
156                    c.put(k, k as u64);
157                }
158                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
159                (n, p50)
160            })
161            .collect();
162        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
163
164        let mut c: TinyLfuCache<u32, u64> = TinyLfuCache::with_capacity(canon);
165        for k in 0..canon as u32 {
166            c.put(k, k as u64);
167        }
168        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
169        let (_, put99) = put_evicting(canon, |key| {
170            c.put(key, key as u64);
171        });
172        let mut p99 = BTreeMap::new();
173        p99.insert("get_hit".to_string(), get99);
174        p99.insert("put".to_string(), put99);
175        manifest.set_feature("tinylfu", cat, &p99, &reason);
176    }
177
178    // ---------- weighted: a byte budget rather than a slot count ----------
179    #[cfg(feature = "weighted")]
180    {
181        use subms_block_cache::WeightedCache;
182        // 1 byte per entry so capacity_bytes == slot capacity; eviction behaves
183        // like the base cache, which isolates the weight bookkeeping itself.
184        let sweep: Vec<(usize, u64)> = SIZES
185            .iter()
186            .map(|&n| {
187                let mut c: WeightedCache<u32, u64> =
188                    WeightedCache::with_capacity_bytes(n, |_v: &u64| 1);
189                for k in 0..n as u32 {
190                    c.put(k, k as u64);
191                }
192                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
193                (n, p50)
194            })
195            .collect();
196        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
197
198        let mut c: WeightedCache<u32, u64> =
199            WeightedCache::with_capacity_bytes(canon, |_v: &u64| 1);
200        for k in 0..canon as u32 {
201            c.put(k, k as u64);
202        }
203        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
204        let (_, put99) = put_evicting(canon, |key| {
205            let _ = c.put(key, key as u64);
206        });
207        let mut p99 = BTreeMap::new();
208        p99.insert("get_hit".to_string(), get99);
209        p99.insert("put".to_string(), put99);
210        manifest.set_feature("weighted", cat, &p99, &reason);
211    }
212
213    // ---------- concurrent-shards: measured single-threaded ----------
214    // Uncontended on purpose. This isolates the sharding INDIRECTION from the
215    // contention it exists to relieve; a multi-threaded number here would say
216    // more about the thread count than about the feature.
217    #[cfg(feature = "concurrent-shards")]
218    {
219        use subms_block_cache::ShardedCache;
220        let sweep: Vec<(usize, u64)> = SIZES
221            .iter()
222            .map(|&n| {
223                let c: ShardedCache<u32, u64> = ShardedCache::with_capacity(n, 16);
224                for k in 0..n as u32 {
225                    c.put(k, k as u64);
226                }
227                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
228                (n, p50)
229            })
230            .collect();
231        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
232
233        let c: ShardedCache<u32, u64> = ShardedCache::with_capacity(canon, 16);
234        for k in 0..canon as u32 {
235            c.put(k, k as u64);
236        }
237        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
238        let (_, put99) = put_evicting(canon, |key| {
239            c.put(key, key as u64);
240        });
241        let mut p99 = BTreeMap::new();
242        p99.insert("get_hit".to_string(), get99);
243        p99.insert("put".to_string(), put99);
244        manifest.set_feature("concurrent-shards", cat, &p99, &reason);
245    }
246
247    // ---------- metrics: hit/miss counters on the lookup path ----------
248    #[cfg(feature = "metrics")]
249    {
250        use subms_block_cache::MetricsCache;
251        let sweep: Vec<(usize, u64)> = SIZES
252            .iter()
253            .map(|&n| {
254                let mut c: MetricsCache<u32, u64> = MetricsCache::with_capacity(n);
255                for k in 0..n as u32 {
256                    c.put(k, k as u64);
257                }
258                let (p50, _) = get_hit(n, |key| c.get(&key).is_some());
259                (n, p50)
260            })
261            .collect();
262        let (cat, reason) = classify_feature(&sweep, Some(base_p50), None);
263
264        let mut c: MetricsCache<u32, u64> = MetricsCache::with_capacity(canon);
265        for k in 0..canon as u32 {
266            c.put(k, k as u64);
267        }
268        let (_, get99) = get_hit(canon, |key| c.get(&key).is_some());
269        let (_, put99) = put_evicting(canon, |key| {
270            c.put(key, key as u64);
271        });
272        let mut p99 = BTreeMap::new();
273        p99.insert("get_hit".to_string(), get99);
274        p99.insert("put".to_string(), put99);
275        manifest.set_feature("metrics", cat, &p99, &reason);
276    }
277
278    std::fs::create_dir_all(path.parent().unwrap())?;
279    std::fs::write(&path, manifest.to_json())?;
280    io::stdout().write_all(manifest.to_json().as_bytes())?;
281    Ok(())
282}
Source

pub fn remove(&mut self, key: &K) -> Option<V>

Invalidation is not eviction, so it moves no counter.

Source

pub fn clear(&mut self)

Auto Trait Implementations§

§

impl<K, V> !Freeze for MetricsCache<K, V>

§

impl<K, V> RefUnwindSafe for MetricsCache<K, V>

§

impl<K, V> Send for MetricsCache<K, V>
where K: Send, V: Send,

§

impl<K, V> Sync for MetricsCache<K, V>
where K: Sync, V: Sync,

§

impl<K, V> Unpin for MetricsCache<K, V>
where K: Unpin, V: Unpin,

§

impl<K, V> UnsafeUnpin for MetricsCache<K, V>

§

impl<K, V> UnwindSafe for MetricsCache<K, V>
where K: UnwindSafe, V: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.