Skip to main content

rez_next_cache/
error.rs

1//! Error types for the intelligent caching system
2
3use std::io;
4use thiserror::Error;
5
6/// Cache-specific error types
7#[derive(Error, Debug)]
8pub enum CacheError {
9    /// I/O error during cache operations
10    #[error("Cache I/O error: {0}")]
11    Io(#[from] io::Error),
12
13    /// Serialization/deserialization error
14    #[error("Cache serialization error: {0}")]
15    Serialization(#[from] serde_json::Error),
16
17    /// Cache capacity exceeded
18    #[error("Cache capacity exceeded: {current} >= {max}")]
19    CapacityExceeded { current: usize, max: usize },
20
21    /// Invalid cache configuration
22    #[error("Invalid cache configuration: {0}")]
23    InvalidConfig(String),
24
25    /// Cache entry not found
26    #[error("Cache entry not found: {key}")]
27    EntryNotFound { key: String },
28
29    /// Cache entry expired
30    #[error("Cache entry expired: {key}")]
31    EntryExpired { key: String },
32
33    /// Cache operation timeout
34    #[error("Cache operation timeout after {timeout_ms}ms")]
35    Timeout { timeout_ms: u64 },
36
37    /// Cache corruption detected
38    #[error("Cache corruption detected: {details}")]
39    Corruption { details: String },
40
41    /// Insufficient memory for cache operation
42    #[error("Insufficient memory: requested {requested} bytes, available {available} bytes")]
43    InsufficientMemory { requested: u64, available: u64 },
44
45    /// Cache lock contention
46    #[error("Cache lock contention: operation failed after {attempts} attempts")]
47    LockContention { attempts: u32 },
48
49    /// Predictive preheating error
50    #[error("Preheating error: {0}")]
51    PreheatingError(String),
52
53    /// Adaptive tuning error
54    #[error("Tuning error: {0}")]
55    TuningError(String),
56
57    /// Cache level error (L1, L2, etc.)
58    #[error("Cache level {level} error: {message}")]
59    CacheLevelError { level: String, message: String },
60
61    /// Generic cache error
62    #[error("Cache error: {0}")]
63    Generic(String),
64}
65
66impl CacheError {
67    /// Create a new capacity exceeded error
68    pub fn capacity_exceeded(current: usize, max: usize) -> Self {
69        Self::CapacityExceeded { current, max }
70    }
71
72    /// Create a new invalid config error
73    pub fn invalid_config<S: Into<String>>(message: S) -> Self {
74        Self::InvalidConfig(message.into())
75    }
76
77    /// Create a new entry not found error
78    pub fn entry_not_found<S: Into<String>>(key: S) -> Self {
79        Self::EntryNotFound { key: key.into() }
80    }
81
82    /// Create a new entry expired error
83    pub fn entry_expired<S: Into<String>>(key: S) -> Self {
84        Self::EntryExpired { key: key.into() }
85    }
86
87    /// Create a new timeout error
88    pub fn timeout(timeout_ms: u64) -> Self {
89        Self::Timeout { timeout_ms }
90    }
91
92    /// Create a new corruption error
93    pub fn corruption<S: Into<String>>(details: S) -> Self {
94        Self::Corruption {
95            details: details.into(),
96        }
97    }
98
99    /// Create a new insufficient memory error
100    pub fn insufficient_memory(requested: u64, available: u64) -> Self {
101        Self::InsufficientMemory {
102            requested,
103            available,
104        }
105    }
106
107    /// Create a new lock contention error
108    pub fn lock_contention(attempts: u32) -> Self {
109        Self::LockContention { attempts }
110    }
111
112    /// Create a new preheating error
113    pub fn preheating_error<S: Into<String>>(message: S) -> Self {
114        Self::PreheatingError(message.into())
115    }
116
117    /// Create a new tuning error
118    pub fn tuning_error<S: Into<String>>(message: S) -> Self {
119        Self::TuningError(message.into())
120    }
121
122    /// Create a new cache level error
123    pub fn cache_level_error<S: Into<String>>(level: S, message: S) -> Self {
124        Self::CacheLevelError {
125            level: level.into(),
126            message: message.into(),
127        }
128    }
129
130    /// Create a generic cache error
131    pub fn generic<S: Into<String>>(message: S) -> Self {
132        Self::Generic(message.into())
133    }
134
135    /// Check if the error is recoverable
136    pub fn is_recoverable(&self) -> bool {
137        match self {
138            CacheError::Io(_) => false,
139            CacheError::Serialization(_) => false,
140            CacheError::CapacityExceeded { .. } => true,
141            CacheError::InvalidConfig(_) => false,
142            CacheError::EntryNotFound { .. } => true,
143            CacheError::EntryExpired { .. } => true,
144            CacheError::Timeout { .. } => true,
145            CacheError::Corruption { .. } => false,
146            CacheError::InsufficientMemory { .. } => true,
147            CacheError::LockContention { .. } => true,
148            CacheError::PreheatingError(_) => true,
149            CacheError::TuningError(_) => true,
150            CacheError::CacheLevelError { .. } => true,
151            CacheError::Generic(_) => false,
152        }
153    }
154
155    /// Get error severity level
156    pub fn severity(&self) -> ErrorSeverity {
157        match self {
158            CacheError::Io(_) => ErrorSeverity::Critical,
159            CacheError::Serialization(_) => ErrorSeverity::High,
160            CacheError::CapacityExceeded { .. } => ErrorSeverity::Medium,
161            CacheError::InvalidConfig(_) => ErrorSeverity::High,
162            CacheError::EntryNotFound { .. } => ErrorSeverity::Low,
163            CacheError::EntryExpired { .. } => ErrorSeverity::Low,
164            CacheError::Timeout { .. } => ErrorSeverity::Medium,
165            CacheError::Corruption { .. } => ErrorSeverity::Critical,
166            CacheError::InsufficientMemory { .. } => ErrorSeverity::High,
167            CacheError::LockContention { .. } => ErrorSeverity::Medium,
168            CacheError::PreheatingError(_) => ErrorSeverity::Low,
169            CacheError::TuningError(_) => ErrorSeverity::Low,
170            CacheError::CacheLevelError { .. } => ErrorSeverity::Medium,
171            CacheError::Generic(_) => ErrorSeverity::Medium,
172        }
173    }
174}
175
176/// Error severity levels
177#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
178pub enum ErrorSeverity {
179    /// Low severity - operation can continue
180    Low,
181    /// Medium severity - may affect performance
182    Medium,
183    /// High severity - significant impact
184    High,
185    /// Critical severity - system may be unstable
186    Critical,
187}
188
189impl ErrorSeverity {
190    /// Get severity as a string
191    pub fn as_str(&self) -> &'static str {
192        match self {
193            ErrorSeverity::Low => "LOW",
194            ErrorSeverity::Medium => "MEDIUM",
195            ErrorSeverity::High => "HIGH",
196            ErrorSeverity::Critical => "CRITICAL",
197        }
198    }
199
200    /// Check if the severity requires immediate attention
201    pub fn requires_immediate_attention(&self) -> bool {
202        matches!(self, ErrorSeverity::High | ErrorSeverity::Critical)
203    }
204}
205
206/// Result type for cache operations
207pub type CacheResult<T> = Result<T, CacheError>;
208
209/// Error context for better error reporting
210#[derive(Debug, Clone)]
211pub struct ErrorContext {
212    /// Operation that failed
213    pub operation: String,
214    /// Cache level where error occurred
215    pub cache_level: Option<String>,
216    /// Additional context information
217    pub context: std::collections::HashMap<String, String>,
218    /// Timestamp when error occurred
219    pub timestamp: u64,
220}
221
222impl ErrorContext {
223    /// Create a new error context
224    pub fn new<S: Into<String>>(operation: S) -> Self {
225        Self {
226            operation: operation.into(),
227            cache_level: None,
228            context: std::collections::HashMap::new(),
229            timestamp: std::time::SystemTime::now()
230                .duration_since(std::time::UNIX_EPOCH)
231                .map(|d| d.as_secs())
232                .unwrap_or(0),
233        }
234    }
235
236    /// Set the cache level
237    pub fn with_cache_level<S: Into<String>>(mut self, level: S) -> Self {
238        self.cache_level = Some(level.into());
239        self
240    }
241
242    /// Add context information
243    pub fn with_context<K: Into<String>, V: Into<String>>(mut self, key: K, value: V) -> Self {
244        self.context.insert(key.into(), value.into());
245        self
246    }
247}
248
249/// Enhanced cache error with context
250#[derive(Debug)]
251pub struct ContextualCacheError {
252    /// The underlying cache error
253    pub error: CacheError,
254    /// Error context
255    pub context: ErrorContext,
256}
257
258impl ContextualCacheError {
259    /// Create a new contextual error
260    pub fn new(error: CacheError, context: ErrorContext) -> Self {
261        Self { error, context }
262    }
263
264    /// Get the error severity
265    pub fn severity(&self) -> ErrorSeverity {
266        self.error.severity()
267    }
268
269    /// Check if the error is recoverable
270    pub fn is_recoverable(&self) -> bool {
271        self.error.is_recoverable()
272    }
273}
274
275impl std::fmt::Display for ContextualCacheError {
276    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
277        write!(
278            f,
279            "Cache error in operation '{}': {} (severity: {})",
280            self.context.operation,
281            self.error,
282            self.severity().as_str()
283        )?;
284
285        if let Some(ref level) = self.context.cache_level {
286            write!(f, " [cache level: {}]", level)?;
287        }
288
289        if !self.context.context.is_empty() {
290            write!(f, " [context: {:?}]", self.context.context)?;
291        }
292
293        Ok(())
294    }
295}
296
297impl std::error::Error for ContextualCacheError {
298    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
299        Some(&self.error)
300    }
301}
302
303#[cfg(test)]
304mod tests {
305    use super::*;
306
307    #[test]
308    fn test_cache_error_creation() {
309        let error = CacheError::capacity_exceeded(100, 50);
310        assert!(matches!(
311            error,
312            CacheError::CapacityExceeded {
313                current: 100,
314                max: 50
315            }
316        ));
317        assert!(error.is_recoverable());
318        assert_eq!(error.severity(), ErrorSeverity::Medium);
319    }
320
321    #[test]
322    fn test_error_context() {
323        let context = ErrorContext::new("get_operation")
324            .with_cache_level("L1")
325            .with_context("key", "test_key");
326
327        assert_eq!(context.operation, "get_operation");
328        assert_eq!(context.cache_level, Some("L1".to_string()));
329        assert_eq!(context.context.get("key"), Some(&"test_key".to_string()));
330    }
331
332    #[test]
333    fn test_contextual_error() {
334        let error = CacheError::timeout(1000);
335        let context = ErrorContext::new("put_operation");
336        let contextual_error = ContextualCacheError::new(error, context);
337
338        assert_eq!(contextual_error.severity(), ErrorSeverity::Medium);
339        assert!(contextual_error.is_recoverable());
340    }
341
342    #[test]
343    fn test_error_severity() {
344        assert!(ErrorSeverity::Critical.requires_immediate_attention());
345        assert!(ErrorSeverity::High.requires_immediate_attention());
346        assert!(!ErrorSeverity::Medium.requires_immediate_attention());
347        assert!(!ErrorSeverity::Low.requires_immediate_attention());
348    }
349}