hashiverse_lib/client/caching/
cache_radius_tracker.rs1use crate::tools::time::{DurationMillis, TimeMillis};
14use crate::tools::tools::LeadingAgreementBits;
15use crate::tools::types::Id;
16use parking_lot::RwLock;
17use std::collections::HashMap;
18
19pub struct CacheRadiusTracker {
25 radii: RwLock<HashMap<Id, (LeadingAgreementBits, TimeMillis)>>,
26 ttl: DurationMillis,
27}
28
29impl CacheRadiusTracker {
30 pub fn new(ttl: DurationMillis) -> Self {
31 Self {
32 radii: RwLock::new(HashMap::new()),
33 ttl,
34 }
35 }
36
37 pub fn get(&self, location_id: Id, now: TimeMillis) -> Option<LeadingAgreementBits> {
39 let radii = self.radii.read();
40 if let Some(&(radius, stored_at)) = radii.get(&location_id) {
41 if (now - stored_at) < self.ttl {
42 return Some(radius);
43 }
44 }
45 None
46 }
47
48 pub fn update(&self, location_id: Id, radius: LeadingAgreementBits, now: TimeMillis) {
50 self.radii.write().insert(location_id, (radius, now));
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57 use crate::tools::time::{DurationMillis, TimeMillis};
58 use crate::tools::types::Id;
59
60 #[test]
61 fn test_get_returns_none_when_empty() {
62 let tracker = CacheRadiusTracker::new(DurationMillis(60_000));
63 let id = Id::random();
64 let now = TimeMillis(1_000_000);
65 assert_eq!(None, tracker.get(id, now));
66 }
67
68 #[test]
69 fn test_update_and_get() {
70 let tracker = CacheRadiusTracker::new(DurationMillis(60_000));
71 let id = Id::random();
72 let now = TimeMillis(1_000_000);
73 tracker.update(id, 10, now);
74 assert_eq!(Some(10), tracker.get(id, now));
75 assert_eq!(Some(10), tracker.get(id, TimeMillis(1_000_000 + 59_999)));
76 }
77
78 #[test]
79 fn test_get_returns_none_after_ttl() {
80 let tracker = CacheRadiusTracker::new(DurationMillis(60_000));
81 let id = Id::random();
82 let now = TimeMillis(1_000_000);
83 tracker.update(id, 10, now);
84 assert_eq!(None, tracker.get(id, TimeMillis(1_000_000 + 60_000)));
85 assert_eq!(None, tracker.get(id, TimeMillis(1_000_000 + 120_000)));
86 }
87
88 #[test]
89 fn test_update_overwrites() {
90 let tracker = CacheRadiusTracker::new(DurationMillis(60_000));
91 let id = Id::random();
92 let now = TimeMillis(1_000_000);
93 tracker.update(id, 10, now);
94 tracker.update(id, 20, now);
95 assert_eq!(Some(20), tracker.get(id, now));
96 }
97
98 #[test]
99 fn test_different_locations_independent() {
100 let tracker = CacheRadiusTracker::new(DurationMillis(60_000));
101 let id1 = Id::random();
102 let id2 = Id::random();
103 let now = TimeMillis(1_000_000);
104 tracker.update(id1, 10, now);
105 assert_eq!(Some(10), tracker.get(id1, now));
106 assert_eq!(None, tracker.get(id2, now));
107 }
108}