cache_rs/metrics/slru.rs
1//! SLRU Cache Metrics
2//!
3//! Metrics specific to the SLRU (Segmented Least Recently Used) cache algorithm.
4
5extern crate alloc;
6
7use super::{CacheMetrics, CoreCacheMetrics};
8use alloc::collections::BTreeMap;
9use alloc::string::{String, ToString};
10
11/// SLRU-specific metrics (extends CoreCacheMetrics)
12///
13/// This struct contains metrics specific to the SLRU (Segmented LRU) cache algorithm.
14/// SLRU divides the cache into probationary and protected segments, so these metrics
15/// focus on segment utilization and promotion/demotion patterns.
16#[derive(Debug, Clone)]
17pub struct SlruCacheMetrics {
18 /// Core metrics common to all cache algorithms
19 pub core: CoreCacheMetrics,
20
21 /// Number of items currently in the probationary segment
22 pub probationary_size: u64,
23
24 /// Number of items currently in the protected segment
25 pub protected_size: u64,
26
27 /// Maximum allowed size for the protected segment
28 pub protected_max_size: u64,
29
30 /// Total number of promotions from probationary to protected segment
31 pub total_promotions: u64,
32
33 /// Total number of demotions from protected to probationary segment
34 pub total_demotions: u64,
35
36 /// Number of cache hits in the probationary segment
37 pub probationary_hits: u64,
38
39 /// Number of cache hits in the protected segment
40 pub protected_hits: u64,
41
42 /// Number of evictions from the probationary segment
43 pub probationary_evictions: u64,
44
45 /// Number of evictions from the protected segment
46 pub protected_evictions: u64,
47}
48
49impl SlruCacheMetrics {
50 /// Creates a new SlruCacheMetrics instance with the specified parameters
51 ///
52 /// # Arguments
53 /// * `max_cache_size_bytes` - The maximum allowed cache size in bytes
54 /// * `protected_max_size` - The maximum number of items in protected segment
55 pub fn new(max_cache_size_bytes: u64, protected_max_size: u64) -> Self {
56 Self {
57 core: CoreCacheMetrics::new(max_cache_size_bytes),
58 probationary_size: 0,
59 protected_size: 0,
60 protected_max_size,
61 total_promotions: 0,
62 total_demotions: 0,
63 probationary_hits: 0,
64 protected_hits: 0,
65 probationary_evictions: 0,
66 protected_evictions: 0,
67 }
68 }
69
70 /// Records a promotion from probationary to protected segment
71 pub fn record_promotion(&mut self) {
72 self.total_promotions += 1;
73 }
74
75 /// Records a demotion from protected to probationary segment
76 pub fn record_demotion(&mut self) {
77 self.total_demotions += 1;
78 }
79
80 /// Records a cache hit in the probationary segment
81 ///
82 /// # Arguments
83 /// * `object_size` - Size of the object that was served from cache (in bytes)
84 pub fn record_probationary_hit(&mut self, object_size: u64) {
85 self.core.record_hit(object_size);
86 self.probationary_hits += 1;
87 }
88
89 /// Records a cache hit in the protected segment
90 ///
91 /// # Arguments
92 /// * `object_size` - Size of the object that was served from cache (in bytes)
93 pub fn record_protected_hit(&mut self, object_size: u64) {
94 self.core.record_hit(object_size);
95 self.protected_hits += 1;
96 }
97
98 /// Records an eviction from the probationary segment
99 ///
100 /// # Arguments
101 /// * `evicted_size` - Size of the evicted object (in bytes)
102 pub fn record_probationary_eviction(&mut self, evicted_size: u64) {
103 self.core.record_eviction(evicted_size);
104 self.probationary_evictions += 1;
105 }
106
107 /// Records an eviction from the protected segment
108 ///
109 /// # Arguments
110 /// * `evicted_size` - Size of the evicted object (in bytes)
111 pub fn record_protected_eviction(&mut self, evicted_size: u64) {
112 self.core.record_eviction(evicted_size);
113 self.protected_evictions += 1;
114 }
115
116 /// Records a removal (explicit remove) from the probationary segment.
117 ///
118 /// Unlike `record_probationary_eviction`, this does **not** increment the
119 /// eviction counter. Use this when the user explicitly removes an entry
120 /// via `remove()`.
121 ///
122 /// # Arguments
123 /// * `removed_size` - Size of the removed object (in bytes)
124 pub fn record_probationary_removal(&mut self, removed_size: u64) {
125 self.core.record_removal(removed_size);
126 }
127
128 /// Records a removal (explicit remove) from the protected segment.
129 ///
130 /// Unlike `record_protected_eviction`, this does **not** increment the
131 /// eviction counter. Use this when the user explicitly removes an entry
132 /// via `remove()`.
133 ///
134 /// # Arguments
135 /// * `removed_size` - Size of the removed object (in bytes)
136 pub fn record_protected_removal(&mut self, removed_size: u64) {
137 self.core.record_removal(removed_size);
138 }
139
140 /// Updates the segment sizes
141 ///
142 /// # Arguments
143 /// * `probationary_size` - Current number of items in probationary segment
144 /// * `protected_size` - Current number of items in protected segment
145 pub fn update_segment_sizes(&mut self, probationary_size: u64, protected_size: u64) {
146 self.probationary_size = probationary_size;
147 self.protected_size = protected_size;
148 }
149
150 /// Calculates the protection ratio (protected hits / total hits)
151 ///
152 /// # Returns
153 /// Ratio of hits in protected segment vs total hits, or 0.0 if no hits
154 pub fn protection_ratio(&self) -> f64 {
155 if self.core.cache_hits > 0 {
156 self.protected_hits as f64 / self.core.cache_hits as f64
157 } else {
158 0.0
159 }
160 }
161
162 /// Calculates the promotion efficiency (promotions / probationary hits)
163 ///
164 /// # Returns
165 /// How often probationary hits lead to promotions, or 0.0 if no probationary hits
166 pub fn promotion_efficiency(&self) -> f64 {
167 if self.probationary_hits > 0 {
168 self.total_promotions as f64 / self.probationary_hits as f64
169 } else {
170 0.0
171 }
172 }
173
174 /// Calculates protected segment utilization
175 ///
176 /// # Returns
177 /// Ratio of current protected size to maximum protected size
178 pub fn protected_utilization(&self) -> f64 {
179 if self.protected_max_size > 0 {
180 self.protected_size as f64 / self.protected_max_size as f64
181 } else {
182 0.0
183 }
184 }
185
186 /// Converts SLRU metrics to a BTreeMap for reporting
187 ///
188 /// This method returns all metrics relevant to the SLRU cache algorithm,
189 /// including both core metrics and SLRU-specific segment metrics.
190 ///
191 /// Uses BTreeMap to ensure consistent, deterministic ordering of metrics.
192 ///
193 /// # Returns
194 /// A BTreeMap containing all SLRU cache metrics as key-value pairs
195 pub fn to_btreemap(&self) -> BTreeMap<String, f64> {
196 let mut metrics = self.core.to_btreemap();
197
198 // SLRU-specific segment metrics
199 metrics.insert(
200 "probationary_size".to_string(),
201 self.probationary_size as f64,
202 );
203 metrics.insert("protected_size".to_string(), self.protected_size as f64);
204 metrics.insert(
205 "protected_max_size".to_string(),
206 self.protected_max_size as f64,
207 );
208 metrics.insert(
209 "protected_utilization".to_string(),
210 self.protected_utilization(),
211 );
212
213 // Movement metrics
214 metrics.insert("total_promotions".to_string(), self.total_promotions as f64);
215 metrics.insert("total_demotions".to_string(), self.total_demotions as f64);
216
217 // Segment-specific hit metrics
218 metrics.insert(
219 "probationary_hits".to_string(),
220 self.probationary_hits as f64,
221 );
222 metrics.insert("protected_hits".to_string(), self.protected_hits as f64);
223 metrics.insert("protection_ratio".to_string(), self.protection_ratio());
224
225 // Segment-specific eviction metrics
226 metrics.insert(
227 "probationary_evictions".to_string(),
228 self.probationary_evictions as f64,
229 );
230 metrics.insert(
231 "protected_evictions".to_string(),
232 self.protected_evictions as f64,
233 );
234
235 // Efficiency metrics
236 metrics.insert(
237 "promotion_efficiency".to_string(),
238 self.promotion_efficiency(),
239 );
240
241 if self.core.requests > 0 {
242 metrics.insert(
243 "promotion_rate".to_string(),
244 self.total_promotions as f64 / self.core.requests as f64,
245 );
246 metrics.insert(
247 "demotion_rate".to_string(),
248 self.total_demotions as f64 / self.core.requests as f64,
249 );
250 }
251
252 metrics
253 }
254}
255
256impl CacheMetrics for SlruCacheMetrics {
257 /// Returns all SLRU cache metrics as key-value pairs in deterministic order
258 ///
259 /// # Returns
260 /// A BTreeMap containing all metrics tracked by this SLRU cache instance
261 fn metrics(&self) -> BTreeMap<String, f64> {
262 self.to_btreemap()
263 }
264
265 /// Returns the algorithm name for this cache implementation
266 ///
267 /// # Returns
268 /// "SLRU" - identifying this as a Segmented Least Recently Used cache
269 fn algorithm_name(&self) -> &'static str {
270 "SLRU"
271 }
272}