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 /// Updates the segment sizes
117 ///
118 /// # Arguments
119 /// * `probationary_size` - Current number of items in probationary segment
120 /// * `protected_size` - Current number of items in protected segment
121 pub fn update_segment_sizes(&mut self, probationary_size: u64, protected_size: u64) {
122 self.probationary_size = probationary_size;
123 self.protected_size = protected_size;
124 }
125
126 /// Calculates the protection ratio (protected hits / total hits)
127 ///
128 /// # Returns
129 /// Ratio of hits in protected segment vs total hits, or 0.0 if no hits
130 pub fn protection_ratio(&self) -> f64 {
131 if self.core.cache_hits > 0 {
132 self.protected_hits as f64 / self.core.cache_hits as f64
133 } else {
134 0.0
135 }
136 }
137
138 /// Calculates the promotion efficiency (promotions / probationary hits)
139 ///
140 /// # Returns
141 /// How often probationary hits lead to promotions, or 0.0 if no probationary hits
142 pub fn promotion_efficiency(&self) -> f64 {
143 if self.probationary_hits > 0 {
144 self.total_promotions as f64 / self.probationary_hits as f64
145 } else {
146 0.0
147 }
148 }
149
150 /// Calculates protected segment utilization
151 ///
152 /// # Returns
153 /// Ratio of current protected size to maximum protected size
154 pub fn protected_utilization(&self) -> f64 {
155 if self.protected_max_size > 0 {
156 self.protected_size as f64 / self.protected_max_size as f64
157 } else {
158 0.0
159 }
160 }
161
162 /// Converts SLRU metrics to a BTreeMap for reporting
163 ///
164 /// This method returns all metrics relevant to the SLRU cache algorithm,
165 /// including both core metrics and SLRU-specific segment metrics.
166 ///
167 /// Uses BTreeMap to ensure consistent, deterministic ordering of metrics.
168 ///
169 /// # Returns
170 /// A BTreeMap containing all SLRU cache metrics as key-value pairs
171 pub fn to_btreemap(&self) -> BTreeMap<String, f64> {
172 let mut metrics = self.core.to_btreemap();
173
174 // SLRU-specific segment metrics
175 metrics.insert(
176 "probationary_size".to_string(),
177 self.probationary_size as f64,
178 );
179 metrics.insert("protected_size".to_string(), self.protected_size as f64);
180 metrics.insert(
181 "protected_max_size".to_string(),
182 self.protected_max_size as f64,
183 );
184 metrics.insert(
185 "protected_utilization".to_string(),
186 self.protected_utilization(),
187 );
188
189 // Movement metrics
190 metrics.insert("total_promotions".to_string(), self.total_promotions as f64);
191 metrics.insert("total_demotions".to_string(), self.total_demotions as f64);
192
193 // Segment-specific hit metrics
194 metrics.insert(
195 "probationary_hits".to_string(),
196 self.probationary_hits as f64,
197 );
198 metrics.insert("protected_hits".to_string(), self.protected_hits as f64);
199 metrics.insert("protection_ratio".to_string(), self.protection_ratio());
200
201 // Segment-specific eviction metrics
202 metrics.insert(
203 "probationary_evictions".to_string(),
204 self.probationary_evictions as f64,
205 );
206 metrics.insert(
207 "protected_evictions".to_string(),
208 self.protected_evictions as f64,
209 );
210
211 // Efficiency metrics
212 metrics.insert(
213 "promotion_efficiency".to_string(),
214 self.promotion_efficiency(),
215 );
216
217 if self.core.requests > 0 {
218 metrics.insert(
219 "promotion_rate".to_string(),
220 self.total_promotions as f64 / self.core.requests as f64,
221 );
222 metrics.insert(
223 "demotion_rate".to_string(),
224 self.total_demotions as f64 / self.core.requests as f64,
225 );
226 }
227
228 metrics
229 }
230}
231
232impl CacheMetrics for SlruCacheMetrics {
233 /// Returns all SLRU cache metrics as key-value pairs in deterministic order
234 ///
235 /// # Returns
236 /// A BTreeMap containing all metrics tracked by this SLRU cache instance
237 fn metrics(&self) -> BTreeMap<String, f64> {
238 self.to_btreemap()
239 }
240
241 /// Returns the algorithm name for this cache implementation
242 ///
243 /// # Returns
244 /// "SLRU" - identifying this as a Segmented Least Recently Used cache
245 fn algorithm_name(&self) -> &'static str {
246 "SLRU"
247 }
248}