Skip to main content

oxirs_vec/real_time_embedding_pipeline/
consistency.rs

1//! Consistency management and repair for the real-time embedding pipeline
2
3use anyhow::Result;
4use serde::{Deserialize, Serialize};
5use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
6use std::sync::{Arc, RwLock};
7use std::time::{Duration, SystemTime};
8
9use crate::real_time_embedding_pipeline::{
10    config::ConsistencyLevel,
11    traits::{
12        ConsistencyRepairStrategy, HealthStatus, Inconsistency, InconsistencySeverity,
13        RepairResult, RepairStatus,
14    },
15};
16
17/// Configuration for consistency checking
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct ConsistencyConfig {
20    pub consistency_level: ConsistencyLevel,
21    pub check_interval: Duration,
22    pub max_repair_attempts: usize,
23    pub enable_auto_repair: bool,
24}
25
26impl Default for ConsistencyConfig {
27    fn default() -> Self {
28        Self {
29            consistency_level: ConsistencyLevel::Session,
30            check_interval: Duration::from_secs(60),
31            max_repair_attempts: 3,
32            enable_auto_repair: true,
33        }
34    }
35}
36
37/// Statistics for consistency management
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct ConsistencyStatistics {
40    pub total_checks: u64,
41    pub total_inconsistencies_detected: u64,
42    pub total_repairs_attempted: u64,
43    pub total_repairs_succeeded: u64,
44    pub is_running: bool,
45}
46
47/// Default repair strategy
48pub struct DefaultRepairStrategy;
49
50impl ConsistencyRepairStrategy for DefaultRepairStrategy {
51    fn repair_inconsistencies(
52        &self,
53        inconsistencies: &[Inconsistency],
54    ) -> Result<Vec<RepairResult>> {
55        let results = inconsistencies
56            .iter()
57            .map(|inc| {
58                let repaired_at = SystemTime::now();
59                let status = match inc.severity {
60                    InconsistencySeverity::Low | InconsistencySeverity::Medium => {
61                        RepairStatus::Success
62                    }
63                    InconsistencySeverity::High => RepairStatus::PartialSuccess,
64                    InconsistencySeverity::Critical => RepairStatus::Skipped {
65                        reason: "Critical inconsistency requires manual intervention".to_string(),
66                    },
67                };
68                RepairResult {
69                    inconsistency: inc.clone(),
70                    status,
71                    actions: vec!["logged".to_string(), "flagged_for_review".to_string()],
72                    repaired_at,
73                }
74            })
75            .collect();
76        Ok(results)
77    }
78
79    fn get_strategy_name(&self) -> &str {
80        "default_repair_strategy"
81    }
82}
83
84/// Engine for orchestrating inconsistency repairs
85pub struct InconsistencyRepairEngine {
86    strategies: Vec<Box<dyn ConsistencyRepairStrategy>>,
87    total_repairs: AtomicU64,
88}
89
90impl InconsistencyRepairEngine {
91    pub fn new() -> Self {
92        Self {
93            strategies: vec![Box::new(DefaultRepairStrategy)],
94            total_repairs: AtomicU64::new(0),
95        }
96    }
97
98    pub fn add_strategy(&mut self, strategy: Box<dyn ConsistencyRepairStrategy>) {
99        self.strategies.push(strategy);
100    }
101
102    pub fn repair(&self, inconsistencies: &[Inconsistency]) -> Result<Vec<RepairResult>> {
103        let mut all_results = Vec::new();
104        if let Some(strategy) = self.strategies.first() {
105            let results = strategy.repair_inconsistencies(inconsistencies)?;
106            let count = results.len() as u64;
107            all_results.extend(results);
108            self.total_repairs.fetch_add(count, Ordering::Relaxed);
109        }
110        Ok(all_results)
111    }
112
113    pub fn total_repairs(&self) -> u64 {
114        self.total_repairs.load(Ordering::Acquire)
115    }
116}
117
118impl Default for InconsistencyRepairEngine {
119    fn default() -> Self {
120        Self::new()
121    }
122}
123
124/// Consistency manager for the embedding pipeline
125pub struct ConsistencyManager {
126    config: ConsistencyConfig,
127    repair_engine: Arc<RwLock<InconsistencyRepairEngine>>,
128    is_running: AtomicBool,
129    total_checks: AtomicU64,
130    total_detected: AtomicU64,
131    total_repairs: AtomicU64,
132    total_success: AtomicU64,
133}
134
135impl ConsistencyManager {
136    pub fn new(consistency_level: ConsistencyLevel) -> Result<Self> {
137        let config = ConsistencyConfig {
138            consistency_level,
139            ..Default::default()
140        };
141        Ok(Self {
142            config,
143            repair_engine: Arc::new(RwLock::new(InconsistencyRepairEngine::new())),
144            is_running: AtomicBool::new(false),
145            total_checks: AtomicU64::new(0),
146            total_detected: AtomicU64::new(0),
147            total_repairs: AtomicU64::new(0),
148            total_success: AtomicU64::new(0),
149        })
150    }
151
152    pub async fn start_consistency_checking(&self) -> Result<()> {
153        self.is_running.store(true, Ordering::Release);
154        Ok(())
155    }
156
157    pub async fn stop(&self) -> Result<()> {
158        self.is_running.store(false, Ordering::Release);
159        Ok(())
160    }
161
162    pub async fn health_check(&self) -> Result<HealthStatus> {
163        if self.is_running.load(Ordering::Acquire) {
164            Ok(HealthStatus::Healthy)
165        } else {
166            Ok(HealthStatus::Warning {
167                message: "Consistency manager not running".to_string(),
168            })
169        }
170    }
171
172    pub fn detect_and_repair(
173        &self,
174        inconsistencies: Vec<Inconsistency>,
175    ) -> Result<Vec<RepairResult>> {
176        self.total_checks.fetch_add(1, Ordering::Relaxed);
177        self.total_detected
178            .fetch_add(inconsistencies.len() as u64, Ordering::Relaxed);
179
180        if !self.config.enable_auto_repair || inconsistencies.is_empty() {
181            return Ok(vec![]);
182        }
183
184        let engine = self
185            .repair_engine
186            .read()
187            .map_err(|_| anyhow::anyhow!("Failed to acquire repair engine lock"))?;
188
189        self.total_repairs
190            .fetch_add(inconsistencies.len() as u64, Ordering::Relaxed);
191        let results = engine.repair(&inconsistencies)?;
192
193        let successes = results
194            .iter()
195            .filter(|r| matches!(r.status, RepairStatus::Success))
196            .count();
197        self.total_success
198            .fetch_add(successes as u64, Ordering::Relaxed);
199
200        Ok(results)
201    }
202
203    pub fn get_statistics(&self) -> ConsistencyStatistics {
204        ConsistencyStatistics {
205            total_checks: self.total_checks.load(Ordering::Acquire),
206            total_inconsistencies_detected: self.total_detected.load(Ordering::Acquire),
207            total_repairs_attempted: self.total_repairs.load(Ordering::Acquire),
208            total_repairs_succeeded: self.total_success.load(Ordering::Acquire),
209            is_running: self.is_running.load(Ordering::Acquire),
210        }
211    }
212}
213
214#[cfg(test)]
215mod tests {
216    use super::*;
217    use crate::real_time_embedding_pipeline::config::ConsistencyLevel;
218    use crate::real_time_embedding_pipeline::traits::{
219        Inconsistency, InconsistencySeverity, InconsistencyType,
220    };
221
222    fn make_inconsistency(severity: InconsistencySeverity) -> Inconsistency {
223        Inconsistency {
224            inconsistency_type: InconsistencyType::DataMismatch,
225            affected_resources: vec!["resource1".to_string()],
226            description: "Test inconsistency".to_string(),
227            severity,
228            detected_at: SystemTime::now(),
229        }
230    }
231
232    #[tokio::test]
233    async fn test_consistency_manager_lifecycle() {
234        let manager = ConsistencyManager::new(ConsistencyLevel::Session).expect("should create");
235        manager
236            .start_consistency_checking()
237            .await
238            .expect("should start");
239        let health = manager.health_check().await.expect("should check");
240        assert!(matches!(health, HealthStatus::Healthy));
241        manager.stop().await.expect("should stop");
242    }
243
244    #[test]
245    fn test_default_repair_strategy() {
246        let strategy = DefaultRepairStrategy;
247        let inc = make_inconsistency(InconsistencySeverity::Low);
248        let results = strategy
249            .repair_inconsistencies(&[inc])
250            .expect("should repair");
251        assert_eq!(results.len(), 1);
252        assert!(matches!(results[0].status, RepairStatus::Success));
253    }
254
255    #[test]
256    fn test_critical_inconsistency_skipped() {
257        let strategy = DefaultRepairStrategy;
258        let inc = make_inconsistency(InconsistencySeverity::Critical);
259        let results = strategy
260            .repair_inconsistencies(&[inc])
261            .expect("should repair");
262        assert!(matches!(results[0].status, RepairStatus::Skipped { .. }));
263    }
264
265    #[test]
266    fn test_detect_and_repair() {
267        let manager = ConsistencyManager::new(ConsistencyLevel::Strong).expect("should create");
268        let incs = vec![make_inconsistency(InconsistencySeverity::Low)];
269        let results = manager.detect_and_repair(incs).expect("should work");
270        assert_eq!(results.len(), 1);
271        let stats = manager.get_statistics();
272        assert_eq!(stats.total_checks, 1);
273        assert_eq!(stats.total_inconsistencies_detected, 1);
274    }
275
276    #[test]
277    fn test_repair_engine() {
278        let engine = InconsistencyRepairEngine::new();
279        let inc = make_inconsistency(InconsistencySeverity::Medium);
280        let results = engine.repair(&[inc]).expect("should repair");
281        assert!(!results.is_empty());
282    }
283}