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
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn test_initial_state() {
103 let ws = WindowState::new();
104 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);
109 assert_eq!(ws.very_slow_rate_rounds, 0);
110 }
111
112 #[test]
113 fn test_window_increase_on_complete() {
114 let mut ws = WindowState::new();
115 ws.on_window_complete();
117 assert_eq!(ws.window, 5);
119 assert_eq!(ws.window_min, 2);
120
121 ws.on_window_complete();
122 assert_eq!(ws.window, 6);
124 assert_eq!(ws.window_min, 3);
125 }
126
127 #[test]
128 fn test_window_capped_at_max() {
129 let mut ws = WindowState::new();
130 ws.window = 10;
131 ws.window_max = 10;
132 ws.on_window_complete();
133 assert_eq!(ws.window, 10); }
135
136 #[test]
137 fn test_window_decrease_on_timeout() {
138 let mut ws = WindowState::new();
139 ws.on_timeout();
141 assert_eq!(ws.window, 3);
144 assert_eq!(ws.window_max, 8);
145 }
146
147 #[test]
148 fn test_window_min_floor() {
149 let mut ws = WindowState::new();
150 ws.window = RESOURCE_WINDOW_MIN;
151 ws.on_timeout();
152 assert_eq!(ws.window, RESOURCE_WINDOW_MIN); }
154
155 #[test]
156 fn test_fast_rate_detection() {
157 let mut ws = WindowState::new();
158 for _ in 0..3 {
160 ws.update_req_resp_rate(RESOURCE_RATE_FAST + 1.0);
161 }
162 assert_eq!(ws.fast_rate_rounds, 3);
163 assert_eq!(ws.window_max, RESOURCE_WINDOW_MAX_SLOW); ws.update_req_resp_rate(RESOURCE_RATE_FAST + 1.0);
166 assert_eq!(ws.fast_rate_rounds, 4);
167 assert_eq!(ws.window_max, RESOURCE_WINDOW_MAX_FAST); }
169
170 #[test]
171 fn test_fast_rate_rounds_never_reset() {
172 let mut ws = WindowState::new();
173 ws.update_req_resp_rate(RESOURCE_RATE_FAST + 1.0);
174 assert_eq!(ws.fast_rate_rounds, 1);
175
176 ws.update_req_resp_rate(1.0);
178 assert_eq!(ws.fast_rate_rounds, 1);
179 }
180
181 #[test]
182 fn test_fast_rate_rounds_cap() {
183 let mut ws = WindowState::new();
184 for _ in 0..10 {
185 ws.update_req_resp_rate(RESOURCE_RATE_FAST + 1.0);
186 }
187 assert_eq!(ws.fast_rate_rounds, RESOURCE_FAST_RATE_THRESHOLD);
189 }
190
191 #[test]
192 fn test_very_slow_detection() {
193 let mut ws = WindowState::new();
194 assert_eq!(ws.fast_rate_rounds, 0);
196
197 ws.update_data_rate(RESOURCE_RATE_VERY_SLOW - 1.0);
198 assert_eq!(ws.very_slow_rate_rounds, 1);
199 assert_eq!(ws.window_max, RESOURCE_WINDOW_MAX_SLOW); ws.update_data_rate(RESOURCE_RATE_VERY_SLOW - 1.0);
202 assert_eq!(ws.very_slow_rate_rounds, 2);
203 assert_eq!(ws.window_max, RESOURCE_WINDOW_MAX_VERY_SLOW); }
205
206 #[test]
207 fn test_very_slow_blocked_by_fast() {
208 let mut ws = WindowState::new();
209 ws.update_data_rate(RESOURCE_RATE_FAST + 1.0);
211 assert_eq!(ws.fast_rate_rounds, 1);
212
213 ws.update_data_rate(RESOURCE_RATE_VERY_SLOW - 1.0);
215 assert_eq!(ws.very_slow_rate_rounds, 0);
216 }
217
218 #[test]
219 fn test_restore_window() {
220 let mut ws = WindowState::new();
221 ws.restore(8);
222 assert_eq!(ws.window, 8);
223 }
224
225 #[test]
226 fn test_window_never_below_min() {
227 let mut ws = WindowState::new();
228 ws.window = 2;
229 ws.window_min = 2;
230 ws.on_timeout();
231 assert_eq!(ws.window, 2);
232 }
233
234 #[test]
235 fn test_window_never_above_max() {
236 let mut ws = WindowState::new();
237 ws.window = 10;
238 ws.window_max = 10;
239 ws.on_window_complete();
240 assert_eq!(ws.window, 10);
241 }
242}