Skip to main content

linkrs_query/cache/cte_cache/
entry.rs

1use std::sync::Arc;
2use std::time::{Duration, Instant};
3
4use crate::cache::config::CachePriority;
5
6/// CTE cache entries
7#[derive(Debug, Clone)]
8pub struct CteCacheEntry {
9    /// Resulting data (shared using Arc)
10    pub data: Arc<Vec<u8>>,
11    /// Number of result rows
12    pub row_count: u64,
13    /// Result size (bytes)
14    pub data_size: usize,
15    /// Creation time
16    pub created_at: Instant,
17    /// Last access time
18    pub last_accessed: Instant,
19    /// Number of visits
20    pub access_count: u64,
21    /// Estimated probability of reuse
22    pub reuse_probability: f64,
23    /// CTE definition hash (used to identify identical CTEs)
24    pub cte_hash: String,
25    /// CTE definition text
26    pub cte_definition: String,
27    /// Cache priority
28    pub priority: CachePriority,
29    /// Compute cost (milliseconds)
30    pub compute_cost_ms: u64,
31    /// Access frequency (per minute)
32    pub access_frequency: f64,
33    /// Dependent tables (for invalidation detection)
34    pub dependent_tables: Vec<String>,
35}
36
37impl CteCacheEntry {
38    /// Creating a new cache entry
39    pub fn new(
40        cte_hash: String,
41        cte_definition: String,
42        data: Vec<u8>,
43        row_count: u64,
44        compute_cost_ms: u64,
45    ) -> Self {
46        let data_size = data.len();
47        Self {
48            data: Arc::new(data),
49            row_count,
50            data_size,
51            created_at: Instant::now(),
52            last_accessed: Instant::now(),
53            access_count: 0,
54            reuse_probability: 0.5,
55            cte_hash,
56            cte_definition,
57            priority: CachePriority::Normal,
58            compute_cost_ms,
59            access_frequency: 0.0,
60            dependent_tables: Vec::new(),
61        }
62    }
63
64    /// Estimate memory usage (bytes)
65    pub fn estimate_memory(&self) -> usize {
66        let mut total = 0;
67
68        total += std::mem::size_of::<Arc<Vec<u8>>>();
69        total += std::mem::size_of::<Vec<u8>>();
70        total += self.data_size;
71
72        total += std::mem::size_of::<String>();
73        total += self.cte_hash.capacity();
74
75        total += std::mem::size_of::<String>();
76        total += self.cte_definition.capacity();
77
78        total += std::mem::size_of::<Vec<String>>();
79        for table in &self.dependent_tables {
80            total += std::mem::size_of::<String>();
81            total += table.capacity();
82        }
83
84        total += std::mem::size_of::<Instant>() * 2;
85        total += std::mem::size_of::<u64>() * 3;
86        total += std::mem::size_of::<f64>() * 2;
87        total += std::mem::size_of::<CachePriority>();
88
89        total
90    }
91
92    /// Calculate cache value score (for eviction decisions)
93    pub fn value_score(&self) -> f64 {
94        let frequency_score = self.access_frequency * 0.4;
95        let cost_score = (self.compute_cost_ms as f64 / 1000.0) * 0.3;
96        let priority_score = (self.priority as i32 as f64) * 0.2;
97        let size_penalty = (self.data_size as f64 / 1024.0 / 1024.0) * 0.1;
98
99        frequency_score + cost_score + priority_score - size_penalty
100    }
101
102    /// Recorded visits
103    pub fn record_access(&mut self) {
104        self.last_accessed = Instant::now();
105        self.access_count += 1;
106
107        let elapsed_minutes = self.created_at.elapsed().as_secs_f64() / 60.0;
108        if elapsed_minutes > 0.0 {
109            self.access_frequency = self.access_count as f64 / elapsed_minutes;
110        }
111
112        self.reuse_probability = (self.reuse_probability * 0.7 + 0.3).min(0.95);
113    }
114
115    /// Get Cache Age
116    pub fn age(&self) -> Duration {
117        self.created_at.elapsed()
118    }
119
120    /// Getting free time
121    pub fn idle_time(&self) -> Duration {
122        self.last_accessed.elapsed()
123    }
124
125    /// Calculate cache score (for LRU elimination decisions)
126    /// The lower the score, the more likely you are to be eliminated
127    pub fn cache_score(&self) -> f64 {
128        let idle_factor = self.idle_time().as_secs_f64() / 60.0;
129        let size_factor = (self.data_size as f64 / 1024.0 / 1024.0).max(0.1);
130        let access_factor = (self.access_count as f64).sqrt().max(1.0);
131
132        (idle_factor * size_factor) / (access_factor * self.reuse_probability)
133    }
134}