1use crate::types::Value;
18
19pub(crate) const ENTRY_OVERHEAD: usize = 96;
31
32#[derive(Debug)]
37pub struct MemoryTracker {
38 used_bytes: usize,
39 key_count: usize,
40}
41
42impl MemoryTracker {
43 pub fn new() -> Self {
45 Self {
46 used_bytes: 0,
47 key_count: 0,
48 }
49 }
50
51 pub fn reset(&mut self) {
53 self.used_bytes = 0;
54 self.key_count = 0;
55 }
56
57 pub fn used_bytes(&self) -> usize {
59 self.used_bytes
60 }
61
62 pub fn key_count(&self) -> usize {
64 self.key_count
65 }
66
67 pub fn add(&mut self, key: &str, value: &Value) {
69 self.used_bytes += entry_size(key, value);
70 self.key_count += 1;
71 }
72
73 pub fn remove(&mut self, key: &str, value: &Value) {
75 let size = entry_size(key, value);
76 self.used_bytes = self.used_bytes.saturating_sub(size);
77 self.key_count = self.key_count.saturating_sub(1);
78 }
79
80 pub fn replace(&mut self, key: &str, old_value: &Value, new_value: &Value) {
85 let old_size = entry_size(key, old_value);
86 let new_size = entry_size(key, new_value);
87 self.used_bytes = self
88 .used_bytes
89 .saturating_sub(old_size)
90 .saturating_add(new_size);
91 }
92
93 pub fn adjust(&mut self, old_entry_size: usize, new_entry_size: usize) {
99 self.used_bytes = self
100 .used_bytes
101 .saturating_sub(old_entry_size)
102 .saturating_add(new_entry_size);
103 }
104
105 pub fn remove_with_size(&mut self, size: usize) {
108 self.used_bytes = self.used_bytes.saturating_sub(size);
109 self.key_count = self.key_count.saturating_sub(1);
110 }
111}
112
113impl Default for MemoryTracker {
114 fn default() -> Self {
115 Self::new()
116 }
117}
118
119pub fn entry_size(key: &str, value: &Value) -> usize {
123 key.len() + value_size(value) + ENTRY_OVERHEAD
124}
125
126pub(crate) const VECDEQUE_ELEMENT_OVERHEAD: usize = 32;
131
132pub(crate) const VECDEQUE_BASE_OVERHEAD: usize = 24;
134
135pub(crate) const HASHMAP_ENTRY_OVERHEAD: usize = 64;
140
141pub(crate) const HASHMAP_BASE_OVERHEAD: usize = 48;
143
144pub(crate) const HASHSET_MEMBER_OVERHEAD: usize = 40;
148
149pub(crate) const HASHSET_BASE_OVERHEAD: usize = 48;
151
152pub fn value_size(value: &Value) -> usize {
154 match value {
155 Value::String(data) => data.len(),
156 Value::List(deque) => {
157 let element_bytes: usize = deque
158 .iter()
159 .map(|b| b.len() + VECDEQUE_ELEMENT_OVERHEAD)
160 .sum();
161 VECDEQUE_BASE_OVERHEAD + element_bytes
162 }
163 Value::SortedSet(ss) => ss.memory_usage(),
164 Value::Hash(map) => {
165 let entry_bytes: usize = map
166 .iter()
167 .map(|(k, v)| k.len() + v.len() + HASHMAP_ENTRY_OVERHEAD)
168 .sum();
169 HASHMAP_BASE_OVERHEAD + entry_bytes
170 }
171 Value::Set(set) => {
172 let member_bytes: usize = set.iter().map(|m| m.len() + HASHSET_MEMBER_OVERHEAD).sum();
173 HASHSET_BASE_OVERHEAD + member_bytes
174 }
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181 use bytes::Bytes;
182
183 fn string_val(s: &str) -> Value {
184 Value::String(Bytes::from(s.to_string()))
185 }
186
187 #[test]
188 fn new_tracker_is_empty() {
189 let t = MemoryTracker::new();
190 assert_eq!(t.used_bytes(), 0);
191 assert_eq!(t.key_count(), 0);
192 }
193
194 #[test]
195 fn add_increases_usage() {
196 let mut t = MemoryTracker::new();
197 let val = string_val("hello");
198 t.add("key", &val);
199 assert_eq!(t.key_count(), 1);
200 assert_eq!(t.used_bytes(), entry_size("key", &val));
201 }
202
203 #[test]
204 fn remove_decreases_usage() {
205 let mut t = MemoryTracker::new();
206 let val = string_val("data");
207 t.add("k", &val);
208 t.remove("k", &val);
209 assert_eq!(t.used_bytes(), 0);
210 assert_eq!(t.key_count(), 0);
211 }
212
213 #[test]
214 fn replace_adjusts_usage() {
215 let mut t = MemoryTracker::new();
216 let old = string_val("short");
217 let new = string_val("a much longer value here");
218 t.add("k", &old);
219
220 let before = t.used_bytes();
221 t.replace("k", &old, &new);
222
223 assert_eq!(t.key_count(), 1);
224 assert!(t.used_bytes() > before);
226 assert_eq!(t.used_bytes(), entry_size("k", &new),);
227 }
228
229 #[test]
230 fn remove_saturates_at_zero() {
231 let mut t = MemoryTracker::new();
232 let val = string_val("x");
233 t.remove("k", &val);
235 assert_eq!(t.used_bytes(), 0);
236 assert_eq!(t.key_count(), 0);
237 }
238
239 #[test]
240 fn entry_size_accounts_for_key_and_value() {
241 let val = string_val("test");
242 let size = entry_size("mykey", &val);
243 assert_eq!(size, 5 + 4 + ENTRY_OVERHEAD);
245 }
246
247 #[test]
248 fn list_value_size() {
249 let mut deque = std::collections::VecDeque::new();
250 deque.push_back(Bytes::from("hello"));
251 deque.push_back(Bytes::from("world"));
252 let val = Value::List(deque);
253
254 let size = value_size(&val);
255 let expected = VECDEQUE_BASE_OVERHEAD
257 + (5 + VECDEQUE_ELEMENT_OVERHEAD)
258 + (5 + VECDEQUE_ELEMENT_OVERHEAD);
259 assert_eq!(size, expected);
260 }
261
262 #[test]
263 fn empty_list_value_size() {
264 let val = Value::List(std::collections::VecDeque::new());
265 assert_eq!(value_size(&val), VECDEQUE_BASE_OVERHEAD);
266 }
267
268 #[test]
269 fn multiple_entries() {
270 let mut t = MemoryTracker::new();
271 let v1 = string_val("aaa");
272 let v2 = string_val("bbbbb");
273 t.add("k1", &v1);
274 t.add("k2", &v2);
275
276 assert_eq!(t.key_count(), 2);
277 assert_eq!(
278 t.used_bytes(),
279 entry_size("k1", &v1) + entry_size("k2", &v2),
280 );
281
282 t.remove("k1", &v1);
283 assert_eq!(t.key_count(), 1);
284 assert_eq!(t.used_bytes(), entry_size("k2", &v2));
285 }
286}