Skip to main content

linkrs_query/cache/
cte_cache.rs

1//! CTE Results Cache Manager Module
2//!
3//! CTE (Common Table Expression) query result caching function.
4//! Avoid repeated calculation of same CTE to improve query performance.
5//!
6//! ## Caching policy
7//!
8//! - LRU elimination policy: eliminate the longest unused entries when the cache is full
9//! - Memory budget management: tightly control the upper limit of memory used by the cache
10//! - Intelligent caching decision: decide whether to cache or not based on CTE characteristics
11//!
12//! ## Applicable scenarios
13//!
14//! 1. Recursive CTEs are referenced multiple times
15//! 2. Complex subqueries are used multiple times in a single query
16//! 3. Medium-sized result set (100-10,000 rows)
17//! 4. CTE is deterministic (no random functions, etc.)
18//!
19//! The module was split from the original single `cte_cache.rs` into focused
20//! submodules:
21//! - `entry`: the [`CteCacheEntry`] cache-row type
22//! - `manager`: the [`CteCacheManager`] store / eviction engine
23//! - `decision`: the [`CteCacheDecisionMaker`] cache-policy evaluator
24
25pub mod decision;
26pub mod entry;
27pub mod manager;
28
29pub use decision::{CteCacheDecision, CteCacheDecisionMaker};
30pub use entry::CteCacheEntry;
31pub use manager::CteCacheManager;
32
33#[cfg(test)]
34mod tests {
35    use std::sync::Arc;
36
37    use super::*;
38
39    #[test]
40    fn test_cte_cache_entry_creation() {
41        let entry = CteCacheEntry::new(
42            "hash123".to_string(),
43            "SELECT * FROM users".to_string(),
44            vec![1, 2, 3, 4],
45            100,
46            50,
47        );
48
49        assert_eq!(entry.row_count, 100);
50        assert_eq!(entry.data_size, 4);
51        assert_eq!(entry.compute_cost_ms, 50);
52    }
53
54    #[test]
55    fn test_cte_cache_entry_memory_estimation() {
56        let entry = CteCacheEntry::new(
57            "hash".to_string(),
58            "SELECT 1".to_string(),
59            vec![0u8; 1024],
60            10,
61            10,
62        );
63
64        let memory = entry.estimate_memory();
65        assert!(memory > 1024);
66    }
67
68    #[test]
69    fn test_cte_cache_entry_value_score() {
70        let mut entry = CteCacheEntry::new(
71            "hash".to_string(),
72            "SELECT 1".to_string(),
73            vec![0u8; 1024],
74            10,
75            100,
76        );
77
78        entry.access_count = 10;
79        entry.access_frequency = 5.0;
80
81        let score = entry.value_score();
82        assert!(score > 0.0);
83    }
84
85    #[test]
86    fn test_cte_cache_manager_creation() {
87        let manager = CteCacheManager::new();
88        assert!(manager.is_enabled());
89        assert_eq!(manager.entry_count(), 0);
90    }
91
92    #[test]
93    fn test_cte_cache_manager_put_get() {
94        let manager = CteCacheManager::new();
95
96        let hash = manager.put("SELECT 1", vec![1, 2, 3], 1);
97        assert!(hash.is_some());
98
99        let data = manager.get("SELECT 1");
100        assert!(data.is_some());
101        assert_eq!(data.unwrap().as_ref(), &[1, 2, 3]);
102    }
103
104    #[test]
105    fn test_cte_cache_manager_should_cache() {
106        let manager = CteCacheManager::new();
107
108        assert!(manager.should_cache("SELECT * FROM users", 500, true));
109        assert!(!manager.should_cache("SELECT * FROM users", 10, true));
110        assert!(!manager.should_cache("SELECT * FROM users", 500, false));
111    }
112
113    #[test]
114    fn test_cte_cache_manager_invalidate() {
115        let manager = CteCacheManager::new();
116
117        manager.put("SELECT 1", vec![1, 2, 3], 1);
118        assert!(manager.contains("SELECT 1"));
119
120        assert!(manager.invalidate("SELECT 1"));
121        assert!(!manager.contains("SELECT 1"));
122    }
123
124    #[test]
125    fn test_cte_cache_decision_maker() {
126        let manager = Arc::new(CteCacheManager::new());
127        let decision_maker = CteCacheDecisionMaker::new(manager);
128
129        let decision = decision_maker.decide("SELECT * FROM users", 500, 100.0);
130        assert!(decision.should_cache);
131    }
132
133    #[test]
134    fn test_compute_hash() {
135        let hash1 = CteCacheManager::compute_hash("SELECT 1");
136        let hash2 = CteCacheManager::compute_hash("SELECT 1");
137        let hash3 = CteCacheManager::compute_hash("SELECT 2");
138
139        assert_eq!(hash1, hash2);
140        assert_ne!(hash1, hash3);
141    }
142}