1use serde::{Deserialize, Serialize};
8use std::cmp::Reverse;
9use std::collections::{HashMap, HashSet};
10use std::sync::Arc;
11use std::time::{Duration, Instant, SystemTime};
12use tokio::sync::{Mutex as AsyncMutex, RwLock as AsyncRwLock};
13use tokio::time::interval;
14
15#[derive(Debug, Clone)]
17pub struct AdvancedCacheConfig {
18 pub l1_max_size: usize, pub l2_max_size: usize, pub default_ttl: Duration, pub adaptive_ttl: bool, pub max_ttl: Duration, pub min_ttl: Duration, pub cache_warming: bool, pub intelligent_invalidation: bool, pub compression: bool, pub persistence: bool, pub metrics_collection: bool, }
30
31impl Default for AdvancedCacheConfig {
32 fn default() -> Self {
33 Self {
34 l1_max_size: 1000,
35 l2_max_size: 10000,
36 default_ttl: Duration::from_secs(300),
37 adaptive_ttl: true,
38 max_ttl: Duration::from_secs(3600),
39 min_ttl: Duration::from_secs(30),
40 cache_warming: true,
41 intelligent_invalidation: true,
42 compression: true,
43 persistence: false,
44 metrics_collection: true,
45 }
46 }
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct CacheEntry {
52 pub data: serde_json::Value,
53 pub created_at: SystemTime,
54 pub ttl: Duration,
55 pub access_count: u32,
56 pub last_accessed: SystemTime,
57 pub size_bytes: usize,
58 pub query_complexity: usize,
59 pub dependencies: HashSet<String>,
60 pub tags: HashSet<String>,
61}
62
63impl CacheEntry {
64 pub fn new(data: serde_json::Value, ttl: Duration) -> Self {
65 let size_bytes = data.to_string().len();
66 Self {
67 data,
68 created_at: SystemTime::now(),
69 ttl,
70 access_count: 0,
71 last_accessed: SystemTime::now(),
72 size_bytes,
73 query_complexity: 0,
74 dependencies: HashSet::new(),
75 tags: HashSet::new(),
76 }
77 }
78
79 pub fn is_expired(&self) -> bool {
80 self.created_at.elapsed().unwrap_or(Duration::from_secs(0)) > self.ttl
81 }
82
83 pub fn access(&mut self) {
84 self.access_count += 1;
85 self.last_accessed = SystemTime::now();
86 }
87
88 pub fn with_complexity(mut self, complexity: usize) -> Self {
89 self.query_complexity = complexity;
90 self
91 }
92
93 pub fn with_dependencies(mut self, deps: HashSet<String>) -> Self {
94 self.dependencies = deps;
95 self
96 }
97
98 pub fn with_tags(mut self, tags: HashSet<String>) -> Self {
99 self.tags = tags;
100 self
101 }
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct CacheMetrics {
107 pub l1_hits: u64,
108 pub l1_misses: u64,
109 pub l2_hits: u64,
110 pub l2_misses: u64,
111 pub evictions: u64,
112 pub invalidations: u64,
113 pub warming_operations: u64,
114 pub total_size_bytes: usize,
115 pub average_ttl: Duration,
116 pub hit_ratio: f64,
117 pub popular_queries: Vec<PopularQuery>,
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct PopularQuery {
122 pub cache_key: String,
123 pub access_count: u32,
124 pub avg_execution_time: Duration,
125 pub last_accessed: SystemTime,
126}
127
128#[derive(Debug, Clone)]
130pub enum WarmingStrategy {
131 Popular, Predictive, Schedule, Dependency, }
136
137#[derive(Debug, Clone)]
139pub enum InvalidationStrategy {
140 TTL, Manual, Dependency, Smart, }
145
146pub struct AdvancedCache {
148 config: AdvancedCacheConfig,
149 l1_cache: Arc<AsyncRwLock<HashMap<String, CacheEntry>>>,
150 l2_cache: Arc<AsyncRwLock<HashMap<String, CacheEntry>>>,
151 metrics: Arc<AsyncRwLock<CacheMetrics>>,
152 access_patterns: Arc<AsyncRwLock<HashMap<String, AccessPattern>>>,
153 dependency_graph: Arc<AsyncRwLock<DependencyGraph>>,
154 warming_queue: Arc<AsyncMutex<Vec<WarmingTask>>>,
155}
156
157#[derive(Debug, Clone)]
159struct AccessPattern {
160 access_times: VecDeque<Instant>,
161 frequency: f64,
162 #[allow(dead_code)]
163 last_prediction: Option<Instant>,
164}
165
166use std::collections::VecDeque;
167
168impl AccessPattern {
169 fn new() -> Self {
170 Self {
171 access_times: VecDeque::new(),
172 frequency: 0.0,
173 last_prediction: None,
174 }
175 }
176
177 fn record_access(&mut self, now: Instant) {
178 self.access_times.push_back(now);
179
180 let cutoff = now - Duration::from_secs(3600);
182 while let Some(&front) = self.access_times.front() {
183 if front < cutoff {
184 self.access_times.pop_front();
185 } else {
186 break;
187 }
188 }
189
190 self.frequency = self.access_times.len() as f64;
192 }
193
194 #[allow(dead_code)]
195 fn predict_next_access(&self) -> Option<Instant> {
196 if self.access_times.len() < 2 {
197 return None;
198 }
199
200 let intervals: Vec<Duration> = self
202 .access_times
203 .iter()
204 .zip(self.access_times.iter().skip(1))
205 .map(|(first, second)| *second - *first)
206 .collect();
207
208 if intervals.is_empty() {
209 return None;
210 }
211
212 let total_nanos =
213 intervals.iter().map(|d| d.as_nanos()).sum::<u128>() / intervals.len() as u128;
214 let avg_interval = Duration::from_nanos(total_nanos.min(u64::MAX as u128) as u64);
215
216 self.access_times.back().map(|&last| last + avg_interval)
217 }
218}
219
220#[derive(Debug, Default)]
222struct DependencyGraph {
223 dependencies: HashMap<String, HashSet<String>>,
224 dependents: HashMap<String, HashSet<String>>,
225}
226
227impl DependencyGraph {
228 fn add_dependency(&mut self, cache_key: &str, dependency: &str) {
229 self.dependencies
230 .entry(cache_key.to_string())
231 .or_default()
232 .insert(dependency.to_string());
233
234 self.dependents
235 .entry(dependency.to_string())
236 .or_default()
237 .insert(cache_key.to_string());
238 }
239
240 fn get_affected_keys(&self, changed_key: &str) -> HashSet<String> {
241 let mut affected = HashSet::new();
242 let mut to_check = vec![changed_key.to_string()];
243
244 while let Some(key) = to_check.pop() {
245 if let Some(dependents) = self.dependents.get(&key) {
246 for dependent in dependents {
247 if affected.insert(dependent.clone()) {
248 to_check.push(dependent.clone());
249 }
250 }
251 }
252 }
253
254 affected
255 }
256}
257
258#[derive(Debug, Clone)]
260struct WarmingTask {
261 #[allow(dead_code)]
262 cache_key: String,
263 #[allow(dead_code)]
264 query: String,
265 #[allow(dead_code)]
266 variables: HashMap<String, serde_json::Value>,
267 #[allow(dead_code)]
268 priority: u8,
269 scheduled_time: Instant,
270}
271
272impl AdvancedCache {
273 pub fn new(config: AdvancedCacheConfig) -> Self {
275 let cache = Self {
276 config: config.clone(),
277 l1_cache: Arc::new(AsyncRwLock::new(HashMap::new())),
278 l2_cache: Arc::new(AsyncRwLock::new(HashMap::new())),
279 metrics: Arc::new(AsyncRwLock::new(CacheMetrics {
280 l1_hits: 0,
281 l1_misses: 0,
282 l2_hits: 0,
283 l2_misses: 0,
284 evictions: 0,
285 invalidations: 0,
286 warming_operations: 0,
287 total_size_bytes: 0,
288 average_ttl: config.default_ttl,
289 hit_ratio: 0.0,
290 popular_queries: Vec::new(),
291 })),
292 access_patterns: Arc::new(AsyncRwLock::new(HashMap::new())),
293 dependency_graph: Arc::new(AsyncRwLock::new(DependencyGraph::default())),
294 warming_queue: Arc::new(AsyncMutex::new(Vec::new())),
295 };
296
297 cache.start_cleanup_task();
299 cache.start_warming_task();
300 cache.start_metrics_task();
301
302 cache
303 }
304
305 pub async fn get(&self, key: &str) -> Option<serde_json::Value> {
307 {
309 let mut l1 = self.l1_cache.write().await;
310 if let Some(entry) = l1.get_mut(key) {
311 if !entry.is_expired() {
312 entry.access();
313 self.update_access_pattern(key).await;
314 self.record_l1_hit().await;
315 return Some(entry.data.clone());
316 } else {
317 l1.remove(key);
318 }
319 }
320 }
321
322 self.record_l1_miss().await;
323
324 {
326 let mut l2 = self.l2_cache.write().await;
327 if let Some(entry) = l2.get_mut(key) {
328 if !entry.is_expired() {
329 entry.access();
330
331 if entry.access_count > 5 {
333 self.promote_to_l1(key.to_string(), entry.clone()).await;
334 }
335
336 self.update_access_pattern(key).await;
337 self.record_l2_hit().await;
338 return Some(entry.data.clone());
339 } else {
340 l2.remove(key);
341 }
342 }
343 }
344
345 self.record_l2_miss().await;
346 None
347 }
348
349 pub async fn set(
351 &self,
352 key: String,
353 value: serde_json::Value,
354 ttl: Option<Duration>,
355 complexity: Option<usize>,
356 dependencies: Option<HashSet<String>>,
357 tags: Option<HashSet<String>>,
358 ) {
359 let effective_ttl = if self.config.adaptive_ttl {
360 self.calculate_adaptive_ttl(&key, complexity.unwrap_or(0))
361 .await
362 } else {
363 ttl.unwrap_or(self.config.default_ttl)
364 };
365
366 let mut entry = CacheEntry::new(value, effective_ttl);
367
368 if let Some(complexity) = complexity {
369 entry = entry.with_complexity(complexity);
370 }
371
372 if let Some(deps) = dependencies {
373 entry = entry.with_dependencies(deps.clone());
374 self.add_dependencies(&key, &deps).await;
375 }
376
377 if let Some(tags) = tags {
378 entry = entry.with_tags(tags);
379 }
380
381 let should_use_l1 = self.should_place_in_l1(&key, &entry).await;
383
384 if should_use_l1 {
385 self.set_l1(key, entry).await;
386 } else {
387 self.set_l2(key, entry).await;
388 }
389 }
390
391 pub async fn invalidate(&self, key: &str, strategy: InvalidationStrategy) {
393 match strategy {
394 InvalidationStrategy::TTL => {
395 }
397 InvalidationStrategy::Manual => {
398 self.remove_from_all_tiers(key).await;
399 }
400 InvalidationStrategy::Dependency => {
401 let affected_keys = self.get_affected_keys(key).await;
402 for affected_key in affected_keys {
403 self.remove_from_all_tiers(&affected_key).await;
404 }
405 }
406 InvalidationStrategy::Smart => {
407 self.smart_invalidation(key).await;
408 }
409 }
410
411 self.record_invalidation().await;
412 }
413
414 pub async fn warm_cache(&self, strategy: WarmingStrategy) {
416 match strategy {
417 WarmingStrategy::Popular => {
418 self.warm_popular_queries().await;
419 }
420 WarmingStrategy::Predictive => {
421 self.warm_predicted_queries().await;
422 }
423 WarmingStrategy::Schedule => {
424 self.warm_scheduled_queries().await;
425 }
426 WarmingStrategy::Dependency => {
427 self.warm_dependency_queries().await;
428 }
429 }
430
431 self.record_warming_operation().await;
432 }
433
434 pub async fn get_metrics(&self) -> CacheMetrics {
436 let mut metrics = self.metrics.read().await.clone();
437
438 let total_requests =
440 metrics.l1_hits + metrics.l1_misses + metrics.l2_hits + metrics.l2_misses;
441 if total_requests > 0 {
442 metrics.hit_ratio = (metrics.l1_hits + metrics.l2_hits) as f64 / total_requests as f64;
443 }
444
445 metrics.popular_queries = self.get_popular_queries().await;
447
448 metrics
449 }
450
451 pub async fn clear_all(&self) {
453 self.l1_cache.write().await.clear();
454 self.l2_cache.write().await.clear();
455 self.access_patterns.write().await.clear();
456 self.dependency_graph.write().await.dependencies.clear();
457 self.dependency_graph.write().await.dependents.clear();
458 }
459
460 async fn promote_to_l1(&self, key: String, entry: CacheEntry) {
463 self.set_l1(key, entry).await;
464 }
465
466 async fn set_l1(&self, key: String, entry: CacheEntry) {
467 let mut l1 = self.l1_cache.write().await;
468
469 while l1.len() >= self.config.l1_max_size {
471 self.evict_l1_entry(&mut l1).await;
472 }
473
474 l1.insert(key, entry);
475 }
476
477 async fn set_l2(&self, key: String, entry: CacheEntry) {
478 let mut l2 = self.l2_cache.write().await;
479
480 while l2.len() >= self.config.l2_max_size {
482 self.evict_l2_entry(&mut l2).await;
483 }
484
485 l2.insert(key, entry);
486 }
487
488 async fn evict_l1_entry(&self, l1: &mut HashMap<String, CacheEntry>) {
489 let mut oldest_key: Option<String> = None;
491 let mut oldest_time = SystemTime::now();
492
493 for (key, entry) in l1.iter() {
494 if entry.last_accessed < oldest_time {
495 oldest_time = entry.last_accessed;
496 oldest_key = Some(key.clone());
497 }
498 }
499
500 if let Some(key) = oldest_key {
501 if let Some(entry) = l1.remove(&key) {
502 if entry.access_count > 1 && !entry.is_expired() {
504 self.set_l2(key, entry).await;
505 }
506 }
507 }
508
509 self.record_eviction().await;
510 }
511
512 async fn evict_l2_entry(&self, l2: &mut HashMap<String, CacheEntry>) {
513 let mut oldest_key: Option<String> = None;
515 let mut oldest_time = SystemTime::now();
516
517 for (key, entry) in l2.iter() {
518 if entry.last_accessed < oldest_time {
519 oldest_time = entry.last_accessed;
520 oldest_key = Some(key.clone());
521 }
522 }
523
524 if let Some(key) = oldest_key {
525 l2.remove(&key);
526 }
527
528 self.record_eviction().await;
529 }
530
531 async fn should_place_in_l1(&self, key: &str, _entry: &CacheEntry) -> bool {
532 let patterns = self.access_patterns.read().await;
534 if let Some(pattern) = patterns.get(key) {
535 pattern.frequency > 10.0 } else {
537 false }
539 }
540
541 async fn calculate_adaptive_ttl(&self, key: &str, complexity: usize) -> Duration {
542 let patterns = self.access_patterns.read().await;
543
544 let base_ttl = if let Some(pattern) = patterns.get(key) {
545 let frequency_factor = (pattern.frequency / 10.0).clamp(0.5, 3.0);
547 Duration::from_secs(
548 (self.config.default_ttl.as_secs() as f64 * frequency_factor) as u64,
549 )
550 } else {
551 self.config.default_ttl
552 };
553
554 let complexity_factor = 1.0 + (complexity as f64 / 100.0).min(2.0);
556 let adjusted_ttl =
557 Duration::from_secs((base_ttl.as_secs() as f64 * complexity_factor) as u64);
558
559 adjusted_ttl
561 .max(self.config.min_ttl)
562 .min(self.config.max_ttl)
563 }
564
565 async fn update_access_pattern(&self, key: &str) {
566 let mut patterns = self.access_patterns.write().await;
567 let pattern = patterns
568 .entry(key.to_string())
569 .or_insert_with(AccessPattern::new);
570 pattern.record_access(Instant::now());
571 }
572
573 async fn add_dependencies(&self, key: &str, dependencies: &HashSet<String>) {
574 let mut graph = self.dependency_graph.write().await;
575 for dep in dependencies {
576 graph.add_dependency(key, dep);
577 }
578 }
579
580 async fn get_affected_keys(&self, key: &str) -> HashSet<String> {
581 let graph = self.dependency_graph.read().await;
582 graph.get_affected_keys(key)
583 }
584
585 async fn remove_from_all_tiers(&self, key: &str) {
586 self.l1_cache.write().await.remove(key);
587 self.l2_cache.write().await.remove(key);
588 }
589
590 async fn smart_invalidation(&self, key: &str) {
591 self.remove_from_all_tiers(key).await;
594 }
595
596 async fn warm_popular_queries(&self) {
597 }
599
600 async fn warm_predicted_queries(&self) {
601 }
603
604 async fn warm_scheduled_queries(&self) {
605 }
607
608 async fn warm_dependency_queries(&self) {
609 }
611
612 async fn get_popular_queries(&self) -> Vec<PopularQuery> {
613 let mut popular = Vec::new();
614
615 let l1 = self.l1_cache.read().await;
617 let l2 = self.l2_cache.read().await;
618
619 for (key, entry) in l1.iter().chain(l2.iter()) {
620 if entry.access_count > 5 {
621 let estimated_exec_time = if entry.query_complexity > 0 {
623 Duration::from_millis((entry.query_complexity as u64 * 10).min(5000))
624 } else {
625 Duration::from_millis(50) };
627
628 popular.push(PopularQuery {
629 cache_key: key.clone(),
630 access_count: entry.access_count,
631 avg_execution_time: estimated_exec_time,
632 last_accessed: entry.last_accessed,
633 });
634 }
635 }
636
637 popular.sort_by_key(|p| Reverse(p.access_count));
638 popular.truncate(10);
639 popular
640 }
641
642 async fn record_l1_hit(&self) {
644 let mut metrics = self.metrics.write().await;
645 metrics.l1_hits += 1;
646 }
647
648 async fn record_l1_miss(&self) {
649 let mut metrics = self.metrics.write().await;
650 metrics.l1_misses += 1;
651 }
652
653 async fn record_l2_hit(&self) {
654 let mut metrics = self.metrics.write().await;
655 metrics.l2_hits += 1;
656 }
657
658 async fn record_l2_miss(&self) {
659 let mut metrics = self.metrics.write().await;
660 metrics.l2_misses += 1;
661 }
662
663 async fn record_eviction(&self) {
664 let mut metrics = self.metrics.write().await;
665 metrics.evictions += 1;
666 }
667
668 async fn record_invalidation(&self) {
669 let mut metrics = self.metrics.write().await;
670 metrics.invalidations += 1;
671 }
672
673 async fn record_warming_operation(&self) {
674 let mut metrics = self.metrics.write().await;
675 metrics.warming_operations += 1;
676 }
677
678 fn start_cleanup_task(&self) {
680 let l1_cache = Arc::clone(&self.l1_cache);
681 let l2_cache = Arc::clone(&self.l2_cache);
682
683 tokio::spawn(async move {
684 let mut interval = interval(Duration::from_secs(60));
685
686 loop {
687 interval.tick().await;
688
689 {
691 let mut l1 = l1_cache.write().await;
692 l1.retain(|_, entry| !entry.is_expired());
693 }
694
695 {
697 let mut l2 = l2_cache.write().await;
698 l2.retain(|_, entry| !entry.is_expired());
699 }
700 }
701 });
702 }
703
704 fn start_warming_task(&self) {
705 if !self.config.cache_warming {
706 return;
707 }
708
709 let warming_queue = Arc::clone(&self.warming_queue);
710
711 tokio::spawn(async move {
712 let mut interval = interval(Duration::from_secs(300)); loop {
715 interval.tick().await;
716
717 let mut queue = warming_queue.lock().await;
719 let now = Instant::now();
720
721 queue.retain(|task| {
722 if task.scheduled_time <= now {
723 false } else {
727 true }
729 });
730 }
731 });
732 }
733
734 fn start_metrics_task(&self) {
735 if !self.config.metrics_collection {
736 return;
737 }
738
739 let metrics = Arc::clone(&self.metrics);
740 let l1_cache = Arc::clone(&self.l1_cache);
741 let l2_cache = Arc::clone(&self.l2_cache);
742
743 tokio::spawn(async move {
744 let mut interval = interval(Duration::from_secs(60));
745
746 loop {
747 interval.tick().await;
748
749 let mut metrics = metrics.write().await;
751 let l1 = l1_cache.read().await;
752 let l2 = l2_cache.read().await;
753
754 metrics.total_size_bytes = l1
755 .values()
756 .chain(l2.values())
757 .map(|entry| entry.size_bytes)
758 .sum();
759 }
760 });
761 }
762}
763
764#[cfg(test)]
765mod tests {
766 use super::*;
767
768 #[tokio::test]
769 async fn test_advanced_cache_basic_operations() {
770 let config = AdvancedCacheConfig::default();
771 let cache = AdvancedCache::new(config);
772
773 let key = "test_key".to_string();
774 let value = serde_json::json!({"test": "value"});
775
776 cache
778 .set(key.clone(), value.clone(), None, None, None, None)
779 .await;
780 let result = cache.get(&key).await;
781
782 assert_eq!(result, Some(value));
783 }
784
785 #[tokio::test]
786 async fn test_cache_tiers() {
787 let config = AdvancedCacheConfig {
788 l1_max_size: 1, ..Default::default()
790 };
791
792 let cache = AdvancedCache::new(config);
793
794 cache
796 .set(
797 "key1".to_string(),
798 serde_json::json!(1),
799 None,
800 None,
801 None,
802 None,
803 )
804 .await;
805 cache
806 .set(
807 "key2".to_string(),
808 serde_json::json!(2),
809 None,
810 None,
811 None,
812 None,
813 )
814 .await;
815
816 let result1 = cache.get("key1").await;
818 let result2 = cache.get("key2").await;
819
820 assert_eq!(result1, Some(serde_json::json!(1)));
821 assert_eq!(result2, Some(serde_json::json!(2)));
822 }
823
824 #[tokio::test]
825 async fn test_dependency_invalidation() {
826 let cache = AdvancedCache::new(AdvancedCacheConfig::default());
827
828 let mut deps = HashSet::new();
829 deps.insert("dependency1".to_string());
830
831 cache
832 .set(
833 "main_key".to_string(),
834 serde_json::json!({"data": "test"}),
835 None,
836 None,
837 Some(deps),
838 None,
839 )
840 .await;
841
842 cache
844 .invalidate("dependency1", InvalidationStrategy::Dependency)
845 .await;
846
847 let result = cache.get("main_key").await;
849 assert_eq!(result, None);
850 }
851}