feat(client): track and handle late replies after timeout

This commit is contained in:
Nils Andreas Svee committed 2026-05-10 20:56:43 +07:00
1 parent f41f63b922
commit ab951a440a
3 files changed
+215 -8

No files matched your search

+70
View File
@@ -69,6 +69,62 @@ impl PendingMap {
}
}
#[derive(Debug)]
pub(crate) struct TimedOutMap {
map: HashMap<u32, PendingProbe>,
insertion_order: VecDeque<u32>,
max_capacity: usize,
}
impl TimedOutMap {
pub fn new(max_capacity: usize) -> Self {
Self {
map: HashMap::new(),
insertion_order: VecDeque::new(),
max_capacity,
}
}
pub fn insert(&mut self, probe: PendingProbe) {
if self.max_capacity == 0 {
return;
}
if let std::collections::hash_map::Entry::Occupied(mut entry) =
self.map.entry(probe.wire_seq)
{
entry.insert(probe);
return;
}
while self.map.len() >= self.max_capacity {
self.evict_oldest();
}
self.insertion_order.push_back(probe.wire_seq);
self.map.insert(probe.wire_seq, probe);
}
pub fn remove(&mut self, wire_seq: u32) -> Option<PendingProbe> {
self.map.remove(&wire_seq)
}
pub fn clear(&mut self) {
self.map.clear();
self.insertion_order.clear();
}
#[allow(dead_code)]
pub fn len(&self) -> usize {
self.map.len()
}
fn evict_oldest(&mut self) {
while let Some(oldest_key) = self.insertion_order.pop_front() {
if self.map.remove(&oldest_key).is_some() {
break;
}
}
}
}
#[derive(Debug)]
pub(crate) struct CompletedSet {
set: HashMap<u32, u64>,
@@ -187,4 +243,18 @@ mod tests {
assert!(!set.contains(0));
assert!(set.contains(3));
}
#[test]
fn timed_out_map_tracks_and_evicts() {
let mut map = TimedOutMap::new(2);
let now = Instant::now();
map.insert(pending(0, 0, now));
map.insert(pending(1, 1, now));
map.insert(pending(2, 2, now));
assert_eq!(map.len(), 2);
assert!(map.remove(0).is_none());
assert!(map.remove(1).is_some());
assert!(map.remove(2).is_some());
}
}