1use crate::tree::TreeCoordinate;
4
5#[derive(Clone, Debug)]
7pub struct CacheEntry {
8 coords: TreeCoordinate,
10 created_at: u64,
12 last_used: u64,
14 expires_at: u64,
16 path_mtu: Option<u16>,
22}
23
24impl CacheEntry {
25 pub fn new(coords: TreeCoordinate, current_time_ms: u64, ttl_ms: u64) -> Self {
27 Self {
28 coords,
29 created_at: current_time_ms,
30 last_used: current_time_ms,
31 expires_at: current_time_ms.saturating_add(ttl_ms),
32 path_mtu: None,
33 }
34 }
35
36 pub fn coords(&self) -> &TreeCoordinate {
38 &self.coords
39 }
40
41 pub fn created_at(&self) -> u64 {
43 self.created_at
44 }
45
46 pub fn last_used(&self) -> u64 {
48 self.last_used
49 }
50
51 pub fn expires_at(&self) -> u64 {
53 self.expires_at
54 }
55
56 pub fn path_mtu(&self) -> Option<u16> {
58 self.path_mtu
59 }
60
61 pub fn set_path_mtu(&mut self, mtu: u16) {
63 self.path_mtu = Some(mtu);
64 }
65
66 pub fn is_expired(&self, current_time_ms: u64) -> bool {
68 current_time_ms > self.expires_at
69 }
70
71 pub fn touch(&mut self, current_time_ms: u64) {
73 self.last_used = current_time_ms;
74 }
75
76 pub fn refresh(&mut self, current_time_ms: u64, ttl_ms: u64) {
78 self.expires_at = current_time_ms.saturating_add(ttl_ms);
79 self.last_used = current_time_ms;
80 }
81
82 pub fn update(&mut self, coords: TreeCoordinate, current_time_ms: u64, ttl_ms: u64) {
84 self.coords = coords;
85 self.last_used = current_time_ms;
86 self.expires_at = current_time_ms.saturating_add(ttl_ms);
87 }
88
89 pub fn idle_time(&self, current_time_ms: u64) -> u64 {
91 current_time_ms.saturating_sub(self.last_used)
92 }
93
94 pub fn age(&self, current_time_ms: u64) -> u64 {
96 current_time_ms.saturating_sub(self.created_at)
97 }
98
99 pub fn time_to_expiry(&self, current_time_ms: u64) -> u64 {
101 self.expires_at.saturating_sub(current_time_ms)
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108 use crate::NodeAddr;
109
110 fn make_node_addr(val: u8) -> NodeAddr {
111 let mut bytes = [0u8; 16];
112 bytes[0] = val;
113 NodeAddr::from_bytes(bytes)
114 }
115
116 fn make_coords(ids: &[u8]) -> TreeCoordinate {
117 TreeCoordinate::from_addrs(ids.iter().map(|&v| make_node_addr(v)).collect()).unwrap()
118 }
119
120 #[test]
121 fn test_cache_entry_expiry() {
122 let coords = make_coords(&[1, 0]);
123 let entry = CacheEntry::new(coords, 1000, 500);
124
125 assert!(!entry.is_expired(1000));
126 assert!(!entry.is_expired(1500)); assert!(entry.is_expired(1501)); assert!(entry.is_expired(2000));
129 }
130
131 #[test]
132 fn test_cache_entry_refresh() {
133 let coords = make_coords(&[1, 0]);
134 let mut entry = CacheEntry::new(coords, 1000, 500);
135
136 assert!(entry.is_expired(1501)); entry.refresh(1400, 500); assert!(!entry.is_expired(1600));
141 assert!(!entry.is_expired(1900)); assert!(entry.is_expired(1901)); }
144
145 #[test]
146 fn test_cache_entry_times() {
147 let coords = make_coords(&[1, 0]);
148 let entry = CacheEntry::new(coords, 1000, 500);
149
150 assert_eq!(entry.created_at(), 1000);
151 assert_eq!(entry.last_used(), 1000);
152 assert_eq!(entry.expires_at(), 1500);
153 assert_eq!(entry.age(1200), 200);
154 assert_eq!(entry.idle_time(1200), 200);
155 assert_eq!(entry.time_to_expiry(1200), 300);
156 assert_eq!(entry.time_to_expiry(1600), 0);
157 }
158
159 #[test]
160 fn test_cache_entry_touch() {
161 let coords = make_coords(&[1, 0]);
162 let mut entry = CacheEntry::new(coords, 1000, 500);
163
164 assert_eq!(entry.last_used(), 1000);
165 entry.touch(1300);
166 assert_eq!(entry.last_used(), 1300);
167 assert_eq!(entry.expires_at(), 1500);
169 }
170
171 #[test]
172 fn test_cache_entry_update() {
173 let mut entry = CacheEntry::new(make_coords(&[1, 0]), 1000, 500);
174
175 let new_coords = make_coords(&[1, 2, 0]);
176 entry.update(new_coords.clone(), 2000, 600);
177
178 assert_eq!(entry.coords(), &new_coords);
179 assert_eq!(entry.last_used(), 2000);
180 assert_eq!(entry.expires_at(), 2600);
181 assert_eq!(entry.created_at(), 1000);
183 }
184
185 #[test]
186 fn test_cache_entry_saturating_add() {
187 let coords = make_coords(&[1, 0]);
188 let entry = CacheEntry::new(coords, u64::MAX - 10, 100);
189
190 assert_eq!(entry.expires_at(), u64::MAX);
192 }
193}