vtcode_core/compaction/
prefire.rs1use std::sync::Mutex;
2use std::sync::atomic::AtomicBool;
3use std::sync::atomic::Ordering;
4
5#[derive(Debug, Clone)]
9pub struct AsyncCompactionCache {
10 pub note1: String,
12 pub prefix_len: usize,
14 pub fingerprint: u64,
17 pub model_slug: String,
19 pub pass1_latency_ms: u64,
21}
22
23#[derive(Default)]
26pub struct PrefireState {
27 in_flight: AtomicBool,
29 cache: Mutex<Option<AsyncCompactionCache>>,
31}
32
33impl PrefireState {
34 pub fn try_begin(&self) -> bool {
37 self.in_flight
38 .compare_exchange(false, true, Ordering::AcqRel, Ordering::Relaxed)
39 .is_ok()
40 }
41
42 pub fn finish(&self) {
44 self.in_flight.store(false, Ordering::Release);
45 }
46
47 pub fn is_in_flight(&self) -> bool {
49 self.in_flight.load(Ordering::Acquire)
50 }
51
52 pub fn store(&self, cache: AsyncCompactionCache) {
54 *self.cache.lock().unwrap_or_else(std::sync::PoisonError::into_inner) = Some(cache);
55 }
56
57 pub fn take(&self) -> Option<AsyncCompactionCache> {
59 self.cache.lock().unwrap_or_else(std::sync::PoisonError::into_inner).take()
60 }
61
62 pub fn clear(&self) {
64 *self.cache.lock().unwrap_or_else(std::sync::PoisonError::into_inner) = None;
65 }
66
67 pub fn has_cache(&self) -> bool {
69 self.cache.lock().unwrap_or_else(std::sync::PoisonError::into_inner).is_some()
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn try_begin_blocks_concurrent_wins() {
79 let state = PrefireState::default();
80 assert!(state.try_begin());
81 assert!(!state.try_begin());
82 state.finish();
83 assert!(state.try_begin());
84 }
85
86 #[test]
87 fn store_take_roundtrip() {
88 let state = PrefireState::default();
89 state.store(AsyncCompactionCache {
90 note1: "note".to_string(),
91 prefix_len: 3,
92 fingerprint: 42,
93 model_slug: "model".to_string(),
94 pass1_latency_ms: 5,
95 });
96 assert!(state.has_cache());
97 let cache = state.take().unwrap();
98 assert_eq!(cache.note1, "note");
99 assert_eq!(cache.prefix_len, 3);
100 assert!(!state.has_cache());
101 }
102
103 #[test]
104 fn clear_drops_cache() {
105 let state = PrefireState::default();
106 state.store(AsyncCompactionCache {
107 note1: "note".to_string(),
108 prefix_len: 3,
109 fingerprint: 42,
110 model_slug: "model".to_string(),
111 pass1_latency_ms: 5,
112 });
113 assert!(state.has_cache());
114 state.clear();
115 assert!(!state.has_cache());
116 }
117
118 #[test]
119 fn is_in_flight_reflects_try_begin() {
120 let state = PrefireState::default();
121 assert!(!state.is_in_flight());
122 state.try_begin();
123 assert!(state.is_in_flight());
124 state.finish();
125 assert!(!state.is_in_flight());
126 }
127}