refactor: remove logical_seq from client events, session tracking and stats usage
It was an attempt at handling integer wraparound more cleanly keeping in mind that we have a continuous mode, and so we can more easily reach seq > u32::MAX However after running the numbers, if we run with a interval of 10ms, it's still gonna take ~497 days before we hit integer overflow, so for now it doesn't seem worth to have this extra logic to handle something that'll in 99.9% of cases be purely an edge case Keeping in mind autorate usage, in sqm-autorate-rust each send loop is 500 ms by default, and the sleep is then 500 ms / 5 reflectors, so our interval is 100 ms. that means it'll take 4970 days or ~13.6 years to reach the limit. Not worth dealing with IMO
This commit was merged in pull request #11.
This commit is contained in:
1 parent
8ef53c999a
commit
7ad83ca1f6
13 files changed
+117
-273
No files matched your search
@@ -210,7 +210,6 @@ impl Client {
|
||||
.expect("negotiated must exist when Open");
|
||||
|
||||
let wire_seq = session.next_wire_seq;
|
||||
let logical_seq = session.next_logical_seq;
|
||||
let scheduled_at = session.next_send_at;
|
||||
|
||||
let request = EchoRequest {
|
||||
@@ -232,7 +231,6 @@ impl Client {
|
||||
.expect("session must exist when phase is Open");
|
||||
|
||||
let pending = PendingProbe {
|
||||
logical_seq,
|
||||
wire_seq,
|
||||
sent_at,
|
||||
timeout_at: sent_at
|
||||
@@ -243,13 +241,6 @@ impl Client {
|
||||
session.pending.insert(pending)?;
|
||||
|
||||
session.next_wire_seq = session.next_wire_seq.wrapping_add(1);
|
||||
session.next_logical_seq =
|
||||
session
|
||||
.next_logical_seq
|
||||
.checked_add(1)
|
||||
.ok_or(ClientError::CounterOverflow {
|
||||
counter: "next_logical_seq",
|
||||
})?;
|
||||
session.packets_sent =
|
||||
session
|
||||
.packets_sent
|
||||
@@ -279,7 +270,6 @@ impl Client {
|
||||
|
||||
Ok(vec![ClientEvent::EchoSent {
|
||||
seq: wire_seq,
|
||||
logical_seq,
|
||||
remote: self.remote,
|
||||
scheduled_at,
|
||||
sent_at,
|
||||
@@ -372,7 +362,6 @@ impl Client {
|
||||
for probe in expired {
|
||||
events.push(ClientEvent::EchoLoss {
|
||||
seq: probe.wire_seq,
|
||||
logical_seq: probe.logical_seq,
|
||||
sent_at: probe.sent_at,
|
||||
timeout_at: probe.timeout_at,
|
||||
});
|
||||
@@ -468,13 +457,12 @@ impl Client {
|
||||
let highest_seen = session.highest_received_seq.unwrap_or(wire_seq);
|
||||
|
||||
update_highest_received(session, wire_seq);
|
||||
session.completed.insert(wire_seq, pending.logical_seq);
|
||||
session.completed.insert(wire_seq);
|
||||
|
||||
let mut events = Vec::new();
|
||||
if is_late {
|
||||
events.push(ClientEvent::LateReply {
|
||||
seq: wire_seq,
|
||||
logical_seq: Some(pending.logical_seq),
|
||||
highest_seen,
|
||||
remote: self.remote,
|
||||
sent_at: Some(pending.sent_at),
|
||||
@@ -489,7 +477,6 @@ impl Client {
|
||||
} else {
|
||||
events.push(ClientEvent::EchoReply {
|
||||
seq: wire_seq,
|
||||
logical_seq: pending.logical_seq,
|
||||
remote: self.remote,
|
||||
sent_at: pending.sent_at,
|
||||
received_at: now,
|
||||
@@ -520,11 +507,10 @@ impl Client {
|
||||
let received_stats = build_received_stats(&reply);
|
||||
let highest_seen = session.highest_received_seq.unwrap_or(wire_seq);
|
||||
update_highest_received(session, wire_seq);
|
||||
session.completed.insert(wire_seq, timed_out.logical_seq);
|
||||
session.completed.insert(wire_seq);
|
||||
|
||||
let mut events = vec![ClientEvent::LateReply {
|
||||
seq: wire_seq,
|
||||
logical_seq: Some(timed_out.logical_seq),
|
||||
highest_seen,
|
||||
remote: self.remote,
|
||||
sent_at: Some(timed_out.sent_at),
|
||||
@@ -546,7 +532,6 @@ impl Client {
|
||||
{
|
||||
Ok(vec![ClientEvent::LateReply {
|
||||
seq: wire_seq,
|
||||
logical_seq: None,
|
||||
highest_seen: session.highest_received_seq.unwrap(),
|
||||
remote: self.remote,
|
||||
sent_at: None,
|
||||
@@ -648,7 +633,6 @@ impl Client {
|
||||
|
||||
self.session = Some(ActiveSession {
|
||||
next_wire_seq: 0,
|
||||
next_logical_seq: 0,
|
||||
highest_received_seq: None,
|
||||
packets_sent: 0,
|
||||
start_mono: now.mono,
|
||||
|
||||
@@ -43,14 +43,9 @@ fn send_probe_sends_valid_echo_request() {
|
||||
assert_eq!(events.len(), 1);
|
||||
match &events[0] {
|
||||
ClientEvent::EchoSent {
|
||||
seq,
|
||||
logical_seq,
|
||||
remote,
|
||||
bytes,
|
||||
..
|
||||
seq, remote, bytes, ..
|
||||
} => {
|
||||
assert_eq!(*seq, 0);
|
||||
assert_eq!(*logical_seq, 0);
|
||||
assert_eq!(*remote, server.addr);
|
||||
assert_eq!(*bytes, echo_packet_len(false, ¶ms));
|
||||
}
|
||||
@@ -311,30 +306,6 @@ fn send_probe_reports_schedule_overflow() {
|
||||
server.join();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_probe_reports_logical_sequence_counter_overflow() {
|
||||
let params = default_params();
|
||||
let server = silent_open_server(params);
|
||||
let config = ClientConfig {
|
||||
socket_config: crate::SocketConfig {
|
||||
recv_timeout: Some(Duration::from_millis(200)),
|
||||
..Default::default()
|
||||
},
|
||||
..default_test_config(server.addr)
|
||||
};
|
||||
let mut client = Client::connect(config).unwrap();
|
||||
assert_open_started(client.open().unwrap());
|
||||
client.session.as_mut().unwrap().next_logical_seq = u64::MAX;
|
||||
|
||||
assert!(matches!(
|
||||
client.send_probe(),
|
||||
Err(ClientError::CounterOverflow {
|
||||
counter: "next_logical_seq"
|
||||
})
|
||||
));
|
||||
server.join();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_probe_reports_packets_sent_counter_overflow() {
|
||||
let params = default_params();
|
||||
@@ -390,7 +361,6 @@ fn recv_once_decodes_echo_reply_and_emits_event() {
|
||||
match &events[0] {
|
||||
ClientEvent::EchoReply {
|
||||
seq,
|
||||
logical_seq,
|
||||
rtt,
|
||||
received_stats,
|
||||
server_timing,
|
||||
@@ -399,7 +369,6 @@ fn recv_once_decodes_echo_reply_and_emits_event() {
|
||||
..
|
||||
} => {
|
||||
assert_eq!(*seq, 0);
|
||||
assert_eq!(*logical_seq, 0);
|
||||
assert_eq!(*bytes, echo_packet_len(false, ¶ms));
|
||||
assert!(rtt.raw > Duration::ZERO);
|
||||
assert_eq!(rtt.effective, rtt.adjusted.unwrap_or(rtt.raw));
|
||||
@@ -487,14 +456,8 @@ fn recv_once_decodes_only_received_bytes_after_longer_datagram() {
|
||||
let events = client.recv_once().unwrap();
|
||||
assert_eq!(events.len(), 1);
|
||||
match &events[0] {
|
||||
ClientEvent::EchoReply {
|
||||
seq,
|
||||
logical_seq,
|
||||
bytes,
|
||||
..
|
||||
} => {
|
||||
ClientEvent::EchoReply { seq, bytes, .. } => {
|
||||
assert_eq!(*seq, 1);
|
||||
assert_eq!(*logical_seq, 1);
|
||||
assert_eq!(*bytes, echo_packet_len(false, ¶ms));
|
||||
}
|
||||
other => panic!("expected EchoReply after shorter datagram, got {other:?}"),
|
||||
@@ -980,7 +943,6 @@ fn late_reply_after_timeout_preserves_measurement_metadata() {
|
||||
match &late[0] {
|
||||
ClientEvent::LateReply {
|
||||
seq,
|
||||
logical_seq,
|
||||
sent_at,
|
||||
rtt,
|
||||
server_timing,
|
||||
@@ -990,7 +952,6 @@ fn late_reply_after_timeout_preserves_measurement_metadata() {
|
||||
..
|
||||
} => {
|
||||
assert_eq!(*seq, 0);
|
||||
assert_eq!(*logical_seq, Some(0));
|
||||
assert!(sent_at.is_some());
|
||||
assert!(rtt.is_some());
|
||||
assert!(server_timing.is_some());
|
||||
@@ -1758,7 +1719,6 @@ fn send_probe_wraps_wire_sequence_at_u32_max() {
|
||||
|
||||
let session = client.session.as_mut().unwrap();
|
||||
session.next_wire_seq = u32::MAX;
|
||||
session.next_logical_seq = 41;
|
||||
|
||||
client.send_probe().unwrap();
|
||||
client.send_probe().unwrap();
|
||||
@@ -1814,7 +1774,6 @@ fn wrapped_reply_after_u32_max_is_not_late() {
|
||||
assert_open_started(client.open().unwrap());
|
||||
let session = client.session.as_mut().unwrap();
|
||||
session.next_wire_seq = u32::MAX;
|
||||
session.next_logical_seq = 41;
|
||||
|
||||
client.send_probe().unwrap();
|
||||
client.send_probe().unwrap();
|
||||
|
||||
@@ -26,7 +26,6 @@ fn sequence_ordering_handles_normal_and_wrapped_values() {
|
||||
fn highest_received_seq_updates_across_wrap() {
|
||||
let mut session = ActiveSession {
|
||||
next_wire_seq: 0,
|
||||
next_logical_seq: 0,
|
||||
highest_received_seq: Some(u32::MAX),
|
||||
packets_sent: 0,
|
||||
start_mono: Instant::now(),
|
||||
|
||||
@@ -41,7 +41,6 @@ pub enum ClientEvent {
|
||||
|
||||
EchoSent {
|
||||
seq: u32,
|
||||
logical_seq: u64,
|
||||
remote: SocketAddr,
|
||||
scheduled_at: Instant,
|
||||
sent_at: ClientTimestamp,
|
||||
@@ -52,7 +51,6 @@ pub enum ClientEvent {
|
||||
|
||||
EchoReply {
|
||||
seq: u32,
|
||||
logical_seq: u64,
|
||||
remote: SocketAddr,
|
||||
sent_at: ClientTimestamp,
|
||||
received_at: ClientTimestamp,
|
||||
@@ -66,7 +64,6 @@ pub enum ClientEvent {
|
||||
|
||||
EchoLoss {
|
||||
seq: u32,
|
||||
logical_seq: u64,
|
||||
sent_at: ClientTimestamp,
|
||||
timeout_at: std::time::Instant,
|
||||
},
|
||||
@@ -80,7 +77,6 @@ pub enum ClientEvent {
|
||||
|
||||
LateReply {
|
||||
seq: u32,
|
||||
logical_seq: Option<u64>,
|
||||
highest_seen: u32,
|
||||
remote: SocketAddr,
|
||||
sent_at: Option<ClientTimestamp>,
|
||||
|
||||
@@ -594,19 +594,13 @@ mod tests {
|
||||
server.join();
|
||||
|
||||
assert_eq!(outcome.end_reason, SessionEndReason::TestComplete);
|
||||
assert!(events.iter().any(|event| matches!(
|
||||
event,
|
||||
ClientEvent::EchoLoss {
|
||||
seq: 0,
|
||||
logical_seq: 0,
|
||||
..
|
||||
}
|
||||
)));
|
||||
assert!(events
|
||||
.iter()
|
||||
.any(|event| matches!(event, ClientEvent::EchoLoss { seq: 0, .. })));
|
||||
assert!(events.iter().any(|event| matches!(
|
||||
event,
|
||||
ClientEvent::LateReply {
|
||||
seq: 0,
|
||||
logical_seq: Some(0),
|
||||
sent_at: Some(_),
|
||||
rtt: Some(_),
|
||||
..
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::{
|
||||
collections::{HashMap, VecDeque},
|
||||
collections::{HashMap, HashSet, VecDeque},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
@@ -7,7 +7,6 @@ use crate::{error::ClientError, timing::ClientTimestamp};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct PendingProbe {
|
||||
pub logical_seq: u64,
|
||||
pub wire_seq: u32,
|
||||
pub sent_at: ClientTimestamp,
|
||||
pub timeout_at: Instant,
|
||||
@@ -59,7 +58,7 @@ impl PendingMap {
|
||||
expired.push(probe);
|
||||
}
|
||||
}
|
||||
expired.sort_by_key(|p| p.logical_seq);
|
||||
expired.sort_by_key(|p| p.sent_at.mono);
|
||||
expired
|
||||
}
|
||||
|
||||
@@ -134,7 +133,7 @@ impl TimedOutMap {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CompletedSet {
|
||||
set: HashMap<u32, u64>,
|
||||
set: HashSet<u32>,
|
||||
insertion_order: VecDeque<u32>,
|
||||
max_capacity: usize,
|
||||
}
|
||||
@@ -142,31 +141,32 @@ pub(crate) struct CompletedSet {
|
||||
impl CompletedSet {
|
||||
pub fn new(max_capacity: usize) -> Self {
|
||||
Self {
|
||||
set: HashMap::new(),
|
||||
set: HashSet::new(),
|
||||
insertion_order: VecDeque::new(),
|
||||
max_capacity,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, wire_seq: u32, logical_seq: u64) {
|
||||
if let Some(existing) = self.set.get_mut(&wire_seq) {
|
||||
*existing = logical_seq;
|
||||
pub fn insert(&mut self, seq: u32) {
|
||||
if self.set.contains(&seq) {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.set.len() >= self.max_capacity {
|
||||
self.evict_oldest();
|
||||
}
|
||||
self.insertion_order.push_back(wire_seq);
|
||||
self.set.insert(wire_seq, logical_seq);
|
||||
|
||||
self.insertion_order.push_back(seq);
|
||||
self.set.insert(seq);
|
||||
}
|
||||
|
||||
pub fn contains(&self, wire_seq: u32) -> bool {
|
||||
self.set.contains_key(&wire_seq)
|
||||
pub fn contains(&self, seq: u32) -> bool {
|
||||
self.set.contains(&seq)
|
||||
}
|
||||
|
||||
fn evict_oldest(&mut self) {
|
||||
while let Some(oldest_key) = self.insertion_order.pop_front() {
|
||||
if self.set.remove(&oldest_key).is_some() {
|
||||
while let Some(oldest_seq) = self.insertion_order.pop_front() {
|
||||
if self.set.remove(&oldest_seq) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -185,9 +185,8 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn pending(seq: u32, logical: u64, timeout_at: Instant) -> PendingProbe {
|
||||
fn pending(seq: u32, timeout_at: Instant) -> PendingProbe {
|
||||
PendingProbe {
|
||||
logical_seq: logical,
|
||||
wire_seq: seq,
|
||||
sent_at: ts(timeout_at - Duration::from_secs(1)),
|
||||
timeout_at,
|
||||
@@ -198,7 +197,7 @@ mod tests {
|
||||
fn pending_map_insert_and_remove() {
|
||||
let mut map = PendingMap::new(10);
|
||||
let now = Instant::now();
|
||||
let probe = pending(0, 0, now + Duration::from_secs(4));
|
||||
let probe = pending(0, now + Duration::from_secs(4));
|
||||
map.insert(probe).unwrap();
|
||||
assert_eq!(map.len(), 1);
|
||||
assert!(map.remove(0).is_some());
|
||||
@@ -210,42 +209,26 @@ mod tests {
|
||||
fn pending_map_rejects_over_capacity() {
|
||||
let mut map = PendingMap::new(2);
|
||||
let now = Instant::now();
|
||||
map.insert(pending(0, 0, now + Duration::from_secs(4)))
|
||||
map.insert(pending(0, now + Duration::from_secs(4)))
|
||||
.unwrap();
|
||||
map.insert(pending(1, 1, now + Duration::from_secs(4)))
|
||||
map.insert(pending(1, now + Duration::from_secs(4)))
|
||||
.unwrap();
|
||||
assert!(matches!(
|
||||
map.insert(pending(2, 2, now + Duration::from_secs(4))),
|
||||
map.insert(pending(2, now + Duration::from_secs(4))),
|
||||
Err(ClientError::PendingLimitExceeded { limit: 2 })
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drain_expired_returns_in_logical_order() {
|
||||
let mut map = PendingMap::new(10);
|
||||
let now = Instant::now();
|
||||
let past = now - Duration::from_secs(1);
|
||||
map.insert(pending(5, 5, past)).unwrap();
|
||||
map.insert(pending(2, 2, past)).unwrap();
|
||||
map.insert(pending(8, 8, now + Duration::from_secs(10)))
|
||||
.unwrap();
|
||||
let expired = map.drain_expired(now);
|
||||
assert_eq!(expired.len(), 2);
|
||||
assert_eq!(expired[0].wire_seq, 2);
|
||||
assert_eq!(expired[1].wire_seq, 5);
|
||||
assert_eq!(map.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completed_set_tracks_and_evicts() {
|
||||
let mut set = CompletedSet::new(3);
|
||||
set.insert(0, 0);
|
||||
set.insert(1, 1);
|
||||
set.insert(2, 2);
|
||||
set.insert(0);
|
||||
set.insert(1);
|
||||
set.insert(2);
|
||||
assert!(set.contains(0));
|
||||
assert!(set.contains(1));
|
||||
assert!(set.contains(2));
|
||||
set.insert(3, 3);
|
||||
set.insert(3);
|
||||
assert_eq!(set.set.len(), 3);
|
||||
assert!(!set.contains(0));
|
||||
assert!(set.contains(3));
|
||||
@@ -255,9 +238,9 @@ mod tests {
|
||||
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));
|
||||
map.insert(pending(0, now));
|
||||
map.insert(pending(1, now));
|
||||
map.insert(pending(2, now));
|
||||
|
||||
assert_eq!(map.len(), 2);
|
||||
assert!(map.remove(0).is_none());
|
||||
@@ -271,7 +254,7 @@ mod tests {
|
||||
let now = Instant::now();
|
||||
|
||||
for i in 0..20 {
|
||||
map.insert(pending(i, u64::from(i), now));
|
||||
map.insert(pending(i, now));
|
||||
assert!(map.remove(i).is_some());
|
||||
assert_eq!(map.len(), 0);
|
||||
assert_eq!(map.insertion_order_len(), 0);
|
||||
|
||||
@@ -24,7 +24,6 @@ pub(crate) enum ClientPhase {
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ActiveSession {
|
||||
pub next_wire_seq: u32,
|
||||
pub next_logical_seq: u64,
|
||||
pub highest_received_seq: Option<u32>,
|
||||
pub packets_sent: u64,
|
||||
pub start_mono: Instant,
|
||||
|
||||
Reference in new issue
Block a user