1use async_trait::async_trait;
6use chrono::{DateTime, Utc};
7use serde::{de::DeserializeOwned, Serialize};
8use std::collections::HashMap;
9use std::sync::Arc;
10use tokio::sync::RwLock;
11use tracing::{debug, error, info, instrument, warn};
12
13use super::error::{StorageError, StorageResult};
14use super::traits::{Backup, BackupMetadata, Migrator, Migration, Storage};
15use super::types::{
16 Batch, Query, StorageBackend, StorageEntry, StorageHealth, StorageMetadata, StorageStats,
17 Transaction,
18};
19use super::wrapper::AnyStorage;
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum ManagerState {
24 Uninitialized,
25 Initializing,
26 Running,
27 Stopping,
28 Stopped,
29 Failed,
30}
31
32#[derive(Debug, Clone, Default)]
34pub struct ManagerStats {
35 pub total_operations: u64,
37
38 pub successful_operations: u64,
40
41 pub failed_operations: u64,
43
44 pub operations_by_backend: HashMap<String, u64>,
46
47 pub fallback_count: u64,
49
50 pub last_updated: DateTime<Utc>,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum RoutingStrategy {
57 PrimaryOnly,
59 CacheAside,
61 MultiWrite,
63 FastestRead,
65}
66
67pub struct StorageManager {
69 state: Arc<RwLock<ManagerState>>,
71
72 primary: Option<Arc<AnyStorage>>,
74
75 cache: Option<Arc<AnyStorage>>,
77
78 secondary: Option<Arc<AnyStorage>>,
80
81 backends: Arc<RwLock<HashMap<StorageBackend, Arc<AnyStorage>>>>,
83
84 routing_strategy: RoutingStrategy,
86
87 enable_fallback: bool,
89
90 stats: Arc<RwLock<ManagerStats>>,
92}
93
94impl StorageManager {
95 pub fn new(routing_strategy: RoutingStrategy) -> Self {
97 Self {
98 state: Arc::new(RwLock::new(ManagerState::Uninitialized)),
99 primary: None,
100 cache: None,
101 secondary: None,
102 backends: Arc::new(RwLock::new(HashMap::new())),
103 routing_strategy,
104 enable_fallback: true,
105 stats: Arc::new(RwLock::new(ManagerStats::default())),
106 }
107 }
108
109 pub fn with_primary(mut self, backend: Arc<AnyStorage>) -> Self {
111 let backend_type = backend.backend();
112 self.primary = Some(backend.clone());
113
114 self.backends = Arc::new(RwLock::new({
116 let mut map = HashMap::new();
117 map.insert(backend_type, backend);
118 map
119 }));
120
121 self
122 }
123
124 pub fn with_cache(mut self, backend: Arc<AnyStorage>) -> Self {
126 self.cache = Some(backend.clone());
127 self
128 }
129
130 pub fn with_secondary(mut self, backend: Arc<AnyStorage>) -> Self {
132 self.secondary = Some(backend);
133 self
134 }
135
136 pub fn with_fallback(mut self, enable: bool) -> Self {
138 self.enable_fallback = enable;
139 self
140 }
141
142 pub async fn state(&self) -> ManagerState {
144 *self.state.read().await
145 }
146
147 pub async fn manager_stats(&self) -> ManagerStats {
149 self.stats.read().await.clone()
150 }
151
152 #[instrument(skip(self, backend))]
154 pub async fn add_backend(&self, backend: Arc<AnyStorage>) -> StorageResult<()> {
155 let backend_type = backend.backend();
156 info!("Adding backend: {:?}", backend_type);
157
158 let mut backends = self.backends.write().await;
159 backends.insert(backend_type, backend);
160
161 Ok(())
162 }
163
164 #[instrument(skip(self))]
166 pub async fn remove_backend(&self, backend_type: StorageBackend) -> StorageResult<()> {
167 info!("Removing backend: {:?}", backend_type);
168
169 let mut backends = self.backends.write().await;
170 backends.remove(&backend_type);
171
172 Ok(())
173 }
174
175 pub async fn get_backend(
177 &self,
178 backend_type: StorageBackend,
179 ) -> Option<Arc<AnyStorage>> {
180 let backends = self.backends.read().await;
181 backends.get(&backend_type).cloned()
182 }
183
184 pub async fn list_backends(&self) -> Vec<StorageBackend> {
186 let backends = self.backends.read().await;
187 backends.keys().copied().collect()
188 }
189
190 #[instrument(skip(self))]
192 pub async fn initialize(&mut self) -> StorageResult<()> {
193 info!("Initializing storage manager");
194 *self.state.write().await = ManagerState::Initializing;
195
196 if let Some(ref mut primary) = self.primary {
198 if let Some(storage) = Arc::get_mut(primary) {
199 storage.initialize().await?;
200 }
201 }
202
203 if let Some(ref mut cache) = self.cache {
205 if let Some(storage) = Arc::get_mut(cache) {
206 storage.initialize().await?;
207 }
208 }
209
210 if let Some(ref mut secondary) = self.secondary {
212 if let Some(storage) = Arc::get_mut(secondary) {
213 storage.initialize().await?;
214 }
215 }
216
217 *self.state.write().await = ManagerState::Running;
218 info!("Storage manager initialized successfully");
219
220 Ok(())
221 }
222
223 #[instrument(skip(self))]
225 pub async fn shutdown(&mut self) -> StorageResult<()> {
226 info!("Shutting down storage manager");
227 *self.state.write().await = ManagerState::Stopping;
228
229 if let Some(ref mut primary) = self.primary {
231 if let Some(storage) = Arc::get_mut(primary) {
232 storage.shutdown().await?;
233 }
234 }
235
236 if let Some(ref mut cache) = self.cache {
237 if let Some(storage) = Arc::get_mut(cache) {
238 storage.shutdown().await?;
239 }
240 }
241
242 if let Some(ref mut secondary) = self.secondary {
243 if let Some(storage) = Arc::get_mut(secondary) {
244 storage.shutdown().await?;
245 }
246 }
247
248 *self.state.write().await = ManagerState::Stopped;
249 info!("Storage manager shut down successfully");
250
251 Ok(())
252 }
253
254 async fn execute_with_fallback<F, T>(&self, operation: F) -> StorageResult<T>
256 where
257 F: Fn(Arc<AnyStorage>) -> futures::future::BoxFuture<'static, StorageResult<T>> + Send,
258 T: Send,
259 {
260 if let Some(ref primary) = self.primary {
262 match operation(primary.clone()).await {
263 Ok(result) => {
264 self.record_success(primary.backend()).await;
265 return Ok(result);
266 }
267 Err(e) if !self.enable_fallback => {
268 self.record_failure(primary.backend()).await;
269 return Err(e);
270 }
271 Err(e) => {
272 warn!("Primary backend failed: {}, trying fallback", e);
273 self.record_failure(primary.backend()).await;
274 }
275 }
276 }
277
278 if let Some(ref secondary) = self.secondary {
280 match operation(secondary.clone()).await {
281 Ok(result) => {
282 self.record_success(secondary.backend()).await;
283 self.record_fallback().await;
284 return Ok(result);
285 }
286 Err(e) => {
287 error!("Secondary backend also failed: {}", e);
288 self.record_failure(secondary.backend()).await;
289 return Err(e);
290 }
291 }
292 }
293
294 Err(StorageError::BackendNotAvailable {
295 backend: "all".to_string(),
296 })
297 }
298
299 async fn record_success(&self, backend: StorageBackend) {
301 let mut stats = self.stats.write().await;
302 stats.total_operations += 1;
303 stats.successful_operations += 1;
304 *stats
305 .operations_by_backend
306 .entry(backend.name().to_string())
307 .or_insert(0) += 1;
308 stats.last_updated = Utc::now();
309 }
310
311 async fn record_failure(&self, backend: StorageBackend) {
313 let mut stats = self.stats.write().await;
314 stats.total_operations += 1;
315 stats.failed_operations += 1;
316 stats.last_updated = Utc::now();
317 }
318
319 async fn record_fallback(&self) {
321 let mut stats = self.stats.write().await;
322 stats.fallback_count += 1;
323 }
324
325 #[instrument(skip(self))]
327 pub async fn health_check_all(&self) -> HashMap<StorageBackend, StorageHealth> {
328 let mut results = HashMap::new();
329
330 let backends = self.backends.read().await;
331 for (backend_type, storage) in backends.iter() {
332 match storage.health_check().await {
333 Ok(health) => {
334 results.insert(*backend_type, health);
335 }
336 Err(e) => {
337 error!("Health check failed for {:?}: {}", backend_type, e);
338 results.insert(*backend_type, StorageHealth::Unhealthy);
339 }
340 }
341 }
342
343 results
344 }
345
346 #[instrument(skip(self))]
348 pub async fn stats_all(&self) -> HashMap<StorageBackend, StorageStats> {
349 let mut results = HashMap::new();
350
351 let backends = self.backends.read().await;
352 for (backend_type, storage) in backends.iter() {
353 match storage.stats().await {
354 Ok(stats) => {
355 results.insert(*backend_type, stats);
356 }
357 Err(e) => {
358 error!("Failed to get stats for {:?}: {}", backend_type, e);
359 }
360 }
361 }
362
363 results
364 }
365}
366
367impl std::fmt::Debug for StorageManager {
369 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
370 f.debug_struct("StorageManager")
371 .field("routing_strategy", &self.routing_strategy)
372 .field("has_primary", &self.primary.is_some())
373 .field("has_cache", &self.cache.is_some())
374 .field("has_secondary", &self.secondary.is_some())
375 .finish()
376 }
377}
378
379#[async_trait]
381impl Storage for StorageManager {
382 fn backend(&self) -> StorageBackend {
383 if let Some(ref primary) = self.primary {
384 primary.backend()
385 } else {
386 StorageBackend::Sled }
388 }
389
390 async fn metadata(&self) -> StorageResult<StorageMetadata> {
391 if let Some(ref primary) = self.primary {
392 primary.metadata().await
393 } else {
394 Err(StorageError::BackendNotAvailable {
395 backend: "primary".to_string(),
396 })
397 }
398 }
399
400 async fn health_check(&self) -> StorageResult<StorageHealth> {
401 let health_results = self.health_check_all().await;
403
404 if health_results.values().any(|h| h == &StorageHealth::Healthy) {
405 Ok(StorageHealth::Healthy)
406 } else if health_results
407 .values()
408 .any(|h| h == &StorageHealth::Degraded)
409 {
410 Ok(StorageHealth::Degraded)
411 } else {
412 Ok(StorageHealth::Unhealthy)
413 }
414 }
415
416 async fn stats(&self) -> StorageResult<StorageStats> {
417 if let Some(ref primary) = self.primary {
418 primary.stats().await
419 } else {
420 Err(StorageError::BackendNotAvailable {
421 backend: "primary".to_string(),
422 })
423 }
424 }
425
426 #[instrument(skip(self, value))]
427 async fn insert<T: Serialize + DeserializeOwned + Send + Sync>(
428 &self,
429 table: &str,
430 key: &str,
431 value: &T,
432 ) -> StorageResult<()> {
433 match self.routing_strategy {
434 RoutingStrategy::CacheAside | RoutingStrategy::PrimaryOnly => {
435 let table = table.to_string();
437 let key = key.to_string();
438 let value_clone = serde_json::to_value(value).map_err(|e| {
439 StorageError::SerializationError {
440 source: Box::new(e),
441 }
442 })?;
443
444 self.execute_with_fallback(|storage| {
445 let table = table.clone();
446 let key = key.clone();
447 let value = value_clone.clone();
448 Box::pin(async move {
449 storage
450 .insert(
451 &table,
452 &key,
453 &serde_json::from_value::<T>(value).unwrap(),
454 )
455 .await
456 })
457 })
458 .await
459 }
460 RoutingStrategy::MultiWrite => {
461 if let Some(ref primary) = self.primary {
463 primary.insert(table, key, value).await?;
464 }
465 if let Some(ref secondary) = self.secondary {
466 let _ = secondary.insert(table, key, value).await; }
468 Ok(())
469 }
470 RoutingStrategy::FastestRead => {
471 if let Some(ref primary) = self.primary {
473 primary.insert(table, key, value).await
474 } else {
475 Err(StorageError::BackendNotAvailable {
476 backend: "primary".to_string(),
477 })
478 }
479 }
480 }
481 }
482
483 #[instrument(skip(self, value))]
484 async fn insert_with_ttl<T: Serialize + Send + Sync>(
485 &self,
486 table: &str,
487 key: &str,
488 value: &T,
489 ttl_seconds: i64,
490 ) -> StorageResult<()> {
491 if let Some(ref cache) = self.cache {
493 cache.insert_with_ttl(table, key, value, ttl_seconds).await
494 } else if let Some(ref primary) = self.primary {
495 primary
496 .insert_with_ttl(table, key, value, ttl_seconds)
497 .await
498 } else {
499 Err(StorageError::BackendNotAvailable {
500 backend: "any".to_string(),
501 })
502 }
503 }
504
505 #[instrument(skip(self))]
506 async fn get<T: DeserializeOwned + Serialize + Send + Sync>(
507 &self,
508 table: &str,
509 key: &str,
510 ) -> StorageResult<Option<StorageEntry<T>>> {
511 match self.routing_strategy {
512 RoutingStrategy::CacheAside => {
513 if let Some(ref cache) = self.cache {
515 if let Ok(Some(entry)) = cache.get(table, key).await {
516 debug!("Cache hit for key: {}", key);
517 return Ok(Some(entry));
518 }
519 }
520
521 if let Some(ref primary) = self.primary {
523 let entry = primary.get(table, key).await?;
524
525 if let Some(ref cache) = self.cache {
527 if let Some(ref e) = entry {
528 let _ = cache.insert(table, key, &e.value).await;
529 }
530 }
531
532 Ok(entry)
533 } else {
534 Err(StorageError::BackendNotAvailable {
535 backend: "primary".to_string(),
536 })
537 }
538 }
539 _ => {
540 if let Some(ref primary) = self.primary {
542 primary.get(table, key).await
543 } else {
544 Err(StorageError::BackendNotAvailable {
545 backend: "primary".to_string(),
546 })
547 }
548 }
549 }
550 }
551
552 #[instrument(skip(self, value))]
553 async fn update<T: Serialize + Send + Sync>(
554 &self,
555 table: &str,
556 key: &str,
557 value: &T,
558 ) -> StorageResult<()> {
559 if let Some(ref primary) = self.primary {
560 primary.update(table, key, value).await?;
561
562 if let Some(ref cache) = self.cache {
564 let _ = cache.delete(table, key).await;
565 }
566
567 Ok(())
568 } else {
569 Err(StorageError::BackendNotAvailable {
570 backend: "primary".to_string(),
571 })
572 }
573 }
574
575 #[instrument(skip(self, value))]
576 async fn update_versioned<T: Serialize + Send + Sync>(
577 &self,
578 table: &str,
579 key: &str,
580 value: &T,
581 expected_version: u64,
582 ) -> StorageResult<()> {
583 if let Some(ref primary) = self.primary {
584 primary
585 .update_versioned(table, key, value, expected_version)
586 .await
587 } else {
588 Err(StorageError::BackendNotAvailable {
589 backend: "primary".to_string(),
590 })
591 }
592 }
593
594 #[instrument(skip(self))]
595 async fn delete(&self, table: &str, key: &str) -> StorageResult<()> {
596 if let Some(ref primary) = self.primary {
597 primary.delete(table, key).await?;
598
599 if let Some(ref cache) = self.cache {
601 let _ = cache.delete(table, key).await;
602 }
603
604 Ok(())
605 } else {
606 Err(StorageError::BackendNotAvailable {
607 backend: "primary".to_string(),
608 })
609 }
610 }
611
612 #[instrument(skip(self))]
613 async fn exists(&self, table: &str, key: &str) -> StorageResult<bool> {
614 if let Some(ref primary) = self.primary {
615 primary.exists(table, key).await
616 } else {
617 Err(StorageError::BackendNotAvailable {
618 backend: "primary".to_string(),
619 })
620 }
621 }
622
623 #[instrument(skip(self, batch))]
624 async fn execute_batch(&self, batch: Batch) -> StorageResult<()> {
625 if let Some(ref primary) = self.primary {
626 primary.execute_batch(batch).await
627 } else {
628 Err(StorageError::BackendNotAvailable {
629 backend: "primary".to_string(),
630 })
631 }
632 }
633
634 #[instrument(skip(self))]
635 async fn query<T: DeserializeOwned + Serialize + Send + Sync + 'static>(
636 &self,
637 query: Query,
638 ) -> StorageResult<Vec<StorageEntry<T>>> {
639 if let Some(ref primary) = self.primary {
640 primary.query(query).await
641 } else {
642 Err(StorageError::BackendNotAvailable {
643 backend: "primary".to_string(),
644 })
645 }
646 }
647
648 #[instrument(skip(self))]
649 async fn count(&self, query: Query) -> StorageResult<usize> {
650 if let Some(ref primary) = self.primary {
651 primary.count(query).await
652 } else {
653 Err(StorageError::BackendNotAvailable {
654 backend: "primary".to_string(),
655 })
656 }
657 }
658
659 #[instrument(skip(self))]
660 async fn begin_transaction(&self) -> StorageResult<Transaction> {
661 if let Some(ref primary) = self.primary {
662 primary.begin_transaction().await
663 } else {
664 Err(StorageError::BackendNotAvailable {
665 backend: "primary".to_string(),
666 })
667 }
668 }
669
670 #[instrument(skip(self, transaction))]
671 async fn commit_transaction(&self, transaction: Transaction) -> StorageResult<()> {
672 if let Some(ref primary) = self.primary {
673 primary.commit_transaction(transaction).await
674 } else {
675 Err(StorageError::BackendNotAvailable {
676 backend: "primary".to_string(),
677 })
678 }
679 }
680
681 #[instrument(skip(self, transaction))]
682 async fn rollback_transaction(&self, transaction: Transaction) -> StorageResult<()> {
683 if let Some(ref primary) = self.primary {
684 primary.rollback_transaction(transaction).await
685 } else {
686 Err(StorageError::BackendNotAvailable {
687 backend: "primary".to_string(),
688 })
689 }
690 }
691
692 #[instrument(skip(self))]
693 async fn scan_prefix(&self, table: &str, prefix: &str) -> StorageResult<Vec<String>> {
694 if let Some(ref primary) = self.primary {
695 primary.scan_prefix(table, prefix).await
696 } else {
697 Err(StorageError::BackendNotAvailable {
698 backend: "primary".to_string(),
699 })
700 }
701 }
702
703 #[instrument(skip(self))]
704 async fn get_multi<T: DeserializeOwned + Serialize + Send + Sync>(
705 &self,
706 table: &str,
707 keys: Vec<String>,
708 ) -> StorageResult<Vec<Option<StorageEntry<T>>>> {
709 if let Some(ref primary) = self.primary {
710 primary.get_multi(table, keys).await
711 } else {
712 Err(StorageError::BackendNotAvailable {
713 backend: "primary".to_string(),
714 })
715 }
716 }
717
718 #[instrument(skip(self))]
719 async fn delete_multi(&self, table: &str, keys: Vec<String>) -> StorageResult<()> {
720 if let Some(ref primary) = self.primary {
721 primary.delete_multi(table, keys).await
722 } else {
723 Err(StorageError::BackendNotAvailable {
724 backend: "primary".to_string(),
725 })
726 }
727 }
728
729 #[instrument(skip(self, new_value))]
730 async fn compare_and_swap<T: Serialize + Send + Sync>(
731 &self,
732 table: &str,
733 key: &str,
734 expected_version: u64,
735 new_value: &T,
736 ) -> StorageResult<bool> {
737 if let Some(ref primary) = self.primary {
738 primary
739 .compare_and_swap(table, key, expected_version, new_value)
740 .await
741 } else {
742 Err(StorageError::BackendNotAvailable {
743 backend: "primary".to_string(),
744 })
745 }
746 }
747
748 #[instrument(skip(self))]
749 async fn get_modified_since<T: DeserializeOwned + Serialize + Send + Sync + 'static>(
750 &self,
751 table: &str,
752 since: DateTime<Utc>,
753 ) -> StorageResult<Vec<StorageEntry<T>>> {
754 if let Some(ref primary) = self.primary {
755 primary.get_modified_since(table, since).await
756 } else {
757 Err(StorageError::BackendNotAvailable {
758 backend: "primary".to_string(),
759 })
760 }
761 }
762
763 #[instrument(skip(self))]
764 async fn get_expiring_before<T: DeserializeOwned + Serialize + Send + Sync + 'static>(
765 &self,
766 table: &str,
767 before: DateTime<Utc>,
768 ) -> StorageResult<Vec<StorageEntry<T>>> {
769 if let Some(ref primary) = self.primary {
770 primary.get_expiring_before(table, before).await
771 } else {
772 Err(StorageError::BackendNotAvailable {
773 backend: "primary".to_string(),
774 })
775 }
776 }
777
778 #[instrument(skip(self))]
779 async fn cleanup_expired(&self, table: &str) -> StorageResult<usize> {
780 if let Some(ref primary) = self.primary {
781 primary.cleanup_expired(table).await
782 } else {
783 Err(StorageError::BackendNotAvailable {
784 backend: "primary".to_string(),
785 })
786 }
787 }
788
789 #[instrument(skip(self))]
790 async fn compact(&self) -> StorageResult<()> {
791 if let Some(ref primary) = self.primary {
792 primary.compact().await
793 } else {
794 Ok(())
795 }
796 }
797
798 #[instrument(skip(self))]
799 async fn flush(&self) -> StorageResult<()> {
800 if let Some(ref primary) = self.primary {
801 primary.flush().await
802 } else {
803 Ok(())
804 }
805 }
806
807 async fn initialize(&mut self) -> StorageResult<()> {
808 self.initialize().await
809 }
810
811 async fn shutdown(&mut self) -> StorageResult<()> {
812 self.shutdown().await
813 }
814}
815
816#[cfg(test)]
817mod tests {
818 use super::*;
819
820 #[tokio::test]
821 async fn test_manager_state() {
822 let manager = StorageManager::new(RoutingStrategy::PrimaryOnly);
823 assert_eq!(manager.state().await, ManagerState::Uninitialized);
824 }
825
826 #[tokio::test]
827 async fn test_routing_strategies() {
828 let strategies = vec![
829 RoutingStrategy::PrimaryOnly,
830 RoutingStrategy::CacheAside,
831 RoutingStrategy::MultiWrite,
832 RoutingStrategy::FastestRead,
833 ];
834
835 for strategy in strategies {
836 let manager = StorageManager::new(strategy);
837 assert_eq!(manager.routing_strategy, strategy);
838 }
839 }
840}