Skip to main content

linkrs_query/cache/cte_cache/
decision.rs

1use std::sync::Arc;
2
3use crate::cache::config::CachePriority;
4
5use super::manager::CteCacheManager;
6
7/// CTE Cache Decision
8///
9/// Decide whether to use caching based on query characteristics
10#[derive(Debug, Clone)]
11pub struct CteCacheDecision {
12    /// Should the cache be used?
13    pub should_cache: bool,
14    /// Reasons for decision-making
15    pub reason: String,
16    /// Estimated reuse probability
17    pub reuse_probability: f64,
18    /// Estimated caching gains
19    pub estimated_benefit: f64,
20    /// Suggested priority
21    pub suggested_priority: CachePriority,
22}
23
24/// CTE cache decision maker
25#[derive(Debug)]
26pub struct CteCacheDecisionMaker {
27    /// Cache Manager
28    cache_manager: Arc<CteCacheManager>,
29    /// Minimum Reuse Probability Threshold
30    min_reuse_probability: f64,
31    /// Minimum estimated gain
32    min_benefit: f64,
33}
34
35impl CteCacheDecisionMaker {
36    /// Create a new decision maker.
37    pub fn new(cache_manager: Arc<CteCacheManager>) -> Self {
38        Self {
39            cache_manager,
40            min_reuse_probability: 0.3,
41            min_benefit: 1.0,
42        }
43    }
44
45    /// Setting parameters
46    pub fn with_params(mut self, min_reuse_probability: f64, min_benefit: f64) -> Self {
47        self.min_reuse_probability = min_reuse_probability;
48        self.min_benefit = min_benefit;
49        self
50    }
51
52    /// Making a decision regarding caching
53    pub fn decide(
54        &self,
55        cte_definition: &str,
56        estimated_rows: u64,
57        compute_cost: f64,
58    ) -> CteCacheDecision {
59        if !self.cache_manager.is_enabled() {
60            return CteCacheDecision {
61                should_cache: false,
62                reason: "Cache disabled".to_string(),
63                reuse_probability: 0.0,
64                estimated_benefit: 0.0,
65                suggested_priority: CachePriority::Low,
66            };
67        }
68
69        let config = self.cache_manager.config();
70
71        if estimated_rows < config.min_row_count {
72            return CteCacheDecision {
73                should_cache: false,
74                reason: format!(
75                    "Row count {} below minimum {}",
76                    estimated_rows, config.min_row_count
77                ),
78                reuse_probability: 0.0,
79                estimated_benefit: 0.0,
80                suggested_priority: CachePriority::Low,
81            };
82        }
83
84        if estimated_rows > config.max_row_count {
85            return CteCacheDecision {
86                should_cache: false,
87                reason: format!(
88                    "Row count {} above maximum {}",
89                    estimated_rows, config.max_row_count
90                ),
91                reuse_probability: 0.0,
92                estimated_benefit: 0.0,
93                suggested_priority: CachePriority::Low,
94            };
95        }
96
97        let reuse_prob = self.cache_manager.predict_reuse_probability(cte_definition);
98
99        if reuse_prob < self.min_reuse_probability {
100            return CteCacheDecision {
101                should_cache: false,
102                reason: format!(
103                    "Reuse probability {:.2} below threshold {:.2}",
104                    reuse_prob, self.min_reuse_probability
105                ),
106                reuse_probability: reuse_prob,
107                estimated_benefit: 0.0,
108                suggested_priority: CachePriority::Low,
109            };
110        }
111
112        let estimated_benefit = compute_cost * reuse_prob;
113
114        let priority = if compute_cost > 1000.0 {
115            CachePriority::High
116        } else if compute_cost > 100.0 {
117            CachePriority::Normal
118        } else {
119            CachePriority::Low
120        };
121
122        CteCacheDecision {
123            should_cache: estimated_benefit >= self.min_benefit,
124            reason: if estimated_benefit >= self.min_benefit {
125                format!("Estimated benefit {:.2} meets threshold", estimated_benefit)
126            } else {
127                format!(
128                    "Estimated benefit {:.2} below threshold {:.2}",
129                    estimated_benefit, self.min_benefit
130                )
131            },
132            reuse_probability: reuse_prob,
133            estimated_benefit,
134            suggested_priority: priority,
135        }
136    }
137}