1use std::{
2 time::{Duration},
3 collections::LinkedList,
4};
5use cyfs_base::*;
6use crate::types::*;
7use super::cc_impl::CcImpl;
8
9#[derive(Clone)]
10pub struct Config {
11 pub target_delay: Duration,
12 pub min_cwnd: u64,
13 pub max_cwnd_inc: u64,
14 pub cwnd_gain: u64,
15 pub history_count: u64,
16 pub history_roll_interval: Duration
17}
18
19impl Default for Config {
20 fn default() -> Self {
21 Self {
22 target_delay: Duration::from_millis(100),
23 min_cwnd: 2,
24 max_cwnd_inc: 8,
25 cwnd_gain: 1,
26 history_count: 10,
27 history_roll_interval: Duration::from_secs(60),
28 }
29 }
30}
31
32struct EstimateDelay {
33 last_roll: Timestamp,
34 base_delay: LinkedList<i64>,
35 current_delay: LinkedList<i64>
36}
37
38impl EstimateDelay {
39 fn new(config: &Config) -> Self {
40 let mut base_delay = LinkedList::new();
41 for _ in 0..config.history_count {
42 base_delay.push_back(i64::MAX);
43 }
44 let mut current_delay = LinkedList::new();
45 for _ in 0..config.history_count {
46 current_delay.push_back(i64::MAX);
47 }
48
49 Self {
50 last_roll: bucky_time_now() - config.history_roll_interval.as_micros() as u64,
51 base_delay,
52 current_delay,
53 }
54 }
55
56 fn current_delay(&self) -> i64 {
57 let mut delay = i64::MAX;
58 for d in &self.current_delay {
59 delay = std::cmp::min(*d, delay);
60 }
61 delay
62 }
63
64 fn base_delay(&self) -> i64 {
65 let mut delay = i64::MAX;
66 for d in &self.base_delay {
67 delay = std::cmp::min(*d, delay);
68 }
69 delay
70 }
71
72 fn update(&mut self, delay: i64) {
73 let tail = self.base_delay.back_mut().unwrap();
74 *tail = std::cmp::min(*tail, delay);
75
76 self.current_delay.pop_front();
77 self.current_delay.push_back(delay);
78 }
79
80 fn check_roll(&mut self, config: &Config, now: Timestamp) {
81 if now > self.last_roll && Duration::from_micros(now - self.last_roll) > config.history_roll_interval {
82 self.last_roll = now;
83 self.base_delay.pop_front();
84 self.base_delay.push_back(i64::MAX);
85
86 let base_delay = {
87 let mut delay = i64::MAX;
88 for d in &self.base_delay {
89 delay = std::cmp::min(*d, delay);
90 }
91 delay
92 };
93 if base_delay == i64::MAX {
94 for d in &mut self.current_delay {
95 *d = i64::MAX;
96 }
97 }
98 }
99 }
100}
101
102
103pub(super) struct Ledbat {
104 mss: usize,
105 est_delay: EstimateDelay,
106 config: Config,
107 cwnd: u64
108}
109
110impl Ledbat {
111 pub fn new(mss: usize, config: &Config) -> Self {
112 let mut config = config.clone();
113 config.min_cwnd = config.min_cwnd * mss as u64;
114 config.cwnd_gain = config.cwnd_gain * mss as u64;
115 config.max_cwnd_inc = config.max_cwnd_inc * mss as u64;
116 Self {
117 cwnd: config.min_cwnd,
118 mss,
119 est_delay: EstimateDelay::new(&config),
120 config
121 }
122 }
123}
124
125
126impl CcImpl for Ledbat {
127 fn on_sent(&mut self, _: Timestamp, _: u64, _: u64) {
128 }
129
130 fn cwnd(&self) -> u64 {
131 self.cwnd
132 }
133
134 fn on_estimate(&mut self, _rtt: Duration, _rto: Duration, delay: Duration, _app_limited: bool) {
135 self.est_delay.update(delay.as_micros() as i64);
136 }
137
138 fn on_ack(
139 &mut self,
140 _flight: u64,
141 ack: u64,
142 _largest_packet_num_acked: Option<u64>,
143 _sent_time: Timestamp,
144 _app_limited: bool
145 ) {
146 let cwnd = self.cwnd();
147 let cur_delay = self.est_delay.current_delay();
148 let base_delay = self.est_delay.base_delay();
149 let queuing_delay = cur_delay - base_delay;
150 let delay_factor = (self.config.target_delay.as_micros() as i64 - queuing_delay) as f64 / self.config.target_delay.as_micros() as f64;
151 let cwnd_factor = std::cmp::min(ack, cwnd) as f64 / std::cmp::max(ack, cwnd) as f64;
152 let scaled_gain = (self.config.max_cwnd_inc as f64 * cwnd_factor * delay_factor) as i64;
153 let new_cwnd = (cwnd as i64 + scaled_gain) as u64;
154 self.cwnd = new_cwnd.max(self.config.min_cwnd);
158 }
159
160
161 fn on_loss(&mut self, _lost: u64) {
162 self.cwnd = (self.cwnd / 2).max(self.config.min_cwnd)
163 }
164
165 fn on_no_resp(&mut self, rto: Duration, _lost: u64) -> Duration {
166 self.cwnd = self.config.min_cwnd;
167 rto * 2
168 }
169
170 fn on_time_escape(&mut self, now: Timestamp) {
171 self.est_delay.check_roll(&self.config, now);
172 }
173
174 fn rate(&self) -> u64 {
175 0
176 }
177}
178