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) > (self.window_flexibility as isize - 1) {
40 self.window_min += 1;
41 }
42 }
43 }
44
45 pub fn on_timeout(&mut self) {
48 if self.window > self.window_min {
49 self.window -= 1;
50 if self.window_max > self.window_min {
51 self.window_max -= 1;
52 if (self.window_max as isize - self.window as isize) > (self.window_flexibility as isize - 1) {
53 self.window_max -= 1;
54 }
55 }
56 }
57 }
58
59 pub fn update_req_resp_rate(&mut self, rate: f64) {
62 if rate > RESOURCE_RATE_FAST && self.fast_rate_rounds < RESOURCE_FAST_RATE_THRESHOLD {
63 self.fast_rate_rounds += 1;
64 if self.fast_rate_rounds == RESOURCE_FAST_RATE_THRESHOLD {
65 self.window_max = RESOURCE_WINDOW_MAX_FAST;
66 }
67 }
68 }
69
70 pub fn update_data_rate(&mut self, rate: f64) {
73 if rate > RESOURCE_RATE_FAST && self.fast_rate_rounds < RESOURCE_FAST_RATE_THRESHOLD {
74 self.fast_rate_rounds += 1;
75 if self.fast_rate_rounds == RESOURCE_FAST_RATE_THRESHOLD {
76 self.window_max = RESOURCE_WINDOW_MAX_FAST;
77 }
78 }
79
80 if self.fast_rate_rounds == 0
82 && rate < RESOURCE_RATE_VERY_SLOW
83 && self.very_slow_rate_rounds < RESOURCE_VERY_SLOW_RATE_THRESHOLD
84 {
85 self.very_slow_rate_rounds += 1;
86 if self.very_slow_rate_rounds == RESOURCE_VERY_SLOW_RATE_THRESHOLD {
87 self.window_max = RESOURCE_WINDOW_MAX_VERY_SLOW;
88 }
89 }
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn test_initial_state() {
99 let ws = WindowState::new();
100 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);
105 assert_eq!(ws.very_slow_rate_rounds, 0);
106 }
107
108 #[test]
109 fn test_window_increase_on_complete() {
110 let mut ws = WindowState::new();
111 ws.on_window_complete();
113 assert_eq!(ws.window, 5);
115 assert_eq!(ws.window_min, 2);
116
117 ws.on_window_complete();
118 assert_eq!(ws.window, 6);
120 assert_eq!(ws.window_min, 3);
121 }
122
123 #[test]
124 fn test_window_capped_at_max() {
125 let mut ws = WindowState::new();
126 ws.window = 10;
127 ws.window_max = 10;
128 ws.on_window_complete();
129 assert_eq!(ws.window, 10); }
131
132 #[test]
133 fn test_window_decrease_on_timeout() {
134 let mut ws = WindowState::new();
135 ws.on_timeout();
137 assert_eq!(ws.window, 3);
140 assert_eq!(ws.window_max, 8);
141 }
142
143 #[test]
144 fn test_window_min_floor() {
145 let mut ws = WindowState::new();
146 ws.window = RESOURCE_WINDOW_MIN;
147 ws.on_timeout();
148 assert_eq!(ws.window, RESOURCE_WINDOW_MIN); }
150
151 #[test]
152 fn test_fast_rate_detection() {
153 let mut ws = WindowState::new();
154 for _ in 0..3 {
156 ws.update_req_resp_rate(RESOURCE_RATE_FAST + 1.0);
157 }
158 assert_eq!(ws.fast_rate_rounds, 3);
159 assert_eq!(ws.window_max, RESOURCE_WINDOW_MAX_SLOW); ws.update_req_resp_rate(RESOURCE_RATE_FAST + 1.0);
162 assert_eq!(ws.fast_rate_rounds, 4);
163 assert_eq!(ws.window_max, RESOURCE_WINDOW_MAX_FAST); }
165
166 #[test]
167 fn test_fast_rate_rounds_never_reset() {
168 let mut ws = WindowState::new();
169 ws.update_req_resp_rate(RESOURCE_RATE_FAST + 1.0);
170 assert_eq!(ws.fast_rate_rounds, 1);
171
172 ws.update_req_resp_rate(1.0);
174 assert_eq!(ws.fast_rate_rounds, 1);
175 }
176
177 #[test]
178 fn test_fast_rate_rounds_cap() {
179 let mut ws = WindowState::new();
180 for _ in 0..10 {
181 ws.update_req_resp_rate(RESOURCE_RATE_FAST + 1.0);
182 }
183 assert_eq!(ws.fast_rate_rounds, RESOURCE_FAST_RATE_THRESHOLD);
185 }
186
187 #[test]
188 fn test_very_slow_detection() {
189 let mut ws = WindowState::new();
190 assert_eq!(ws.fast_rate_rounds, 0);
192
193 ws.update_data_rate(RESOURCE_RATE_VERY_SLOW - 1.0);
194 assert_eq!(ws.very_slow_rate_rounds, 1);
195 assert_eq!(ws.window_max, RESOURCE_WINDOW_MAX_SLOW); ws.update_data_rate(RESOURCE_RATE_VERY_SLOW - 1.0);
198 assert_eq!(ws.very_slow_rate_rounds, 2);
199 assert_eq!(ws.window_max, RESOURCE_WINDOW_MAX_VERY_SLOW); }
201
202 #[test]
203 fn test_very_slow_blocked_by_fast() {
204 let mut ws = WindowState::new();
205 ws.update_data_rate(RESOURCE_RATE_FAST + 1.0);
207 assert_eq!(ws.fast_rate_rounds, 1);
208
209 ws.update_data_rate(RESOURCE_RATE_VERY_SLOW - 1.0);
211 assert_eq!(ws.very_slow_rate_rounds, 0);
212 }
213
214 #[test]
215 fn test_restore_window() {
216 let mut ws = WindowState::new();
217 ws.restore(8);
218 assert_eq!(ws.window, 8);
219 }
220
221 #[test]
222 fn test_window_never_below_min() {
223 let mut ws = WindowState::new();
224 ws.window = 2;
225 ws.window_min = 2;
226 ws.on_timeout();
227 assert_eq!(ws.window, 2);
228 }
229
230 #[test]
231 fn test_window_never_above_max() {
232 let mut ws = WindowState::new();
233 ws.window = 10;
234 ws.window_max = 10;
235 ws.on_window_complete();
236 assert_eq!(ws.window, 10);
237 }
238}