1use ahash::RandomState;
2use hashlink::LinkedHashMap;
3
4pub mod direction;
5pub mod flow;
6pub mod process;
7pub mod tuple;
8pub mod vni;
9
10pub trait Trackable {
12 type Timestamp: PartialOrd + Clone;
13 fn timestamp(&self) -> Self::Timestamp;
14 fn set_timestamp(&mut self, ts: Self::Timestamp);
15}
16
17pub struct Tracker<K, V: Trackable> {
19 lru: LinkedHashMap<K, V, RandomState>,
20}
21
22impl<K, V> Tracker<K, V>
23where
24 K: Eq + std::hash::Hash + Clone,
25 V: Trackable,
26{
27 #[inline]
28 pub fn new() -> Self {
29 Tracker {
30 lru: LinkedHashMap::with_hasher(RandomState::new()),
31 }
32 }
33
34 #[inline]
35 pub fn with_capacity(capacity: usize) -> Self {
36 Tracker {
37 lru: LinkedHashMap::with_capacity_and_hasher(capacity, RandomState::new()),
38 }
39 }
40
41 #[inline]
42 pub fn get_or_insert_with<F>(&mut self, key: &K, create: F) -> &mut V
43 where
44 F: FnOnce() -> V,
45 {
46 let lru_ptr = &mut self.lru as *mut LinkedHashMap<K, V, RandomState>;
50 if let Some(v) = unsafe { &mut *lru_ptr }.to_back(key) {
51 return v;
52 }
53
54 self.lru.entry(key.clone()).or_insert_with(create)
55 }
56
57 pub fn process_and_evict<F>(&mut self, mut process: F) -> usize
59 where
60 F: FnMut(&K, &V) -> bool, {
62 let mut evicted = 0;
63 loop {
64 match self.lru.front() {
65 Some((k, v)) if process(k, v) => {
66 self.lru.pop_front(); evicted += 1;
68 }
69 _ => break,
70 }
71 }
72 evicted
73 }
74
75 #[inline]
77 pub fn front(&self) -> Option<(&K, &V)> {
78 self.lru.front()
79 }
80
81 #[inline]
83 pub fn back(&self) -> Option<(&K, &V)> {
84 self.lru.back()
85 }
86
87 #[inline]
89 pub fn pop_front(&mut self) -> Option<(K, V)> {
90 self.lru.pop_front()
91 }
92
93 #[inline]
95 pub fn pop_back(&mut self) -> Option<(K, V)> {
96 self.lru.pop_back()
97 }
98
99 #[inline]
101 pub fn remove(&mut self, key: &K) -> Option<V> {
102 self.lru.remove(key)
103 }
104
105 #[inline]
107 pub fn get_timestamp(&self, key: &K) -> Option<V::Timestamp> {
108 self.lru.get(key).map(|v| v.timestamp())
109 }
110
111 #[inline]
113 pub fn get(&self, key: &K) -> Option<&V> {
114 self.lru.get(key)
115 }
116
117 #[inline]
119 pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
120 self.lru.get_mut(key)
121 }
122
123 pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
125 self.lru.iter()
126 }
127
128 pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
130 self.lru.iter_mut()
131 }
132
133 pub fn keys(&self) -> impl Iterator<Item = &K> {
135 self.lru.keys()
136 }
137
138 pub fn values(&self) -> impl Iterator<Item = &V> {
140 self.lru.values()
141 }
142
143 pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
145 self.lru.values_mut()
146 }
147
148 #[inline]
150 pub fn len(&self) -> usize {
151 self.lru.len()
152 }
153
154 #[inline]
156 pub fn is_empty(&self) -> bool {
157 self.lru.is_empty()
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[derive(Debug, Clone, PartialEq)]
166 struct FlowData {
167 timestamp: u64,
168 bytes: u64,
169 packets: u32,
170 }
171
172 impl Trackable for FlowData {
173 type Timestamp = u64;
174
175 fn timestamp(&self) -> u64 {
176 self.timestamp
177 }
178
179 fn set_timestamp(&mut self, ts: u64) {
180 self.timestamp = ts;
181 }
182 }
183
184 #[test]
185 fn test_basic_insertion() {
186 let mut tracker = Tracker::<i32, FlowData>::with_capacity(10);
187
188 tracker.get_or_insert_with(&1, || FlowData {
190 timestamp: 100,
191 bytes: 1000,
192 packets: 10,
193 });
194 tracker.get_or_insert_with(&2, || FlowData {
195 timestamp: 200,
196 bytes: 2000,
197 packets: 20,
198 });
199 tracker.get_or_insert_with(&3, || FlowData {
200 timestamp: 300,
201 bytes: 3000,
202 packets: 30,
203 });
204
205 assert_eq!(tracker.len(), 3);
206
207 let flow1 = tracker.get(&1).unwrap();
209 assert_eq!(flow1.timestamp, 100);
210 assert_eq!(flow1.bytes, 1000);
211 }
212
213 #[test]
214 fn test_lru_behavior() {
215 let mut tracker = Tracker::<i32, FlowData>::with_capacity(10);
216
217 tracker.get_or_insert_with(&1, || FlowData {
218 timestamp: 100,
219 bytes: 1000,
220 packets: 10,
221 });
222 tracker.get_or_insert_with(&2, || FlowData {
223 timestamp: 200,
224 bytes: 2000,
225 packets: 20,
226 });
227 tracker.get_or_insert_with(&3, || FlowData {
228 timestamp: 300,
229 bytes: 3000,
230 packets: 30,
231 });
232
233 let keys: Vec<_> = tracker.lru.keys().copied().collect();
235 println!("After inserts: {:?}", keys);
236 assert_eq!(keys, vec![1, 2, 3]);
237
238 tracker.get_or_insert_with(&1, || FlowData {
240 timestamp: 400,
241 bytes: 1000,
242 packets: 10,
243 });
244
245 let keys: Vec<_> = tracker.lru.keys().copied().collect();
247 println!("After accessing 1: {:?}", keys);
248 assert_eq!(keys, vec![2, 3, 1]); assert_eq!(tracker.lru.front().map(|(k, _)| *k), Some(2));
252 assert_eq!(tracker.lru.back().map(|(k, _)| *k), Some(1));
253 }
254
255 #[test]
256 fn test_iteration_order() {
257 let mut tracker = Tracker::<i32, FlowData>::with_capacity(10);
258
259 tracker.get_or_insert_with(&1, || FlowData {
260 timestamp: 100,
261 bytes: 1000,
262 packets: 10,
263 });
264 tracker.get_or_insert_with(&2, || FlowData {
265 timestamp: 200,
266 bytes: 2000,
267 packets: 20,
268 });
269 tracker.get_or_insert_with(&3, || FlowData {
270 timestamp: 300,
271 bytes: 3000,
272 packets: 30,
273 });
274
275 let keys: Vec<_> = tracker.iter().map(|(k, _)| *k).collect();
277 assert_eq!(keys, vec![1, 2, 3]);
278
279 let timestamps: Vec<_> = tracker.iter().map(|(_, v)| v.timestamp).collect();
281 assert_eq!(timestamps, vec![100, 200, 300]);
282 }
283
284 #[test]
285 fn test_get_or_insert_with() {
286 let mut tracker = Tracker::<i32, FlowData>::with_capacity(10);
287
288 tracker.get_or_insert_with(&1, || FlowData {
290 timestamp: 100,
291 bytes: 1000,
292 packets: 10,
293 });
294
295 assert_eq!(tracker.len(), 1);
296 assert_eq!(tracker.get(&1).unwrap().bytes, 1000);
297
298 tracker.get_or_insert_with(&1, || FlowData {
300 timestamp: 200,
301 bytes: 9999,
302 packets: 99,
303 });
304
305 assert_eq!(tracker.get(&1).unwrap().bytes, 1000);
307 }
308
309 #[test]
310 fn test_empty_tracker() {
311 let tracker = Tracker::<i32, FlowData>::new();
312
313 assert!(tracker.is_empty());
314 assert_eq!(tracker.len(), 0);
315 assert!(tracker.get(&1).is_none());
316 assert!(tracker.get_timestamp(&1).is_none());
317 }
318
319 #[test]
320 fn test_process_and_evict_basic() {
321 let mut tracker = Tracker::<i32, FlowData>::with_capacity(10);
322
323 tracker.get_or_insert_with(&1, || FlowData {
324 timestamp: 100,
325 bytes: 1000,
326 packets: 10,
327 });
328 tracker.get_or_insert_with(&2, || FlowData {
329 timestamp: 200,
330 bytes: 2000,
331 packets: 20,
332 });
333 tracker.get_or_insert_with(&3, || FlowData {
334 timestamp: 300,
335 bytes: 3000,
336 packets: 30,
337 });
338 tracker.get_or_insert_with(&4, || FlowData {
339 timestamp: 400,
340 bytes: 4000,
341 packets: 40,
342 });
343
344 let threshold = 250;
346 let evicted = tracker.process_and_evict(|_key, value| {
347 value.timestamp < threshold });
349
350 assert_eq!(evicted, 2); assert_eq!(tracker.len(), 2); assert!(tracker.get(&1).is_none());
354 assert!(tracker.get(&2).is_none());
355 assert!(tracker.get(&3).is_some());
356 assert!(tracker.get(&4).is_some());
357 }
358
359 #[test]
360 fn test_process_and_evict_with_keep() {
361 let mut tracker = Tracker::<i32, FlowData>::with_capacity(10);
362
363 tracker.get_or_insert_with(&1, || FlowData {
364 timestamp: 100,
365 bytes: 1000,
366 packets: 10,
367 });
368 tracker.get_or_insert_with(&2, || FlowData {
369 timestamp: 200,
370 bytes: 2000,
371 packets: 20,
372 });
373 tracker.get_or_insert_with(&3, || FlowData {
374 timestamp: 300,
375 bytes: 3000,
376 packets: 30,
377 });
378 tracker.get_or_insert_with(&4, || FlowData {
379 timestamp: 400,
380 bytes: 4000,
381 packets: 40,
382 });
383
384 let threshold = 250;
387 let evicted = tracker.process_and_evict(|_key, value| {
388 value.timestamp < threshold });
390
391 assert_eq!(evicted, 2); assert_eq!(tracker.len(), 2); assert!(tracker.get(&1).is_none());
395 assert!(tracker.get(&2).is_none());
396 assert!(tracker.get(&3).is_some());
397 assert!(tracker.get(&4).is_some());
398 }
399
400 #[test]
401 fn test_process_and_evict_stop_early() {
402 let mut tracker = Tracker::<i32, FlowData>::with_capacity(10);
403
404 tracker.get_or_insert_with(&1, || FlowData {
405 timestamp: 100,
406 bytes: 1000,
407 packets: 10,
408 });
409 tracker.get_or_insert_with(&2, || FlowData {
410 timestamp: 200,
411 bytes: 2000,
412 packets: 20,
413 });
414 tracker.get_or_insert_with(&3, || FlowData {
415 timestamp: 300,
416 bytes: 3000,
417 packets: 30,
418 });
419 tracker.get_or_insert_with(&4, || FlowData {
420 timestamp: 400,
421 bytes: 4000,
422 packets: 40,
423 });
424
425 let mut inspected = Vec::new();
427 let threshold = 250;
428 let evicted = tracker.process_and_evict(|key, value| {
429 inspected.push(*key);
430 value.timestamp < threshold });
432
433 assert_eq!(evicted, 2); assert_eq!(inspected, vec![1, 2, 3]); assert_eq!(tracker.len(), 2); assert!(tracker.get(&1).is_none());
438 assert!(tracker.get(&2).is_none());
439 assert!(tracker.get(&3).is_some()); assert!(tracker.get(&4).is_some());
441 }
442
443 #[test]
444 fn test_process_and_evict_with_accumulation() {
445 let mut tracker = Tracker::<i32, FlowData>::with_capacity(10);
446
447 tracker.get_or_insert_with(&1, || FlowData {
448 timestamp: 100,
449 bytes: 1000,
450 packets: 10,
451 });
452 tracker.get_or_insert_with(&2, || FlowData {
453 timestamp: 200,
454 bytes: 2000,
455 packets: 20,
456 });
457 tracker.get_or_insert_with(&3, || FlowData {
458 timestamp: 300,
459 bytes: 3000,
460 packets: 30,
461 });
462 tracker.get_or_insert_with(&4, || FlowData {
463 timestamp: 400,
464 bytes: 4000,
465 packets: 40,
466 });
467
468 let mut total_bytes_evicted = 0u64;
470 let threshold = 250;
471
472 let evicted = tracker.process_and_evict(|_key, value| {
473 if value.timestamp < threshold {
474 total_bytes_evicted += value.bytes;
475 true } else {
477 false }
479 });
480
481 assert_eq!(evicted, 2);
482 assert_eq!(total_bytes_evicted, 3000); assert_eq!(tracker.len(), 2);
484 }
485
486 #[test]
487 fn test_front_back_access() {
488 let mut tracker = Tracker::<i32, FlowData>::with_capacity(10);
489
490 assert!(tracker.front().is_none());
492 assert!(tracker.back().is_none());
493
494 tracker.get_or_insert_with(&1, || FlowData {
495 timestamp: 100,
496 bytes: 1000,
497 packets: 10,
498 });
499 tracker.get_or_insert_with(&2, || FlowData {
500 timestamp: 200,
501 bytes: 2000,
502 packets: 20,
503 });
504 tracker.get_or_insert_with(&3, || FlowData {
505 timestamp: 300,
506 bytes: 3000,
507 packets: 30,
508 });
509
510 assert_eq!(tracker.front().map(|(k, _)| *k), Some(1));
512 assert_eq!(tracker.front().map(|(_, v)| v.timestamp), Some(100));
513
514 assert_eq!(tracker.back().map(|(k, _)| *k), Some(3));
516 assert_eq!(tracker.back().map(|(_, v)| v.timestamp), Some(300));
517 }
518
519 #[test]
520 fn test_pop_operations() {
521 let mut tracker = Tracker::<i32, FlowData>::with_capacity(10);
522
523 tracker.get_or_insert_with(&1, || FlowData {
524 timestamp: 100,
525 bytes: 1000,
526 packets: 10,
527 });
528 tracker.get_or_insert_with(&2, || FlowData {
529 timestamp: 200,
530 bytes: 2000,
531 packets: 20,
532 });
533 tracker.get_or_insert_with(&3, || FlowData {
534 timestamp: 300,
535 bytes: 3000,
536 packets: 30,
537 });
538
539 let (k, v) = tracker.pop_front().unwrap();
541 assert_eq!(k, 1);
542 assert_eq!(v.timestamp, 100);
543 assert_eq!(tracker.len(), 2);
544
545 let (k, v) = tracker.pop_back().unwrap();
547 assert_eq!(k, 3);
548 assert_eq!(v.timestamp, 300);
549 assert_eq!(tracker.len(), 1);
550
551 assert_eq!(tracker.front().map(|(k, _)| *k), Some(2));
553 }
554
555 #[test]
556 fn test_iterator_methods() {
557 let mut tracker = Tracker::<i32, FlowData>::with_capacity(10);
558
559 tracker.get_or_insert_with(&1, || FlowData {
560 timestamp: 100,
561 bytes: 1000,
562 packets: 10,
563 });
564 tracker.get_or_insert_with(&2, || FlowData {
565 timestamp: 200,
566 bytes: 2000,
567 packets: 20,
568 });
569 tracker.get_or_insert_with(&3, || FlowData {
570 timestamp: 300,
571 bytes: 3000,
572 packets: 30,
573 });
574
575 let keys: Vec<_> = tracker.keys().copied().collect();
577 assert_eq!(keys, vec![1, 2, 3]);
578
579 let bytes: Vec<_> = tracker.values().map(|v| v.bytes).collect();
581 assert_eq!(bytes, vec![1000, 2000, 3000]);
582
583 for value in tracker.values_mut() {
585 value.bytes *= 2;
586 }
587 let bytes: Vec<_> = tracker.values().map(|v| v.bytes).collect();
588 assert_eq!(bytes, vec![2000, 4000, 6000]);
589 }
590
591 #[test]
592 fn test_remove() {
593 let mut tracker = Tracker::<i32, FlowData>::with_capacity(10);
594
595 tracker.get_or_insert_with(&1, || FlowData {
596 timestamp: 100,
597 bytes: 1000,
598 packets: 10,
599 });
600 tracker.get_or_insert_with(&2, || FlowData {
601 timestamp: 200,
602 bytes: 2000,
603 packets: 20,
604 });
605 tracker.get_or_insert_with(&3, || FlowData {
606 timestamp: 300,
607 bytes: 3000,
608 packets: 30,
609 });
610
611 let removed = tracker.remove(&2).unwrap();
613 assert_eq!(removed.bytes, 2000);
614 assert_eq!(tracker.len(), 2);
615
616 let keys: Vec<_> = tracker.keys().copied().collect();
618 assert_eq!(keys, vec![1, 3]);
619
620 assert!(tracker.remove(&99).is_none());
622 }
623
624 #[test]
625 fn test_manual_eviction_pattern() {
626 let mut tracker = Tracker::<i32, FlowData>::with_capacity(10);
627
628 tracker.get_or_insert_with(&1, || FlowData {
629 timestamp: 100,
630 bytes: 1000,
631 packets: 10,
632 });
633 tracker.get_or_insert_with(&2, || FlowData {
634 timestamp: 200,
635 bytes: 2000,
636 packets: 20,
637 });
638 tracker.get_or_insert_with(&3, || FlowData {
639 timestamp: 300,
640 bytes: 3000,
641 packets: 30,
642 });
643 tracker.get_or_insert_with(&4, || FlowData {
644 timestamp: 400,
645 bytes: 4000,
646 packets: 40,
647 });
648
649 let threshold = 250u64;
651 let mut evicted = Vec::new();
652
653 while let Some((_, v)) = tracker.front() {
654 if v.timestamp < threshold {
655 let (k, v) = tracker.pop_front().unwrap();
656 evicted.push((k, v));
657 } else {
658 break;
659 }
660 }
661
662 assert_eq!(evicted.len(), 2);
663 assert_eq!(evicted[0].0, 1);
664 assert_eq!(evicted[1].0, 2);
665 assert_eq!(tracker.len(), 2);
666 }
667}