refactor: replace unbounded control snapshot channel with tokio watch
This commit is contained in:
3 files changed
+19
-56
No files matched your search
+2
-2
@@ -79,7 +79,7 @@ pub struct Baseliner {
|
|||||||
pub reselect_trigger: Sender<bool>,
|
pub reselect_trigger: Sender<bool>,
|
||||||
pub start_time: Instant,
|
pub start_time: Instant,
|
||||||
pub stats_rx: Receiver<MeasurementEvent>,
|
pub stats_rx: Receiver<MeasurementEvent>,
|
||||||
pub control_tx: Sender<ControlSnapshot>,
|
pub control_tx: tokio::sync::watch::Sender<Option<ControlSnapshot>>,
|
||||||
pub selection_tx: Option<Sender<ControlSnapshot>>,
|
pub selection_tx: Option<Sender<ControlSnapshot>>,
|
||||||
pub baseline_metrics: MetricsSender,
|
pub baseline_metrics: MetricsSender,
|
||||||
pub event_metrics: MetricsSender,
|
pub event_metrics: MetricsSender,
|
||||||
@@ -236,7 +236,7 @@ impl Baseliner {
|
|||||||
if let Some(selection_tx) = &self.selection_tx {
|
if let Some(selection_tx) = &self.selection_tx {
|
||||||
let _ = selection_tx.send(snapshot.clone());
|
let _ = selection_tx.send(snapshot.clone());
|
||||||
}
|
}
|
||||||
self.control_tx.send(snapshot)?;
|
self.control_tx.send(Some(snapshot))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -40,6 +40,7 @@ use std::sync::{Arc, RwLock};
|
|||||||
use std::thread;
|
use std::thread;
|
||||||
use std::thread::{JoinHandle, sleep};
|
use std::thread::{JoinHandle, sleep};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
use tokio::sync::watch;
|
||||||
|
|
||||||
struct ReflectorSetup {
|
struct ReflectorSetup {
|
||||||
peers: Arc<RwLock<Vec<SocketAddr>>>,
|
peers: Arc<RwLock<Vec<SocketAddr>>>,
|
||||||
@@ -345,7 +346,7 @@ fn run(settings: &Settings) -> anyhow::Result<()> {
|
|||||||
reselection_enabled,
|
reselection_enabled,
|
||||||
} = setup_reflectors(settings)?;
|
} = 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::<anyhow::Error>();
|
let (error_tx, error_rx) = flume::unbounded::<anyhow::Error>();
|
||||||
let (icmp_binding_tx, icmp_binding_rx) = flume::unbounded();
|
let (icmp_binding_tx, icmp_binding_rx) = flume::unbounded();
|
||||||
#[cfg(feature = "irtt")]
|
#[cfg(feature = "irtt")]
|
||||||
|
|||||||
+15
-53
@@ -16,7 +16,6 @@ use crate::platform::{
|
|||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
use crate::time::{ClockSample, Realtime};
|
use crate::time::{ClockSample, Realtime};
|
||||||
use crate::util::{ArcRwLock, RwLockExt};
|
use crate::util::{ArcRwLock, RwLockExt};
|
||||||
use flume::{Receiver, Sender};
|
|
||||||
use log::{debug, info, warn};
|
use log::{debug, info, warn};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@@ -84,20 +83,6 @@ impl<H> State<H> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drain_latest_snapshot(
|
|
||||||
snapshot_rx: &Receiver<ControlSnapshot>,
|
|
||||||
latest: &mut Option<ControlSnapshot>,
|
|
||||||
) {
|
|
||||||
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(
|
fn deltas_from_snapshot(
|
||||||
snapshot: Option<&ControlSnapshot>,
|
snapshot: Option<&ControlSnapshot>,
|
||||||
reflectors: &[MeasurementStream],
|
reflectors: &[MeasurementStream],
|
||||||
@@ -137,10 +122,9 @@ fn deltas_from_snapshot(
|
|||||||
|
|
||||||
pub struct Ratecontroller<S: InterfaceStatsProvider, T: TrafficControlBackend> {
|
pub struct Ratecontroller<S: InterfaceStatsProvider, T: TrafficControlBackend> {
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
control_snapshot: Option<ControlSnapshot>,
|
control_snapshot_rx: tokio::sync::watch::Receiver<Option<ControlSnapshot>>,
|
||||||
control_snapshot_rx: Receiver<ControlSnapshot>,
|
|
||||||
reflectors_lock: ArcRwLock<Vec<MeasurementStream>>,
|
reflectors_lock: ArcRwLock<Vec<MeasurementStream>>,
|
||||||
reselect_trigger: Sender<bool>,
|
reselect_trigger: flume::Sender<bool>,
|
||||||
state_dl: State<T::Handle>,
|
state_dl: State<T::Handle>,
|
||||||
state_ul: State<T::Handle>,
|
state_ul: State<T::Handle>,
|
||||||
rng: fastrand::Rng,
|
rng: fastrand::Rng,
|
||||||
@@ -152,9 +136,9 @@ pub struct Ratecontroller<S: InterfaceStatsProvider, T: TrafficControlBackend> {
|
|||||||
impl<S: InterfaceStatsProvider, T: TrafficControlBackend> Ratecontroller<S, T> {
|
impl<S: InterfaceStatsProvider, T: TrafficControlBackend> Ratecontroller<S, T> {
|
||||||
fn new_with_backends(
|
fn new_with_backends(
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
control_snapshot_rx: Receiver<ControlSnapshot>,
|
control_snapshot_rx: tokio::sync::watch::Receiver<Option<ControlSnapshot>>,
|
||||||
reflectors_lock: ArcRwLock<Vec<MeasurementStream>>,
|
reflectors_lock: ArcRwLock<Vec<MeasurementStream>>,
|
||||||
reselect_trigger: Sender<bool>,
|
reselect_trigger: flume::Sender<bool>,
|
||||||
metrics: MetricsSender,
|
metrics: MetricsSender,
|
||||||
mut stats_provider: S,
|
mut stats_provider: S,
|
||||||
mut traffic_control: T,
|
mut traffic_control: T,
|
||||||
@@ -179,7 +163,6 @@ impl<S: InterfaceStatsProvider, T: TrafficControlBackend> Ratecontroller<S, T> {
|
|||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
settings,
|
settings,
|
||||||
control_snapshot: None,
|
|
||||||
control_snapshot_rx,
|
control_snapshot_rx,
|
||||||
reflectors_lock,
|
reflectors_lock,
|
||||||
reselect_trigger,
|
reselect_trigger,
|
||||||
@@ -479,15 +462,17 @@ impl<S: InterfaceStatsProvider, T: TrafficControlBackend> Ratecontroller<S, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_deltas(&mut self) -> anyhow::Result<()> {
|
fn update_deltas(&mut self) -> anyhow::Result<()> {
|
||||||
drain_latest_snapshot(&self.control_snapshot_rx, &mut self.control_snapshot);
|
|
||||||
let now_t = Instant::now();
|
let now_t = Instant::now();
|
||||||
let reflectors = self.reflectors_lock.read_anyhow()?;
|
let reflectors = self.reflectors_lock.read_anyhow()?;
|
||||||
let (down_deltas, up_deltas) = deltas_from_snapshot(
|
let (down_deltas, up_deltas) = {
|
||||||
self.control_snapshot.as_ref(),
|
let snapshot = self.control_snapshot_rx.borrow();
|
||||||
&reflectors,
|
deltas_from_snapshot(
|
||||||
now_t,
|
snapshot.as_ref(),
|
||||||
self.settings.advanced_settings.tick_interval,
|
&reflectors,
|
||||||
);
|
now_t,
|
||||||
|
self.settings.advanced_settings.tick_interval,
|
||||||
|
)
|
||||||
|
};
|
||||||
self.state_dl.deltas = down_deltas;
|
self.state_dl.deltas = down_deltas;
|
||||||
self.state_ul.deltas = up_deltas;
|
self.state_ul.deltas = up_deltas;
|
||||||
|
|
||||||
@@ -513,9 +498,9 @@ impl<S: InterfaceStatsProvider, T: TrafficControlBackend> Ratecontroller<S, T> {
|
|||||||
impl Ratecontroller<PlatformInterfaceStats, PlatformTrafficControl> {
|
impl Ratecontroller<PlatformInterfaceStats, PlatformTrafficControl> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
control_snapshot_rx: Receiver<ControlSnapshot>,
|
control_snapshot_rx: tokio::sync::watch::Receiver<Option<ControlSnapshot>>,
|
||||||
reflectors_lock: ArcRwLock<Vec<MeasurementStream>>,
|
reflectors_lock: ArcRwLock<Vec<MeasurementStream>>,
|
||||||
reselect_trigger: Sender<bool>,
|
reselect_trigger: flume::Sender<bool>,
|
||||||
metrics: MetricsSender,
|
metrics: MetricsSender,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
Self::new_with_backends(
|
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]
|
#[test]
|
||||||
fn calculates_sorted_deltas_from_active_fresh_snapshot_state() {
|
fn calculates_sorted_deltas_from_active_fresh_snapshot_state() {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|||||||
Reference in new issue
Block a user