From 1a04f44bb5d56bfacb7fb400d5f543258b45b384 Mon Sep 17 00:00:00 2001 From: Nils Andreas Svee Date: Mon, 11 May 2026 09:33:55 +0700 Subject: [PATCH] refactor(client): remove redundant timestamp parameter from poll_timeouts Use internal monotonic time by default and introduce poll_timeouts_at for callers requiring a specific sampled Instant. This simplifies the API for standard usage while maintaining flexibility for external event loops. --- crates/irtt-cli/src/main.rs | 12 ++++++++---- crates/irtt-client/src/client.rs | 16 ++++++++++++++-- crates/irtt-client/src/client/tests/close.rs | 2 +- .../src/client/tests/probes_replies.rs | 14 +++++++------- crates/irtt-client/src/managed/runner.rs | 15 +++------------ crates/irtt-client/tests/hmac.rs | 2 +- crates/irtt-client/tests/large_packets.rs | 2 +- crates/irtt-client/tests/protocol_options.rs | 1 - crates/irtt-client/tests/server_fill.rs | 2 +- crates/irtt-client/tests/support/mod.rs | 2 +- 10 files changed, 37 insertions(+), 31 deletions(-) diff --git a/crates/irtt-cli/src/main.rs b/crates/irtt-cli/src/main.rs index fc015e4..829ced5 100644 --- a/crates/irtt-cli/src/main.rs +++ b/crates/irtt-cli/src/main.rs @@ -13,7 +13,11 @@ use clap::Parser; use irtt_cli::{ format_event, format_human_event_with_options, CliArgs, HumanOutputOptions, OutputMode, }; -use irtt_client::{Client, ClientEvent, ClientTimestamp, OpenOutcome, RecvBudget}; +use irtt_client::{Client, ClientEvent, OpenOutcome, RecvBudget}; + +#[cfg(test)] +use irtt_client::ClientTimestamp; + #[cfg(feature = "stats")] use irtt_stats::{StatsCollector, StatsConfig}; @@ -85,7 +89,7 @@ fn run(args: CliArgs, shutdown_requested: &AtomicBool) -> Result<(), Box Result<(), Box( printed |= !events.is_empty(); output.print_events(&events)?; - let events = client.poll_timeouts(ClientTimestamp::now())?; + let events = client.poll_timeouts()?; printed |= !events.is_empty(); output.print_events(&events)?; diff --git a/crates/irtt-client/src/client.rs b/crates/irtt-client/src/client.rs index ddbbe17..4d54fb4 100644 --- a/crates/irtt-client/src/client.rs +++ b/crates/irtt-client/src/client.rs @@ -341,7 +341,19 @@ impl Client { recv_buffer_size(self.config.hmac_key.is_some(), self.negotiated.as_ref()) } - pub fn poll_timeouts(&mut self, now: ClientTimestamp) -> Result, ClientError> { + /// Polls for probes that have timed out as of the current monotonic time. + pub fn poll_timeouts(&mut self) -> Result, ClientError> { + self.poll_timeouts_at(Instant::now()) + } + + /// Polls for probes that have timed out as of `now`. + /// + /// This is useful for callers that drive `Client` from their own event loop and + /// want timeout decisions to use the same sampled `Instant` as their scheduling + /// logic. + /// + /// `now` is monotonic time only; wall-clock time is not used for timeout expiry. + pub fn poll_timeouts_at(&mut self, now: Instant) -> Result, ClientError> { match self.phase { ClientPhase::Open { .. } => {} ClientPhase::Closed => return Err(ClientError::AlreadyClosed), @@ -354,7 +366,7 @@ impl Client { .as_mut() .expect("session must exist when phase is Open"); - let expired = session.pending.drain_expired(now.mono); + let expired = session.pending.drain_expired(now); let mut events = Vec::with_capacity(expired.len()); for probe in expired { events.push(ClientEvent::EchoLoss { diff --git a/crates/irtt-client/src/client/tests/close.rs b/crates/irtt-client/src/client/tests/close.rs index 072dcc4..0727728 100644 --- a/crates/irtt-client/src/client/tests/close.rs +++ b/crates/irtt-client/src/client/tests/close.rs @@ -85,7 +85,7 @@ fn close_clears_timed_out_metadata() { client.send_probe().unwrap(); thread::sleep(Duration::from_millis(60)); - client.poll_timeouts(ClientTimestamp::now()).unwrap(); + client.poll_timeouts().unwrap(); assert_eq!(client.session.as_ref().unwrap().timed_out.len(), 1); client.close().unwrap(); diff --git a/crates/irtt-client/src/client/tests/probes_replies.rs b/crates/irtt-client/src/client/tests/probes_replies.rs index 6de2716..135e11c 100644 --- a/crates/irtt-client/src/client/tests/probes_replies.rs +++ b/crates/irtt-client/src/client/tests/probes_replies.rs @@ -896,11 +896,11 @@ fn poll_timeouts_emits_echo_loss() { client.send_probe().unwrap(); client.send_probe().unwrap(); - let no_loss = client.poll_timeouts(ClientTimestamp::now()).unwrap(); + let no_loss = client.poll_timeouts().unwrap(); assert!(no_loss.is_empty()); thread::sleep(Duration::from_millis(150)); - let events = client.poll_timeouts(ClientTimestamp::now()).unwrap(); + let events = client.poll_timeouts().unwrap(); assert_eq!(events.len(), 2); for event in &events { assert!(matches!(event, ClientEvent::EchoLoss { .. })); @@ -925,7 +925,7 @@ fn poll_timeouts_removes_expired_pending() { client.send_probe().unwrap(); thread::sleep(Duration::from_millis(150)); - client.poll_timeouts(ClientTimestamp::now()).unwrap(); + client.poll_timeouts().unwrap(); let session = client.session.as_ref().unwrap(); assert_eq!(session.pending.len(), 0); @@ -971,7 +971,7 @@ fn late_reply_after_timeout_preserves_measurement_metadata() { client.send_probe().unwrap(); thread::sleep(Duration::from_millis(60)); - let losses = client.poll_timeouts(ClientTimestamp::now()).unwrap(); + let losses = client.poll_timeouts().unwrap(); assert!(matches!(&losses[0], ClientEvent::EchoLoss { seq: 0, .. })); assert_eq!(client.session.as_ref().unwrap().pending.len(), 0); assert_eq!(client.session.as_ref().unwrap().timed_out.len(), 1); @@ -1050,7 +1050,7 @@ fn late_reply_metadata_is_unavailable_without_ancillary() { client.send_probe().unwrap(); thread::sleep(Duration::from_millis(60)); - let losses = client.poll_timeouts(ClientTimestamp::now()).unwrap(); + let losses = client.poll_timeouts().unwrap(); assert!(matches!(&losses[0], ClientEvent::EchoLoss { seq: 0, .. })); let late = client.recv_once().unwrap(); @@ -1099,7 +1099,7 @@ fn late_reply_metadata_propagates_observed_dscp_with_ancillary() { client.send_probe().unwrap(); thread::sleep(Duration::from_millis(60)); - let losses = client.poll_timeouts(ClientTimestamp::now()).unwrap(); + let losses = client.poll_timeouts().unwrap(); assert!(matches!(&losses[0], ClientEvent::EchoLoss { seq: 0, .. })); let events = client.recv_once().unwrap(); @@ -1617,7 +1617,7 @@ fn process_received_packet_uses_supplied_receive_metadata_for_late_reply() { client.send_probe_at(ClientTimestamp::now()).unwrap(); thread::sleep(Duration::from_millis(60)); - let losses = client.poll_timeouts(ClientTimestamp::now()).unwrap(); + let losses = client.poll_timeouts().unwrap(); assert!(matches!(&losses[0], ClientEvent::EchoLoss { seq: 0, .. })); let recv_ts = ClientTimestamp::now(); diff --git a/crates/irtt-client/src/managed/runner.rs b/crates/irtt-client/src/managed/runner.rs index bc50650..bf7c448 100644 --- a/crates/irtt-client/src/managed/runner.rs +++ b/crates/irtt-client/src/managed/runner.rs @@ -7,7 +7,6 @@ use crate::{ config::{ClientConfig, RecvBudget}, error::ClientError, event::{ClientEvent, OpenOutcome}, - timing::ClientTimestamp, Client, }; @@ -182,11 +181,7 @@ fn run_client( &mut counters, client.recv_available(MANAGED_RECV_BUDGET)?, ); - publish_events( - &hub, - &mut counters, - client.poll_timeouts(ClientTimestamp::now())?, - ); + publish_events(&hub, &mut counters, client.poll_timeouts()?); break; } @@ -205,11 +200,7 @@ fn run_client( &mut counters, client.recv_available(MANAGED_RECV_BUDGET)?, ); - publish_events( - &hub, - &mut counters, - client.poll_timeouts(ClientTimestamp::now())?, - ); + publish_events(&hub, &mut counters, client.poll_timeouts()?); if client.is_run_complete() { break; @@ -267,7 +258,7 @@ fn drain_final_late_replies( published |= !events.is_empty(); publish_events(hub, counters, events); - let events = client.poll_timeouts(ClientTimestamp::now())?; + let events = client.poll_timeouts()?; published |= !events.is_empty(); publish_events(hub, counters, events); diff --git a/crates/irtt-client/tests/hmac.rs b/crates/irtt-client/tests/hmac.rs index 92980f7..82ec260 100644 --- a/crates/irtt-client/tests/hmac.rs +++ b/crates/irtt-client/tests/hmac.rs @@ -3,7 +3,7 @@ mod support; use std::time::Duration; use irtt_client::{ - Client, ClientConfig, ClientError, ClientEvent, ClientTimestamp, OpenOutcome, SocketConfig, + Client, ClientConfig, ClientError, ClientEvent, OpenOutcome, SocketConfig, WarningKind, }; use irtt_proto::{echo_packet_len, ProtoError, TimestampFields}; diff --git a/crates/irtt-client/tests/large_packets.rs b/crates/irtt-client/tests/large_packets.rs index 32e9517..aa06109 100644 --- a/crates/irtt-client/tests/large_packets.rs +++ b/crates/irtt-client/tests/large_packets.rs @@ -1,6 +1,6 @@ mod support; -use irtt_client::{Client, ClientConfig, ClientEvent, ClientTimestamp, NegotiationPolicy}; +use irtt_client::{Client, ClientConfig, ClientEvent, NegotiationPolicy}; use irtt_proto::{echo_header_len, echo_packet_len, Params, TimestampFields}; use support::{config_for_params, default_params, run_one_probe, BackendPeer, ServerObservation}; diff --git a/crates/irtt-client/tests/protocol_options.rs b/crates/irtt-client/tests/protocol_options.rs index b2bad84..e1c738e 100644 --- a/crates/irtt-client/tests/protocol_options.rs +++ b/crates/irtt-client/tests/protocol_options.rs @@ -1,6 +1,5 @@ mod support; -use irtt_client::ClientTimestamp; use std::time::Duration; use irtt_client::{ diff --git a/crates/irtt-client/tests/server_fill.rs b/crates/irtt-client/tests/server_fill.rs index af9c1c3..089e594 100644 --- a/crates/irtt-client/tests/server_fill.rs +++ b/crates/irtt-client/tests/server_fill.rs @@ -1,7 +1,7 @@ mod support; use irtt_client::{ - Client, ClientConfig, ClientError, ClientEvent, ClientTimestamp, NegotiationPolicy, + Client, ClientConfig, ClientError, ClientEvent, NegotiationPolicy, }; use irtt_proto::{echo_packet_len, Params, TimestampFields}; diff --git a/crates/irtt-client/tests/support/mod.rs b/crates/irtt-client/tests/support/mod.rs index 02dec96..fa04c70 100644 --- a/crates/irtt-client/tests/support/mod.rs +++ b/crates/irtt-client/tests/support/mod.rs @@ -11,7 +11,7 @@ use std::{ }; use irtt_client::{ - Client, ClientConfig, ClientEvent, ClientTimestamp, NegotiatedParams, OpenOutcome, SocketConfig, + Client, ClientConfig, ClientEvent, NegotiatedParams, OpenOutcome, SocketConfig, }; use irtt_proto::{ compute_hmac_in_place, echo_packet_len, flags, verify_hmac, Clock, Params, ProtoError,