1//! Implement a timeout estimator that just uses another process's estimates.
23use crate::timeouts::{pareto::ParetoTimeoutState, Action, TimeoutEstimator};
4use std::time::Duration;
56/// A timeout estimator based on reading timeouts that another timeout estimator
7/// is computing, in another process.
8pub(crate) struct ReadonlyTimeoutEstimator {
9/// Are we using the timeouts?
10using_estimates: bool,
11/// Latest estimate from the persistent state.
12latest_timeout: Option<Duration>,
13/// Timeout to use if we don't have a computed timeout.
14default_timeout: Duration,
15}
1617impl ReadonlyTimeoutEstimator {
18/// Create a new ReadonlyTimeoutEstimator with default settings.
19pub(crate) fn new() -> Self {
20 ReadonlyTimeoutEstimator {
21 using_estimates: true,
22 latest_timeout: None,
23 default_timeout: Duration::from_secs(60),
24 }
25 }
2627/// Create a new ReadonlyTimeoutEstimator, based on persistent state
28pub(crate) fn from_state(s: &ParetoTimeoutState) -> Self {
29let mut est = Self::new();
30 est.update_from_state(s);
31 est
32 }
3334/// Update this estimator based on a newly read state.
35pub(crate) fn update_from_state(&mut self, s: &ParetoTimeoutState) {
36self.latest_timeout = s.latest_estimate();
37 }
38}
3940impl TimeoutEstimator for ReadonlyTimeoutEstimator {
41fn note_hop_completed(&mut self, _hop: u8, _delay: Duration, _is_last: bool) {
42// We don't record any timeouts with this estimator.
43}
4445fn note_circ_timeout(&mut self, _hop: u8, _delay: Duration) {
46// as above
47}
4849fn timeouts(&mut self, action: &Action) -> (Duration, Duration) {
50let base = match (self.using_estimates, self.latest_timeout) {
51 (true, Some(d)) => d,
52 (_, _) => self.default_timeout,
53 };
5455let reference_action = Action::BuildCircuit { length: 3 };
56debug_assert!(reference_action.timeout_scale() > 0);
5758let multiplier =
59 (action.timeout_scale() as f64) / (reference_action.timeout_scale() as f64);
6061use super::mul_duration_f64_saturating as mul;
62let timeout = mul(base, multiplier);
6364// We use the same timeout twice here, since we don't need
65 // separate abandon and timeout thresholds when we are not
66 // recording timeout info.
67 //
68 // TODO: decide whether it is a problem that this might let an
69 // observer know whether our stat is read-only.
70(timeout, timeout)
71 }
7273fn learning_timeouts(&self) -> bool {
74false
75}
7677fn update_params(&mut self, params: &tor_netdir::params::NetParameters) {
78self.using_estimates = !bool::from(params.cbt_learning_disabled);
79self.default_timeout = params
80 .cbt_initial_timeout
81 .try_into()
82 .unwrap_or_else(|_| Duration::from_secs(60));
83 }
8485fn build_state(&mut self) -> Option<ParetoTimeoutState> {
86None
87}
88}