linkrs_query/cache/cte_cache/
entry.rs1use std::sync::Arc;
2use std::time::{Duration, Instant};
3
4use crate::cache::config::CachePriority;
5
6#[derive(Debug, Clone)]
8pub struct CteCacheEntry {
9 pub data: Arc<Vec<u8>>,
11 pub row_count: u64,
13 pub data_size: usize,
15 pub created_at: Instant,
17 pub last_accessed: Instant,
19 pub access_count: u64,
21 pub reuse_probability: f64,
23 pub cte_hash: String,
25 pub cte_definition: String,
27 pub priority: CachePriority,
29 pub compute_cost_ms: u64,
31 pub access_frequency: f64,
33 pub dependent_tables: Vec<String>,
35}
36
37impl CteCacheEntry {
38 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 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 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 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 pub fn age(&self) -> Duration {
117 self.created_at.elapsed()
118 }
119
120 pub fn idle_time(&self) -> Duration {
122 self.last_accessed.elapsed()
123 }
124
125 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}