1use std::io;
4use thiserror::Error;
5
6#[derive(Error, Debug)]
8pub enum CacheError {
9 #[error("Cache I/O error: {0}")]
11 Io(#[from] io::Error),
12
13 #[error("Cache serialization error: {0}")]
15 Serialization(#[from] serde_json::Error),
16
17 #[error("Cache capacity exceeded: {current} >= {max}")]
19 CapacityExceeded { current: usize, max: usize },
20
21 #[error("Invalid cache configuration: {0}")]
23 InvalidConfig(String),
24
25 #[error("Cache entry not found: {key}")]
27 EntryNotFound { key: String },
28
29 #[error("Cache entry expired: {key}")]
31 EntryExpired { key: String },
32
33 #[error("Cache operation timeout after {timeout_ms}ms")]
35 Timeout { timeout_ms: u64 },
36
37 #[error("Cache corruption detected: {details}")]
39 Corruption { details: String },
40
41 #[error("Insufficient memory: requested {requested} bytes, available {available} bytes")]
43 InsufficientMemory { requested: u64, available: u64 },
44
45 #[error("Cache lock contention: operation failed after {attempts} attempts")]
47 LockContention { attempts: u32 },
48
49 #[error("Preheating error: {0}")]
51 PreheatingError(String),
52
53 #[error("Tuning error: {0}")]
55 TuningError(String),
56
57 #[error("Cache level {level} error: {message}")]
59 CacheLevelError { level: String, message: String },
60
61 #[error("Cache error: {0}")]
63 Generic(String),
64}
65
66impl CacheError {
67 pub fn capacity_exceeded(current: usize, max: usize) -> Self {
69 Self::CapacityExceeded { current, max }
70 }
71
72 pub fn invalid_config<S: Into<String>>(message: S) -> Self {
74 Self::InvalidConfig(message.into())
75 }
76
77 pub fn entry_not_found<S: Into<String>>(key: S) -> Self {
79 Self::EntryNotFound { key: key.into() }
80 }
81
82 pub fn entry_expired<S: Into<String>>(key: S) -> Self {
84 Self::EntryExpired { key: key.into() }
85 }
86
87 pub fn timeout(timeout_ms: u64) -> Self {
89 Self::Timeout { timeout_ms }
90 }
91
92 pub fn corruption<S: Into<String>>(details: S) -> Self {
94 Self::Corruption {
95 details: details.into(),
96 }
97 }
98
99 pub fn insufficient_memory(requested: u64, available: u64) -> Self {
101 Self::InsufficientMemory {
102 requested,
103 available,
104 }
105 }
106
107 pub fn lock_contention(attempts: u32) -> Self {
109 Self::LockContention { attempts }
110 }
111
112 pub fn preheating_error<S: Into<String>>(message: S) -> Self {
114 Self::PreheatingError(message.into())
115 }
116
117 pub fn tuning_error<S: Into<String>>(message: S) -> Self {
119 Self::TuningError(message.into())
120 }
121
122 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 pub fn generic<S: Into<String>>(message: S) -> Self {
132 Self::Generic(message.into())
133 }
134
135 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 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#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
178pub enum ErrorSeverity {
179 Low,
181 Medium,
183 High,
185 Critical,
187}
188
189impl ErrorSeverity {
190 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 pub fn requires_immediate_attention(&self) -> bool {
202 matches!(self, ErrorSeverity::High | ErrorSeverity::Critical)
203 }
204}
205
206pub type CacheResult<T> = Result<T, CacheError>;
208
209#[derive(Debug, Clone)]
211pub struct ErrorContext {
212 pub operation: String,
214 pub cache_level: Option<String>,
216 pub context: std::collections::HashMap<String, String>,
218 pub timestamp: u64,
220}
221
222impl ErrorContext {
223 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 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 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#[derive(Debug)]
251pub struct ContextualCacheError {
252 pub error: CacheError,
254 pub context: ErrorContext,
256}
257
258impl ContextualCacheError {
259 pub fn new(error: CacheError, context: ErrorContext) -> Self {
261 Self { error, context }
262 }
263
264 pub fn severity(&self) -> ErrorSeverity {
266 self.error.severity()
267 }
268
269 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}