memscope_rs/export/
export_modes.rs

1//! Export mode system
2//!
3//! Provides Fast and Normal export modes using Rust Futures for asynchronous export operations
4
5use crate::core::types::TrackingResult;
6use crate::export::fast_export_coordinator::{CompleteExportStats, FastExportCoordinator};
7use crate::export::quality_validator::{
8    ExportConfig, ExportMode, ExportModeManager, QualityValidator, ValidationResult,
9    ValidationTiming,
10};
11use std::future::Future;
12use std::path::Path;
13use std::pin::Pin;
14
15// ExportMode is now defined in quality_validator.rs
16
17/// Fast Future result type
18pub type FastExportResult = TrackingResult<CompleteExportStats>;
19
20/// Normal Future result type  
21pub type NormalExportResult = TrackingResult<(CompleteExportStats, ValidationResult)>;
22
23/// Export result type
24#[derive(Debug)]
25pub enum ExportOutcome {
26    /// Fast export result (no validation)
27    Fast(CompleteExportStats),
28    /// Normal export result (with validation)
29    WithValidation(CompleteExportStats, ValidationResult),
30}
31
32/// Fast Future: pure export, no validation
33pub fn export_fast<P: AsRef<Path>>(
34    output_path: P,
35) -> Pin<Box<dyn Future<Output = FastExportResult> + Send>> {
36    let path = output_path.as_ref().to_path_buf();
37
38    Box::pin(async move {
39        tracing::info!("🚀 Starting fast export mode (no validation)");
40
41        // create fast mode coordinator
42        let mut coordinator = FastExportCoordinator::new_fast_mode();
43
44        // pure export, skip all validation
45        let stats = coordinator.export_without_validation(&path).await?;
46
47        tracing::info!(
48            "✅ Fast export completed: {} allocations, {:.2} MB",
49            stats.parallel_processing.total_allocations,
50            stats.write_performance.total_bytes_written as f64 / 1024.0 / 1024.0
51        );
52
53        Ok(stats)
54    })
55}
56
57/// Export with validation: export first, then validate
58pub fn export_with_validation<P: AsRef<Path>>(
59    output_path: P,
60) -> Pin<Box<dyn Future<Output = NormalExportResult> + Send>> {
61    let path = output_path.as_ref().to_path_buf();
62
63    Box::pin(async move {
64        tracing::info!("🚀 Starting export with validation mode (export first, then validate)");
65
66        // Step 1: Complete export
67        tracing::info!("📝 Step 1: Executing export...");
68        let mut coordinator = FastExportCoordinator::new_normal_mode();
69        let stats = coordinator.export_without_validation(&path).await?;
70
71        tracing::info!(
72            "✅ Export completed: {} allocations, {:.2} MB",
73            stats.parallel_processing.total_allocations,
74            stats.write_performance.total_bytes_written as f64 / 1024.0 / 1024.0
75        );
76
77        // Step 2: Validate after export completion
78        tracing::info!("🔍 Step 2: Executing validation...");
79        let mut validator = QualityValidator::new_default();
80        let validation_result = validator.validate_file_async(&path).await?;
81
82        tracing::info!(
83            "✅ Validation completed: {}",
84            if validation_result.is_valid {
85                "PASSED"
86            } else {
87                "FAILED"
88            }
89        );
90
91        Ok((stats, validation_result))
92    })
93}
94
95/// Export coordinator - unified export interface with configuration management
96pub struct ExportCoordinator {
97    /// Export configuration
98    config: ExportConfig,
99    /// Mode manager for automatic optimizations
100    mode_manager: ExportModeManager,
101}
102
103impl ExportCoordinator {
104    /// Create new export coordinator with configuration
105    pub fn new(config: ExportConfig) -> Self {
106        Self {
107            config,
108            mode_manager: ExportModeManager::new(),
109        }
110    }
111
112    /// Create coordinator with fast mode configuration
113    pub fn new_fast() -> Self {
114        Self::new(ExportConfig::fast())
115    }
116
117    /// Create coordinator with slow mode configuration  
118    pub fn new_slow() -> Self {
119        Self::new(ExportConfig::slow())
120    }
121
122    /// Create coordinator with auto mode configuration
123    pub fn new_auto() -> Self {
124        Self::new(ExportConfig::auto())
125    }
126
127    /// Create coordinator with automatic configuration based on data size
128    pub fn new_auto_sized(data_size: usize) -> Self {
129        let mode_manager = ExportModeManager::new();
130        let config = mode_manager.create_auto_config(data_size);
131        Self::new(config)
132    }
133
134    /// Execute export with current configuration
135    pub async fn export<P: AsRef<Path>>(&self, output_path: P) -> TrackingResult<ExportOutcome> {
136        match (&self.config.mode, &self.config.validation_timing) {
137            (ExportMode::Fast, _) | (_, ValidationTiming::Disabled) => {
138                let stats = export_fast(output_path).await?;
139                Ok(ExportOutcome::Fast(stats))
140            }
141            (ExportMode::Slow, ValidationTiming::Inline) => {
142                // For inline validation in slow mode, we still use the normal flow
143                // but with more comprehensive validation
144                let (stats, validation) = export_with_validation(output_path).await?;
145                Ok(ExportOutcome::WithValidation(stats, validation))
146            }
147            _ => {
148                // Default to deferred validation
149                let (stats, validation) = export_with_validation(output_path).await?;
150                Ok(ExportOutcome::WithValidation(stats, validation))
151            }
152        }
153    }
154
155    /// Get current configuration
156    pub fn config(&self) -> &ExportConfig {
157        &self.config
158    }
159
160    /// Update configuration with validation and optimization
161    pub fn update_config(
162        &mut self,
163        mut config: ExportConfig,
164        data_size: Option<usize>,
165    ) -> Vec<String> {
166        let mut warnings = config.validate_and_fix();
167
168        if let Some(size) = data_size {
169            let (optimized_config, optimization_warnings) =
170                self.mode_manager.optimize_config(config, size);
171            config = optimized_config;
172            warnings.extend(optimization_warnings);
173        }
174
175        self.config = config;
176        warnings
177    }
178
179    /// Get mode manager for advanced configuration
180    pub fn mode_manager(&self) -> &ExportModeManager {
181        &self.mode_manager
182    }
183}
184
185#[cfg(test)]
186mod tests {
187    use super::*;
188    use crate::export::error_handling::ValidationType;
189
190    #[test]
191    fn test_export_outcome_debug() {
192        let stats = create_test_stats();
193        let outcome = ExportOutcome::Fast(stats.clone());
194        let debug_str = format!("{outcome:?}");
195        assert!(debug_str.contains("Fast"));
196
197        let validation = create_test_validation_result();
198        let outcome = ExportOutcome::WithValidation(stats, validation);
199        let debug_str = format!("{outcome:?}");
200        assert!(debug_str.contains("WithValidation"));
201    }
202
203    #[test]
204    fn test_fast_export_result_type() {
205        let _result: FastExportResult = Ok(create_test_stats());
206        // Just testing that the type is correctly defined
207    }
208
209    #[test]
210    fn test_normal_export_result_type() {
211        let _result: NormalExportResult =
212            Ok((create_test_stats(), create_test_validation_result()));
213        // Just testing that the type is correctly defined
214    }
215
216    #[test]
217    fn test_export_coordinator_new() {
218        let config = ExportConfig::fast();
219        let coordinator = ExportCoordinator::new(config.clone());
220
221        assert_eq!(coordinator.config().mode, config.mode);
222        assert_eq!(
223            coordinator.config().validation_timing,
224            config.validation_timing
225        );
226    }
227
228    #[test]
229    fn test_export_coordinator_new_fast() {
230        let coordinator = ExportCoordinator::new_fast();
231
232        assert_eq!(coordinator.config().mode, ExportMode::Fast);
233        assert_eq!(
234            coordinator.config().validation_timing,
235            ValidationTiming::Deferred
236        );
237    }
238
239    #[test]
240    fn test_export_coordinator_new_slow() {
241        let coordinator = ExportCoordinator::new_slow();
242
243        assert_eq!(coordinator.config().mode, ExportMode::Slow);
244        assert_eq!(
245            coordinator.config().validation_timing,
246            ValidationTiming::Inline
247        );
248    }
249
250    #[test]
251    fn test_export_coordinator_new_auto() {
252        let coordinator = ExportCoordinator::new_auto();
253
254        assert_eq!(coordinator.config().mode, ExportMode::Auto);
255        assert_eq!(
256            coordinator.config().validation_timing,
257            ValidationTiming::Deferred
258        );
259    }
260
261    #[test]
262    fn test_export_coordinator_new_auto_sized() {
263        let coordinator = ExportCoordinator::new_auto_sized(1000);
264
265        // The mode should be determined based on data size
266        // Since the default mode manager uses Fast as default mode, it will always return Fast
267        assert_eq!(coordinator.config().mode, ExportMode::Fast);
268    }
269
270    #[test]
271    fn test_export_coordinator_update_config() {
272        let mut coordinator = ExportCoordinator::new_fast();
273        let _old_config = coordinator.config().clone();
274
275        let new_config = ExportConfig::slow();
276        let warnings = coordinator.update_config(new_config.clone(), None);
277
278        assert_eq!(coordinator.config().mode, new_config.mode);
279        assert_eq!(
280            coordinator.config().validation_timing,
281            new_config.validation_timing
282        );
283        // Should have no warnings for valid config
284        assert!(warnings.is_empty());
285    }
286
287    #[test]
288    fn test_export_coordinator_update_config_with_optimization() {
289        let mut coordinator = ExportCoordinator::new_fast();
290
291        let new_config = ExportConfig::slow();
292        let _warnings = coordinator.update_config(new_config.clone(), Some(1000000)); // Large data size
293
294        assert_eq!(coordinator.config().mode, new_config.mode);
295        assert_eq!(
296            coordinator.config().validation_timing,
297            new_config.validation_timing
298        );
299        // May have optimization warnings
300        // Just check that the function works without panicking
301    }
302
303    #[test]
304    fn test_export_coordinator_mode_manager() {
305        let coordinator = ExportCoordinator::new_fast();
306        let mode_manager = coordinator.mode_manager();
307
308        // Just check that we can get the mode manager
309        let (mode, threshold, _perf_threshold) = mode_manager.get_settings();
310        assert_eq!(mode, ExportMode::Fast);
311        assert!(threshold > 0);
312    }
313
314    // Helper functions for creating test data
315    fn create_test_stats() -> CompleteExportStats {
316        use crate::export::data_localizer::DataGatheringStats;
317        use crate::export::high_speed_buffered_writer::WritePerformanceStats;
318        use crate::export::parallel_shard_processor::ParallelProcessingStats;
319
320        CompleteExportStats {
321            data_gathering: DataGatheringStats {
322                total_time_ms: 50,
323                basic_data_time_ms: 30,
324                ffi_data_time_ms: 10,
325                scope_data_time_ms: 10,
326                allocation_count: 100,
327                ffi_allocation_count: 10,
328                scope_count: 50,
329            },
330            parallel_processing: ParallelProcessingStats {
331                total_allocations: 100,
332                shard_count: 4,
333                threads_used: 2,
334                total_processing_time_ms: 100,
335                avg_shard_processing_time_ms: 25.0,
336                parallel_efficiency: 1.8,
337                throughput_allocations_per_sec: 1000.0,
338                used_parallel_processing: true,
339                total_output_size_bytes: 10240,
340            },
341            write_performance: WritePerformanceStats {
342                total_bytes_written: 10240,
343                shards_written: 4,
344                total_write_time_ms: 50,
345                avg_write_speed_bps: 204800.0,
346                flush_count: 2,
347                preallocation_effective: true,
348                buffer_utilization: 0.8,
349            },
350            total_export_time_ms: 200,
351            total_allocations_processed: 100,
352            total_output_size_bytes: 10240,
353            overall_throughput_allocations_per_sec: 500.0,
354            overall_write_speed_mbps: 0.05,
355            data_gathering_percentage: 25.0,
356            processing_percentage: 50.0,
357            writing_percentage: 25.0,
358            estimated_traditional_time_ms: 1000,
359            performance_improvement_factor: 5.0,
360        }
361    }
362
363    fn create_test_validation_result() -> ValidationResult {
364        use crate::export::quality_validator::{IssueSeverity, IssueType, ValidationIssue};
365
366        ValidationResult {
367            is_valid: true,
368            validation_type: ValidationType::DataIntegrity,
369            message: "Test validation".to_string(),
370            issues: vec![ValidationIssue {
371                issue_type: IssueType::InconsistentData,
372                description: "Test issue".to_string(),
373                severity: IssueSeverity::Medium,
374                affected_data: "test_data".to_string(),
375                suggested_fix: Some("Fix the data".to_string()),
376                auto_fixable: false,
377            }],
378            validation_time_ms: 10,
379            data_size: 10240,
380        }
381    }
382}