From 9f92b1318698b34fa6236212e030ba3b3d01a01c Mon Sep 17 00:00:00 2001 From: Nils Andreas Svee Date: Wed, 28 Oct 2026 18:01:20 +0700 Subject: [PATCH] refactor: replace unbounded control snapshot channel with tokio watch --- src/baseliner.rs | 4 +-- src/main.rs | 3 +- src/ratecontroller.rs | 68 ++++++++++--------------------------------- 3 files changed, 19 insertions(+), 56 deletions(-) diff --git a/src/baseliner.rs b/src/baseliner.rs index 8363050..c0b6c69 100644 --- a/src/baseliner.rs +++ b/src/baseliner.rs @@ -79,7 +79,7 @@ pub struct Baseliner { pub reselect_trigger: Sender, pub start_time: Instant, pub stats_rx: Receiver, - pub control_tx: Sender, + pub control_tx: tokio::sync::watch::Sender>, pub selection_tx: Option>, pub baseline_metrics: MetricsSender, pub event_metrics: MetricsSender, @@ -236,7 +236,7 @@ impl Baseliner { if let Some(selection_tx) = &self.selection_tx { let _ = selection_tx.send(snapshot.clone()); } - self.control_tx.send(snapshot)?; + self.control_tx.send(Some(snapshot))?; } } } diff --git a/src/main.rs b/src/main.rs index 1bda3c4..d3aab15 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,6 +40,7 @@ use std::sync::{Arc, RwLock}; use std::thread; use std::thread::{JoinHandle, sleep}; use std::time::{Duration, Instant}; +use tokio::sync::watch; struct ReflectorSetup { peers: Arc>>, @@ -345,7 +346,7 @@ fn run(settings: &Settings) -> anyhow::Result<()> { reselection_enabled, } = setup_reflectors(settings)?; - let (control_snapshot_tx, control_snapshot_rx) = flume::unbounded(); + let (control_snapshot_tx, control_snapshot_rx) = watch::channel(None); let (error_tx, error_rx) = flume::unbounded::(); let (icmp_binding_tx, icmp_binding_rx) = flume::unbounded(); #[cfg(feature = "irtt")] diff --git a/src/ratecontroller.rs b/src/ratecontroller.rs index d35e205..5b6630e 100644 --- a/src/ratecontroller.rs +++ b/src/ratecontroller.rs @@ -16,7 +16,6 @@ use crate::platform::{ use crate::settings::Settings; use crate::time::{ClockSample, Realtime}; use crate::util::{ArcRwLock, RwLockExt}; -use flume::{Receiver, Sender}; use log::{debug, info, warn}; use std::fs::File; use std::io::Write; @@ -84,20 +83,6 @@ impl State { } } -fn drain_latest_snapshot( - snapshot_rx: &Receiver, - latest: &mut Option, -) { - while let Ok(snapshot) = snapshot_rx.try_recv() { - if latest - .as_ref() - .is_none_or(|current| snapshot.generated_at >= current.generated_at) - { - *latest = Some(snapshot); - } - } -} - fn deltas_from_snapshot( snapshot: Option<&ControlSnapshot>, reflectors: &[MeasurementStream], @@ -137,10 +122,9 @@ fn deltas_from_snapshot( pub struct Ratecontroller { settings: Settings, - control_snapshot: Option, - control_snapshot_rx: Receiver, + control_snapshot_rx: tokio::sync::watch::Receiver>, reflectors_lock: ArcRwLock>, - reselect_trigger: Sender, + reselect_trigger: flume::Sender, state_dl: State, state_ul: State, rng: fastrand::Rng, @@ -152,9 +136,9 @@ pub struct Ratecontroller { impl Ratecontroller { fn new_with_backends( settings: Settings, - control_snapshot_rx: Receiver, + control_snapshot_rx: tokio::sync::watch::Receiver>, reflectors_lock: ArcRwLock>, - reselect_trigger: Sender, + reselect_trigger: flume::Sender, metrics: MetricsSender, mut stats_provider: S, mut traffic_control: T, @@ -179,7 +163,6 @@ impl Ratecontroller { Ok(Self { settings, - control_snapshot: None, control_snapshot_rx, reflectors_lock, reselect_trigger, @@ -479,15 +462,17 @@ impl Ratecontroller { } fn update_deltas(&mut self) -> anyhow::Result<()> { - drain_latest_snapshot(&self.control_snapshot_rx, &mut self.control_snapshot); let now_t = Instant::now(); let reflectors = self.reflectors_lock.read_anyhow()?; - let (down_deltas, up_deltas) = deltas_from_snapshot( - self.control_snapshot.as_ref(), - &reflectors, - now_t, - self.settings.advanced_settings.tick_interval, - ); + let (down_deltas, up_deltas) = { + let snapshot = self.control_snapshot_rx.borrow(); + deltas_from_snapshot( + snapshot.as_ref(), + &reflectors, + now_t, + self.settings.advanced_settings.tick_interval, + ) + }; self.state_dl.deltas = down_deltas; self.state_ul.deltas = up_deltas; @@ -513,9 +498,9 @@ impl Ratecontroller { impl Ratecontroller { pub fn new( settings: Settings, - control_snapshot_rx: Receiver, + control_snapshot_rx: tokio::sync::watch::Receiver>, reflectors_lock: ArcRwLock>, - reselect_trigger: Sender, + reselect_trigger: flume::Sender, metrics: MetricsSender, ) -> anyhow::Result { Self::new_with_backends( @@ -589,29 +574,6 @@ mod tests { } } - #[test] - fn drains_queued_snapshots_and_keeps_the_newest() { - let start = Instant::now(); - let newest_at = start + Duration::from_secs(2); - let (tx, rx) = flume::unbounded(); - tx.send(snapshot(start + Duration::from_secs(1), 1.0)) - .unwrap(); - tx.send(snapshot(newest_at, 2.0)).unwrap(); - let mut latest = None; - - drain_latest_snapshot(&rx, &mut latest); - - let latest = latest.unwrap(); - assert!(rx.is_empty()); - assert_eq!(latest.generated_at, newest_at); - assert_eq!( - latest.reflectors[&stream(0, "192.0.2.1".parse().unwrap())] - .recent - .down, - 2.0 - ); - } - #[test] fn calculates_sorted_deltas_from_active_fresh_snapshot_state() { let now = Instant::now();