sz_rust_core/runtime/
worker.rs1use std::fmt;
19
20pub const DEFAULT_WORKER_NUM: usize = 0; pub const MIN_WORKER_NUM: usize = 1;
25
26pub const MAX_WORKER_NUM: usize = 256;
28
29#[derive(Debug, Clone, PartialEq, Eq)]
51pub struct WorkerConfig {
52 worker_num: usize,
54 reactor_num: usize,
56 task_worker_num: usize,
58}
59
60impl WorkerConfig {
61 pub fn new() -> Self {
63 let cpu = num_cpus::get();
64 Self {
65 worker_num: cpu,
66 reactor_num: cpu,
67 task_worker_num: cpu,
68 }
69 }
70
71 pub fn with_worker_num(mut self, n: usize) -> Self {
76 self.worker_num = if n == 0 {
77 num_cpus::get()
78 } else {
79 n.clamp(MIN_WORKER_NUM, MAX_WORKER_NUM)
80 };
81 self
82 }
83
84 pub fn with_reactor_num(mut self, n: usize) -> Self {
86 self.reactor_num = if n == 0 {
87 num_cpus::get()
88 } else {
89 n.clamp(MIN_WORKER_NUM, MAX_WORKER_NUM)
90 };
91 self
92 }
93
94 pub fn with_task_worker_num(mut self, n: usize) -> Self {
96 self.task_worker_num = if n == 0 {
97 num_cpus::get()
98 } else {
99 n.clamp(MIN_WORKER_NUM, MAX_WORKER_NUM)
100 };
101 self
102 }
103
104 pub fn worker_num(&self) -> usize {
106 self.worker_num
107 }
108
109 pub fn reactor_num(&self) -> usize {
111 self.reactor_num
112 }
113
114 pub fn task_worker_num(&self) -> usize {
116 self.task_worker_num
117 }
118
119 pub fn cpu_num(&self) -> usize {
121 num_cpus::get()
122 }
123
124 pub fn validate(&self) -> bool {
126 self.worker_num >= MIN_WORKER_NUM
127 && self.worker_num <= MAX_WORKER_NUM
128 && self.reactor_num >= MIN_WORKER_NUM
129 && self.reactor_num <= MAX_WORKER_NUM
130 && self.task_worker_num >= MIN_WORKER_NUM
131 && self.task_worker_num <= MAX_WORKER_NUM
132 }
133
134 pub fn from_env() -> Self {
139 let mut config = Self::new();
140 if let Ok(val) = std::env::var("SZ_RUST_WORKER_NUM") {
141 if let Ok(n) = val.parse::<usize>() {
142 config = config.with_worker_num(n);
143 }
144 }
145 config
146 }
147}
148
149impl Default for WorkerConfig {
150 fn default() -> Self {
151 Self::new()
152 }
153}
154
155impl fmt::Display for WorkerConfig {
156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157 write!(
158 f,
159 "WorkerConfig{{worker_num={}, reactor_num={}, task_worker_num={}, cpu={}}}",
160 self.worker_num,
161 self.reactor_num,
162 self.task_worker_num,
163 self.cpu_num()
164 )
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171
172 static ENV_TEST_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
175
176 #[test]
177 fn test_new_defaults_to_cpu_count() {
178 let config = WorkerConfig::new();
179 let cpu = num_cpus::get();
180 assert_eq!(config.worker_num(), cpu);
181 assert_eq!(config.reactor_num(), cpu);
182 assert_eq!(config.task_worker_num(), cpu);
183 }
184
185 #[test]
186 fn test_with_worker_num_custom() {
187 let config = WorkerConfig::new().with_worker_num(8);
188 assert_eq!(config.worker_num(), 8);
189 }
190
191 #[test]
192 fn test_with_worker_num_zero_falls_back_to_cpu() {
193 let config = WorkerConfig::new().with_worker_num(0);
194 assert_eq!(config.worker_num(), num_cpus::get());
195 }
196
197 #[test]
198 fn test_with_worker_num_exceeds_max_clamped() {
199 let config = WorkerConfig::new().with_worker_num(1024);
200 assert_eq!(config.worker_num(), MAX_WORKER_NUM);
201 }
202
203 #[test]
204 fn test_with_reactor_num_custom() {
205 let config = WorkerConfig::new().with_reactor_num(4);
206 assert_eq!(config.reactor_num(), 4);
207 }
208
209 #[test]
210 fn test_with_task_worker_num_custom() {
211 let config = WorkerConfig::new().with_task_worker_num(16);
212 assert_eq!(config.task_worker_num(), 16);
213 }
214
215 #[test]
216 fn test_cpu_num_matches_num_cpus() {
217 let config = WorkerConfig::new();
218 assert_eq!(config.cpu_num(), num_cpus::get());
219 }
220
221 #[test]
222 fn test_validate_valid_config() {
223 let config = WorkerConfig::new();
224 assert!(config.validate());
225 }
226
227 #[test]
228 fn test_validate_boundary_values() {
229 let config_min = WorkerConfig::new()
230 .with_worker_num(MIN_WORKER_NUM)
231 .with_reactor_num(MIN_WORKER_NUM)
232 .with_task_worker_num(MIN_WORKER_NUM);
233 assert!(config_min.validate());
234
235 let config_max = WorkerConfig::new()
236 .with_worker_num(MAX_WORKER_NUM)
237 .with_reactor_num(MAX_WORKER_NUM)
238 .with_task_worker_num(MAX_WORKER_NUM);
239 assert!(config_max.validate());
240 }
241
242 #[test]
243 fn test_from_env_default() {
244 let _guard = ENV_TEST_LOCK.lock();
247 std::env::remove_var("SZ_RUST_WORKER_NUM");
248 let config = WorkerConfig::from_env();
249 assert_eq!(config.worker_num(), num_cpus::get());
250 }
251
252 #[test]
253 fn test_from_env_custom() {
254 let _guard = ENV_TEST_LOCK.lock();
255 std::env::set_var("SZ_RUST_WORKER_NUM", "12");
256 let config = WorkerConfig::from_env();
257 assert_eq!(config.worker_num(), 12);
258 std::env::remove_var("SZ_RUST_WORKER_NUM");
259 }
260
261 #[test]
262 fn test_from_env_invalid_falls_back_to_default() {
263 let _guard = ENV_TEST_LOCK.lock();
264 std::env::set_var("SZ_RUST_WORKER_NUM", "not-a-number");
265 let config = WorkerConfig::from_env();
266 assert_eq!(config.worker_num(), num_cpus::get());
267 std::env::remove_var("SZ_RUST_WORKER_NUM");
268 }
269
270 #[test]
271 fn test_display_format() {
272 let config = WorkerConfig::new().with_worker_num(4);
273 let s = format!("{}", config);
274 assert!(s.contains("worker_num=4"));
275 assert!(s.contains("reactor_num="));
276 assert!(s.contains("task_worker_num="));
277 }
278
279 #[test]
280 fn test_default_equals_new() {
281 let config1 = WorkerConfig::default();
282 let config2 = WorkerConfig::new();
283 assert_eq!(config1, config2);
284 }
285
286 #[test]
287 fn test_clone_and_equality() {
288 let config1 = WorkerConfig::new().with_worker_num(4);
289 let config2 = config1.clone();
290 assert_eq!(config1, config2);
291 }
292
293 #[test]
294 fn test_builder_chaining() {
295 let config = WorkerConfig::new()
296 .with_worker_num(4)
297 .with_reactor_num(2)
298 .with_task_worker_num(8);
299 assert_eq!(config.worker_num(), 4);
300 assert_eq!(config.reactor_num(), 2);
301 assert_eq!(config.task_worker_num(), 8);
302 assert!(config.validate());
303 }
304}