1use crate::core::types::TrackingResult;
6use crate::export::fast_export_coordinator::FastExportConfigBuilder;
7#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
11pub enum OptimizationTarget {
12 Speed,
13 Memory,
14 Balanced,
15}
16use crate::export::system_optimizer::SystemOptimizer;
17use serde::{Deserialize, Serialize};
18
19pub struct ConfigOptimizer {
21 system_optimizer: SystemOptimizer,
22 optimization_history: Vec<OptimizationRecord>,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct OptimizationRecord {
28 pub timestamp: u64,
30 pub target: OptimizationTarget,
32 pub original_config: ConfigSnapshot,
34 pub optimized_config: ConfigSnapshot,
36 pub performance_improvement: f64,
38 pub success_rate: f64,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct ConfigSnapshot {
45 pub shard_size: usize,
47 pub thread_count: usize,
49 pub buffer_size: usize,
51 pub config_hash: String,
53}
54
55impl ConfigOptimizer {
56 pub fn new() -> TrackingResult<Self> {
58 Ok(Self {
59 system_optimizer: SystemOptimizer::new()?,
60 optimization_history: Vec::new(),
61 })
62 }
63
64 pub fn auto_optimize(
66 &mut self,
67 target: OptimizationTarget,
68 dataset_size: Option<usize>,
69 ) -> TrackingResult<FastExportConfigBuilder> {
70 let recommendation = self
72 .system_optimizer
73 .generate_configuration_recommendation(target, dataset_size);
74
75 let config_builder = FastExportConfigBuilder::new()
77 .shard_size(recommendation.recommended_shard_size)
78 .max_threads(Some(recommendation.recommended_thread_count))
79 .buffer_size(recommendation.recommended_buffer_size)
80 .performance_monitoring(true);
81
82 let validation_result = self
84 .system_optimizer
85 .validate_configuration(&config_builder);
86
87 if !validation_result.is_valid {
88 tracing::warn!("⚠️ configuration validation failed, using default configuration");
89 for error in &validation_result.errors {
90 tracing::warn!(" Error : {}", error);
91 }
92 return Ok(FastExportConfigBuilder::new());
93 }
94
95 let record = OptimizationRecord {
97 timestamp: std::time::SystemTime::now()
98 .duration_since(std::time::UNIX_EPOCH)
99 .unwrap_or_default()
100 .as_secs(),
101 target,
102 original_config: ConfigSnapshot {
103 shard_size: 1000,
104 thread_count: 4,
105 buffer_size: 256 * 1024,
106 config_hash: "default".to_string(),
107 },
108 optimized_config: ConfigSnapshot {
109 shard_size: recommendation.recommended_shard_size,
110 thread_count: recommendation.recommended_thread_count,
111 buffer_size: recommendation.recommended_buffer_size,
112 config_hash: format!(
113 "{:x}",
114 recommendation.recommended_shard_size
115 ^ recommendation.recommended_thread_count
116 ^ recommendation.recommended_buffer_size
117 ),
118 },
119 performance_improvement: recommendation.expected_performance_gain,
120 success_rate: recommendation.confidence,
121 };
122
123 self.optimization_history.push(record);
124
125 Ok(config_builder)
126 }
127
128 pub fn get_optimization_history(&self) -> &[OptimizationRecord] {
130 &self.optimization_history
131 }
132
133 pub fn clear_history(&mut self) {
135 self.optimization_history.clear();
136 }
137}
138
139impl Default for ConfigOptimizer {
140 fn default() -> Self {
141 Self::new().unwrap_or_else(|_| Self {
142 system_optimizer: SystemOptimizer::default(),
143 optimization_history: Vec::new(),
144 })
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 fn test_config_optimizer_new() {
154 let optimizer = ConfigOptimizer::new();
156 assert!(optimizer.is_ok());
157
158 let optimizer = optimizer.unwrap();
159 assert!(optimizer.optimization_history.is_empty());
160 }
161
162 #[test]
163 fn test_config_optimizer_default() {
164 let optimizer = ConfigOptimizer::default();
166 assert!(optimizer.optimization_history.is_empty());
167 }
168
169 #[test]
170 fn test_optimization_target_equality() {
171 assert_eq!(OptimizationTarget::Speed, OptimizationTarget::Speed);
173 assert_ne!(OptimizationTarget::Speed, OptimizationTarget::Memory);
174 assert_ne!(OptimizationTarget::Memory, OptimizationTarget::Balanced);
175 }
176
177 #[test]
178 fn test_auto_optimize_speed() {
179 let mut optimizer = ConfigOptimizer::new().unwrap();
181 let result = optimizer.auto_optimize(OptimizationTarget::Speed, Some(10000));
182
183 assert!(result.is_ok());
184 let config_builder = result.unwrap();
185 let config = config_builder.build();
188 assert!(config.shard_config.shard_size > 0);
190 }
191
192 #[test]
193 fn test_auto_optimize_memory() {
194 let mut optimizer = ConfigOptimizer::new().unwrap();
196 let result = optimizer.auto_optimize(OptimizationTarget::Memory, Some(5000));
197
198 assert!(result.is_ok());
199 assert!(!optimizer.optimization_history.is_empty());
200 }
201
202 #[test]
203 fn test_auto_optimize_balanced() {
204 let mut optimizer = ConfigOptimizer::new().unwrap();
206 let result = optimizer.auto_optimize(OptimizationTarget::Balanced, None);
207
208 assert!(result.is_ok());
209 assert_eq!(optimizer.optimization_history.len(), 1);
211
212 let record = &optimizer.optimization_history[0];
213 assert_eq!(record.target, OptimizationTarget::Balanced);
214 assert!(record.timestamp > 0);
215 }
216
217 #[test]
218 fn test_optimization_history() {
219 let mut optimizer = ConfigOptimizer::new().unwrap();
221
222 let _ = optimizer.auto_optimize(OptimizationTarget::Speed, Some(1000));
224 let _ = optimizer.auto_optimize(OptimizationTarget::Memory, Some(2000));
225 let _ = optimizer.auto_optimize(OptimizationTarget::Balanced, Some(3000));
226
227 let history = optimizer.get_optimization_history();
229 assert_eq!(history.len(), 3);
230
231 assert_eq!(history[0].target, OptimizationTarget::Speed);
233 assert_eq!(history[1].target, OptimizationTarget::Memory);
234 assert_eq!(history[2].target, OptimizationTarget::Balanced);
235
236 for record in history {
238 assert!(record.timestamp > 0);
239 assert!(!record.optimized_config.config_hash.is_empty());
240 }
241 }
242
243 #[test]
244 fn test_clear_history() {
245 let mut optimizer = ConfigOptimizer::new().unwrap();
247
248 let _ = optimizer.auto_optimize(OptimizationTarget::Speed, Some(1000));
250 let _ = optimizer.auto_optimize(OptimizationTarget::Memory, Some(2000));
251
252 assert!(!optimizer.optimization_history.is_empty());
253
254 optimizer.clear_history();
256 assert!(optimizer.optimization_history.is_empty());
257 assert_eq!(optimizer.get_optimization_history().len(), 0);
258 }
259
260 #[test]
261 fn test_config_snapshot_fields() {
262 let snapshot = ConfigSnapshot {
264 shard_size: 1000,
265 thread_count: 8,
266 buffer_size: 512 * 1024,
267 config_hash: "test_hash".to_string(),
268 };
269
270 assert_eq!(snapshot.shard_size, 1000);
271 assert_eq!(snapshot.thread_count, 8);
272 assert_eq!(snapshot.buffer_size, 512 * 1024);
273 assert_eq!(snapshot.config_hash, "test_hash");
274 }
275
276 #[test]
277 fn test_optimization_record_fields() {
278 let original = ConfigSnapshot {
280 shard_size: 500,
281 thread_count: 4,
282 buffer_size: 256 * 1024,
283 config_hash: "original".to_string(),
284 };
285
286 let optimized = ConfigSnapshot {
287 shard_size: 1000,
288 thread_count: 8,
289 buffer_size: 512 * 1024,
290 config_hash: "optimized".to_string(),
291 };
292
293 let record = OptimizationRecord {
294 timestamp: 1234567890,
295 target: OptimizationTarget::Speed,
296 original_config: original.clone(),
297 optimized_config: optimized.clone(),
298 performance_improvement: 25.5,
299 success_rate: 0.95,
300 };
301
302 assert_eq!(record.timestamp, 1234567890);
303 assert_eq!(record.target, OptimizationTarget::Speed);
304 assert_eq!(record.original_config.shard_size, 500);
305 assert_eq!(record.optimized_config.shard_size, 1000);
306 assert_eq!(record.performance_improvement, 25.5);
307 assert_eq!(record.success_rate, 0.95);
308 }
309
310 #[test]
311 fn test_multiple_optimizations_different_sizes() {
312 let mut optimizer = ConfigOptimizer::new().unwrap();
314
315 let sizes = vec![Some(100), Some(1000), Some(10000), Some(100000), None];
316 for size in sizes {
317 let result = optimizer.auto_optimize(OptimizationTarget::Balanced, size);
318 assert!(result.is_ok());
319 }
320
321 assert_eq!(optimizer.get_optimization_history().len(), 5);
323 }
324
325 #[test]
326 fn test_optimization_with_validation_scenario() {
327 let mut optimizer = ConfigOptimizer::new().unwrap();
330
331 let result = optimizer.auto_optimize(OptimizationTarget::Speed, Some(usize::MAX / 2));
333 assert!(result.is_ok());
334
335 let config_builder = result.unwrap();
337 let config = config_builder.build();
338 assert!(config.shard_config.shard_size > 0);
339 }
340
341 #[test]
342 fn test_serialization_of_types() {
343 let target = OptimizationTarget::Memory;
345 let serialized = serde_json::to_string(&target).unwrap();
346 let deserialized: OptimizationTarget = serde_json::from_str(&serialized).unwrap();
347 assert_eq!(target, deserialized);
348
349 let snapshot = ConfigSnapshot {
350 shard_size: 2000,
351 thread_count: 16,
352 buffer_size: 1024 * 1024,
353 config_hash: "hash123".to_string(),
354 };
355 let serialized = serde_json::to_string(&snapshot).unwrap();
356 let deserialized: ConfigSnapshot = serde_json::from_str(&serialized).unwrap();
357 assert_eq!(snapshot.shard_size, deserialized.shard_size);
358 assert_eq!(snapshot.config_hash, deserialized.config_hash);
359 }
360}