rns_core/resource/
window.rs1use crate::constants::*;
2
3#[derive(Debug, Clone)]
8pub struct WindowState {
9 pub window: usize,
10 pub window_max: usize,
11 pub window_min: usize,
12 pub window_flexibility: usize,
13 pub fast_rate_rounds: usize,
14 pub very_slow_rate_rounds: usize,
15}
16
17impl WindowState {
18 pub fn new() -> Self {
19 WindowState {
20 window: RESOURCE_WINDOW,
21 window_max: RESOURCE_WINDOW_MAX_SLOW,
22 window_min: RESOURCE_WINDOW_MIN,
23 window_flexibility: RESOURCE_WINDOW_FLEXIBILITY,
24 fast_rate_rounds: 0,
25 very_slow_rate_rounds: 0,
26 }
27 }
28
29 pub fn restore(&mut self, previous_window: usize) {
31 self.window = previous_window;
32 }
33
34 pub fn on_window_complete(&mut self) {
37 if self.window < self.window_max {
38 self.window += 1;
39 if (self.window as isize - self.window_min as isize)
40 > (self.window_flexibility as isize - 1)
41 {
42 self.window_min += 1;
43 }
44 }
45 }
46
47 pub fn on_timeout(&mut self) {
50 if self.window > self.window_min {
51 self.window -= 1;
52 if self.window_max > self.window_min {
53 self.window_max -= 1;
54 if (self.window_max as isize - self.window as isize)
55 > (self.window_flexibility as isize - 1)
56 {
57 self.window_max -= 1;
58 }
59 }
60 }
61 }
62
63 pub fn update_req_resp_rate(&mut self, rate: f64) {
66 if rate > RESOURCE_RATE_FAST && self.fast_rate_rounds < RESOURCE_FAST_RATE_THRESHOLD {
67 self.fast_rate_rounds += 1;
68 if self.fast_rate_rounds == RESOURCE_FAST_RATE_THRESHOLD {
69 self.window_max = RESOURCE_WINDOW_MAX_FAST;
70 }
71 }
72 }
73
74 pub fn update_data_rate(&mut self, rate: f64) {
77 if rate > RESOURCE_RATE_FAST && self.fast_rate_rounds < RESOURCE_FAST_RATE_THRESHOLD {
78 self.fast_rate_rounds += 1;
79 if self.fast_rate_rounds == RESOURCE_FAST_RATE_THRESHOLD {
80 self.window_max = RESOURCE_WINDOW_MAX_FAST;
81 }
82 }
83
84 if self.fast_rate_rounds == 0
86 && rate < RESOURCE_RATE_VERY_SLOW
87 && self.very_slow_rate_rounds < RESOURCE_VERY_SLOW_RATE_THRESHOLD
88 {
89 self.very_slow_rate_rounds += 1;
90 if self.very_slow_rate_rounds == RESOURCE_VERY_SLOW_RATE_THRESHOLD {
91 self.window_max = RESOURCE_WINDOW_MAX_VERY_SLOW;
92 }
93 }
94 }
95}
96
97impl Default for WindowState {
98 fn default() -> Self {
99 Self::new()
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_initial_state() {
109 let ws = WindowState::new();
110 assert_eq!(ws.window, RESOURCE_WINDOW); assert_eq!(ws.window_max, RESOURCE_WINDOW_MAX_SLOW); assert_eq!(ws.window_min, RESOURCE_WINDOW_MIN); assert_eq!(ws.window_flexibility, RESOURCE_WINDOW_FLEXIBILITY); assert_eq!(ws.fast_rate_rounds, 0);
115 assert_eq!(ws.very_slow_rate_rounds, 0);
116 }
117
118 #[test]
119 fn test_window_increase_on_complete() {
120 let mut ws = WindowState::new();
121 ws.on_window_complete();
123 assert_eq!(ws.window, 5);
125 assert_eq!(ws.window_min, 2);
126
127 ws.on_window_complete();
128 assert_eq!(ws.window, 6);
130 assert_eq!(ws.window_min, 3);
131 }
132
133 #[test]
134 fn test_window_capped_at_max() {
135 let mut ws = WindowState::new();
136 ws.window = 10;
137 ws.window_max = 10;
138 ws.on_window_complete();
139 assert_eq!(ws.window, 10); }
141
142 #[test]
143 fn test_window_decrease_on_timeout() {
144 let mut ws = WindowState::new();
145 ws.on_timeout();
147 assert_eq!(ws.window, 3);
150 assert_eq!(ws.window_max, 8);
151 }
152
153 #[test]
154 fn test_window_min_floor() {
155 let mut ws = WindowState::new();
156 ws.window = RESOURCE_WINDOW_MIN;
157 ws.on_timeout();
158 assert_eq!(ws.window, RESOURCE_WINDOW_MIN); }
160
161 #[test]
162 fn test_fast_rate_detection() {
163 let mut ws = WindowState::new();
164 for _ in 0..3 {
166 ws.update_req_resp_rate(RESOURCE_RATE_FAST + 1.0);
167 }
168 assert_eq!(ws.fast_rate_rounds, 3);
169 assert_eq!(ws.window_max, RESOURCE_WINDOW_MAX_SLOW); ws.update_req_resp_rate(RESOURCE_RATE_FAST + 1.0);
172 assert_eq!(ws.fast_rate_rounds, 4);
173 assert_eq!(ws.window_max, RESOURCE_WINDOW_MAX_FAST); }
175
176 #[test]
177 fn test_fast_rate_rounds_never_reset() {
178 let mut ws = WindowState::new();
179 ws.update_req_resp_rate(RESOURCE_RATE_FAST + 1.0);
180 assert_eq!(ws.fast_rate_rounds, 1);
181
182 ws.update_req_resp_rate(1.0);
184 assert_eq!(ws.fast_rate_rounds, 1);
185 }
186
187 #[test]
188 fn test_fast_rate_rounds_cap() {
189 let mut ws = WindowState::new();
190 for _ in 0..10 {
191 ws.update_req_resp_rate(RESOURCE_RATE_FAST + 1.0);
192 }
193 assert_eq!(ws.fast_rate_rounds, RESOURCE_FAST_RATE_THRESHOLD);
195 }
196
197 #[test]
198 fn test_very_slow_detection() {
199 let mut ws = WindowState::new();
200 assert_eq!(ws.fast_rate_rounds, 0);
202
203 ws.update_data_rate(RESOURCE_RATE_VERY_SLOW - 1.0);
204 assert_eq!(ws.very_slow_rate_rounds, 1);
205 assert_eq!(ws.window_max, RESOURCE_WINDOW_MAX_SLOW); ws.update_data_rate(RESOURCE_RATE_VERY_SLOW - 1.0);
208 assert_eq!(ws.very_slow_rate_rounds, 2);
209 assert_eq!(ws.window_max, RESOURCE_WINDOW_MAX_VERY_SLOW); }
211
212 #[test]
213 fn test_very_slow_blocked_by_fast() {
214 let mut ws = WindowState::new();
215 ws.update_data_rate(RESOURCE_RATE_FAST + 1.0);
217 assert_eq!(ws.fast_rate_rounds, 1);
218
219 ws.update_data_rate(RESOURCE_RATE_VERY_SLOW - 1.0);
221 assert_eq!(ws.very_slow_rate_rounds, 0);
222 }
223
224 #[test]
225 fn test_restore_window() {
226 let mut ws = WindowState::new();
227 ws.restore(8);
228 assert_eq!(ws.window, 8);
229 }
230
231 #[test]
232 fn test_window_never_below_min() {
233 let mut ws = WindowState::new();
234 ws.window = 2;
235 ws.window_min = 2;
236 ws.on_timeout();
237 assert_eq!(ws.window, 2);
238 }
239
240 #[test]
241 fn test_window_never_above_max() {
242 let mut ws = WindowState::new();
243 ws.window = 10;
244 ws.window_max = 10;
245 ws.on_window_complete();
246 assert_eq!(ws.window, 10);
247 }
248}