sqry_core/session/
cache.rs1use std::sync::atomic::{AtomicU64, Ordering};
8use std::sync::{Arc, Mutex};
9use std::time::{Instant, SystemTime};
10
11use crate::graph::CodeGraph;
12
13pub struct CachedIndex {
15 pub graph: Arc<CodeGraph>,
17 pub loaded_at: Instant,
19 last_accessed: AtomicInstant,
21 pub file_mtime: SystemTime,
23 pub query_count: AtomicU64,
25}
26
27impl CachedIndex {
28 #[must_use]
30 pub fn new(graph: Arc<CodeGraph>, file_mtime: SystemTime) -> Self {
31 let now = Instant::now();
32 Self {
33 graph,
34 loaded_at: now,
35 last_accessed: AtomicInstant::new(now),
36 file_mtime,
37 query_count: AtomicU64::new(0),
38 }
39 }
40
41 pub fn access(&self) {
43 self.last_accessed.store(Instant::now());
44 self.query_count.fetch_add(1, Ordering::Relaxed);
45 }
46
47 pub fn last_accessed(&self) -> Instant {
49 self.last_accessed.load()
50 }
51
52 #[cfg(test)]
54 pub fn set_last_accessed(&self, instant: Instant) {
55 self.last_accessed.store(instant);
56 }
57
58 pub fn query_count(&self) -> u64 {
60 self.query_count.load(Ordering::Relaxed)
61 }
62}
63
64pub struct AtomicInstant {
66 inner: Mutex<Instant>,
67}
68
69impl AtomicInstant {
70 fn new(instant: Instant) -> Self {
71 Self {
72 inner: Mutex::new(instant),
73 }
74 }
75
76 fn store(&self, instant: Instant) {
77 *self
79 .inner
80 .lock()
81 .unwrap_or_else(std::sync::PoisonError::into_inner) = instant;
82 }
83
84 fn load(&self) -> Instant {
85 *self
87 .inner
88 .lock()
89 .unwrap_or_else(std::sync::PoisonError::into_inner)
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use std::time::Duration;
97
98 #[test]
99 fn access_updates_tracking() {
100 let graph = Arc::new(CodeGraph::new());
101 let cached = CachedIndex::new(graph, SystemTime::now());
102
103 assert_eq!(cached.query_count(), 0);
104 let before = cached.last_accessed();
105
106 cached.access();
107
108 assert_eq!(cached.query_count(), 1);
109 assert!(cached.last_accessed() >= before);
110 }
111
112 #[test]
113 fn set_last_accessed_allows_manual_adjustment() {
114 let graph = Arc::new(CodeGraph::new());
115 let cached = CachedIndex::new(graph, SystemTime::now());
116 let past = Instant::now().checked_sub(Duration::from_secs(5)).unwrap();
117
118 cached.set_last_accessed(past);
119
120 assert!(cached.last_accessed() <= Instant::now());
121 }
122}