Skip to main content

agentic_evolve_core/optimization/
cache.rs

1//! CacheManager — manages pattern match cache for fast lookups.
2
3use std::collections::HashMap;
4
5/// Cached match result.
6#[derive(Debug, Clone)]
7pub struct CachedMatch {
8    pub pattern_id: String,
9    pub score: f64,
10    pub timestamp: i64,
11    pub hit_count: u64,
12}
13
14/// Manages a cache of recent pattern matches.
15#[derive(Debug)]
16pub struct CacheManager {
17    cache: HashMap<String, Vec<CachedMatch>>,
18    max_entries: usize,
19    ttl_seconds: i64,
20}
21
22impl CacheManager {
23    pub fn new(max_entries: usize, ttl_seconds: i64) -> Self {
24        Self {
25            cache: HashMap::new(),
26            max_entries,
27            ttl_seconds,
28        }
29    }
30
31    pub fn get(&mut self, key: &str) -> Option<&Vec<CachedMatch>> {
32        let now = chrono::Utc::now().timestamp();
33        // Check if expired
34        if let Some(entries) = self.cache.get(key) {
35            if let Some(first) = entries.first() {
36                if now - first.timestamp > self.ttl_seconds {
37                    self.cache.remove(key);
38                    return None;
39                }
40            }
41        }
42        self.cache.get(key)
43    }
44
45    pub fn put(&mut self, key: &str, matches: Vec<CachedMatch>) {
46        if self.cache.len() >= self.max_entries {
47            self.evict_oldest();
48        }
49        self.cache.insert(key.to_string(), matches);
50    }
51
52    pub fn invalidate(&mut self, key: &str) {
53        self.cache.remove(key);
54    }
55
56    pub fn invalidate_pattern(&mut self, pattern_id: &str) {
57        self.cache
58            .retain(|_, entries| !entries.iter().any(|e| e.pattern_id == pattern_id));
59    }
60
61    pub fn clear(&mut self) {
62        self.cache.clear();
63    }
64
65    pub fn size(&self) -> usize {
66        self.cache.len()
67    }
68
69    pub fn hit_rate(&self) -> f64 {
70        let total_hits: u64 = self
71            .cache
72            .values()
73            .flat_map(|entries| entries.iter())
74            .map(|e| e.hit_count)
75            .sum();
76        let total_entries: u64 = self
77            .cache
78            .values()
79            .map(|entries| entries.len() as u64)
80            .sum();
81        if total_entries == 0 {
82            0.0
83        } else {
84            total_hits as f64 / total_entries as f64
85        }
86    }
87
88    fn evict_oldest(&mut self) {
89        if let Some(oldest_key) = self
90            .cache
91            .iter()
92            .min_by_key(|(_, entries)| entries.first().map(|e| e.timestamp).unwrap_or(i64::MAX))
93            .map(|(k, _)| k.clone())
94        {
95            self.cache.remove(&oldest_key);
96        }
97    }
98}
99
100impl Default for CacheManager {
101    fn default() -> Self {
102        Self::new(1000, 3600) // 1000 entries, 1 hour TTL
103    }
104}