Merge branch 'fix/managed-finite-lifetime-wake'
Rust CI / cargo fmt (push) Successful in 19s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Successful in 35s
Rust CI / cargo clippy (push) Successful in 37s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Failing after 7s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Failing after 8s
Rust CI / cargo doc (push) Successful in 23s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Successful in 1m16s
Fuzz Smoke / cargo fuzz smoke (push) Failing after 27s
Supply chain / cargo-deny advisories (push) Successful in 9s
Supply chain / actionlint (push) Successful in 3s
Supply chain / cargo-deny bans licenses sources (push) Successful in 8s
Netem Interop / netem interop (push) Successful in 1m3s
Rust CI / cargo fmt (push) Successful in 19s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Successful in 35s
Rust CI / cargo clippy (push) Successful in 37s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Failing after 7s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Failing after 8s
Rust CI / cargo doc (push) Successful in 23s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Successful in 1m16s
Fuzz Smoke / cargo fuzz smoke (push) Failing after 27s
Supply chain / cargo-deny advisories (push) Successful in 9s
Supply chain / actionlint (push) Successful in 3s
Supply chain / cargo-deny bans licenses sources (push) Successful in 8s
Netem Interop / netem interop (push) Successful in 1m3s
This commit is contained in:
2 files changed
+115
No files matched your search
@@ -48,6 +48,11 @@ impl ProbeSchedule {
|
||||
self.next_send_at
|
||||
}
|
||||
|
||||
/// Wake for finite expiry independently of send readiness until finished.
|
||||
pub(crate) fn end_deadline(&self) -> Option<Instant> {
|
||||
self.end_at.filter(|_| !self.is_finished())
|
||||
}
|
||||
|
||||
pub(crate) fn interval(&self) -> Duration {
|
||||
self.interval
|
||||
}
|
||||
@@ -152,3 +157,42 @@ pub(crate) fn instant_abs_diff(left: Instant, right: Instant) -> Duration {
|
||||
.or_else(|| right.checked_duration_since(left))
|
||||
.unwrap_or(Duration::ZERO)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn lifetime_deadline_exists_only_for_an_unfinished_finite_schedule() {
|
||||
let start = Instant::now();
|
||||
let end = start + Duration::from_millis(500);
|
||||
let mut negotiated = NegotiatedParams {
|
||||
params: irtt_proto::Params {
|
||||
duration_ns: 500_000_000,
|
||||
interval_ns: 1_000_000,
|
||||
..irtt_proto::Params::default()
|
||||
},
|
||||
restrictions: Vec::new(),
|
||||
};
|
||||
let mut finite = ProbeSchedule::new(start, &negotiated).unwrap();
|
||||
assert_eq!(finite.end_deadline(), Some(end));
|
||||
assert!(finite.permit_probe_at(end - Duration::from_nanos(1)));
|
||||
assert_eq!(finite.end_deadline(), Some(end));
|
||||
assert!(!finite.permit_probe_at(end));
|
||||
assert!(finite.is_finished());
|
||||
assert_eq!(finite.end_deadline(), None);
|
||||
|
||||
let mut finite = ProbeSchedule::new(start, &negotiated).unwrap();
|
||||
let commit = finite
|
||||
.preflight_managed_commit(start, end - Duration::from_nanos(1))
|
||||
.unwrap();
|
||||
finite.commit(commit);
|
||||
assert!(finite.is_finished());
|
||||
assert_eq!(finite.end_deadline(), None);
|
||||
|
||||
negotiated.params.duration_ns = 0;
|
||||
let mut continuous = ProbeSchedule::new(start, &negotiated).unwrap();
|
||||
assert!(continuous.permit_probe_at(end));
|
||||
assert_eq!(continuous.end_deadline(), None);
|
||||
}
|
||||
}
|
||||
@@ -1936,6 +1936,12 @@ impl ManagedClientTask {
|
||||
non_send_deadline = non_send_deadline
|
||||
.into_iter()
|
||||
.chain(client.next_probe_timeout_deadline())
|
||||
.chain(
|
||||
target
|
||||
.schedule
|
||||
.as_ref()
|
||||
.and_then(ProbeSchedule::end_deadline),
|
||||
)
|
||||
.min();
|
||||
if target.desired && target.retirement.is_none() && !target.send_waiting {
|
||||
send_deadline = send_deadline
|
||||
@@ -2399,6 +2405,71 @@ fn close_timeout_failure() -> ManagedTargetFailure {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// Real EAGAIN needs privileged queue shaping. Inspect only the owning
|
||||
// deadline selection here, using a production socket without sending.
|
||||
#[test]
|
||||
fn finite_lifetime_deadline_survives_send_waiting_and_stagger_gating() {
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap();
|
||||
runtime.block_on(async {
|
||||
let start = Instant::now();
|
||||
let end = start + Duration::from_millis(500);
|
||||
let negotiated = crate::NegotiatedParams {
|
||||
params: irtt_proto::Params {
|
||||
duration_ns: 500_000_000,
|
||||
interval_ns: 1_000_000,
|
||||
..irtt_proto::Params::default()
|
||||
},
|
||||
restrictions: Vec::new(),
|
||||
};
|
||||
for pacing in [ManagedPacing::Burst, ManagedPacing::Staggered] {
|
||||
let (mut task, _handle) = ManagedClient::task(
|
||||
ManagedClientConfig {
|
||||
pacing,
|
||||
..ManagedClientConfig::default()
|
||||
},
|
||||
vec![ManagedTargetConfig::new("target", "127.0.0.1:9")],
|
||||
)
|
||||
.unwrap();
|
||||
let client = AsyncClient::connect(ClientConfig {
|
||||
server_addr: "127.0.0.1:9".into(),
|
||||
..ClientConfig::default()
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
task.state = DriverState::Running;
|
||||
task.install_target_state(0, TargetState::Active { client });
|
||||
task.send_gate = Some(end + Duration::from_secs(1));
|
||||
|
||||
for send_waiting in [false, true] {
|
||||
task.targets[0].send_waiting = send_waiting;
|
||||
task.targets[0].schedule =
|
||||
Some(ProbeSchedule::new(start, &negotiated).unwrap());
|
||||
let expected = if pacing == ManagedPacing::Burst && !send_waiting {
|
||||
start
|
||||
} else {
|
||||
end
|
||||
};
|
||||
assert_eq!(task.next_deadline(), Some(expected));
|
||||
|
||||
task.targets[0]
|
||||
.schedule
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.permit_probe_at(end);
|
||||
assert_eq!(task.next_deadline(), None);
|
||||
}
|
||||
|
||||
let mut continuous = negotiated.clone();
|
||||
continuous.params.duration_ns = 0;
|
||||
task.targets[0].schedule = Some(ProbeSchedule::new(start, &continuous).unwrap());
|
||||
assert_eq!(task.next_deadline(), None);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn release_gate_only_delays_an_existing_send_deadline() {
|
||||
let earlier = Instant::now();
|
||||
|
||||
Reference in new issue
Block a user