1mod disk;
4mod entry_bytes;
5mod evict;
6mod label;
7mod memory;
8mod pack;
9mod slots;
10mod stats;
11mod tiered;
12
13pub use disk::{DiskCache, ENGINE_DIR_PREFIX, IO_NANOS_PER_BYTE};
14pub use entry_bytes::{RawF64, SampleCodec};
15pub use memory::MemoryCache;
16pub use pack::{FORMAT as PACK_FORMAT, Medium, Pack, VecMedium};
17pub use slots::{DEFAULT_SLOT_BYTES, Put, Slots};
18pub(crate) use stats::Recording;
19pub use stats::{CacheStats, Lookup, Outcome};
20pub use sva_formula::Hash;
21pub use tiered::Tiered;
22
23use std::path::Path;
24use std::time::Duration;
25
26use sva_formula::SpectralSum;
27use sva_samples::{Buffer, FilterTrace, Frames, Label};
28
29#[derive(Clone, Debug, PartialEq)]
31pub enum Payload {
32 Samples(Box<Buffer>),
33 Frames(Box<Frames>),
34 Symbolic(Box<SpectralSum>),
35}
36
37#[derive(Clone, Copy, Debug, PartialEq, Eq)]
38pub enum PayloadKind {
39 Samples,
40 Frames,
41 Symbolic,
42}
43
44#[derive(Clone, Copy, Debug, PartialEq, Eq)]
46pub enum Expected {
47 Samples {
48 rate: u32,
49 width: usize,
50 samples: usize,
51 },
52 Frames,
53 Symbolic,
54}
55
56#[derive(Clone, Copy, Debug, PartialEq, Eq)]
58pub enum Tier {
59 Memory,
60 Persistent,
61 Volatile,
62}
63
64#[derive(Clone, Debug, PartialEq)]
65pub struct Entry {
66 pub payload: Payload,
67 pub traces: Vec<FilterTrace>,
68 pub label: Option<Label>,
70 pub tier: Tier,
71}
72
73impl Expected {
74 pub fn kind(self) -> PayloadKind {
75 match self {
76 Expected::Samples { .. } => PayloadKind::Samples,
77 Expected::Frames => PayloadKind::Frames,
78 Expected::Symbolic => PayloadKind::Symbolic,
79 }
80 }
81}
82
83impl Payload {
84 pub fn kind(&self) -> PayloadKind {
85 match self {
86 Payload::Samples(_) => PayloadKind::Samples,
87 Payload::Frames(_) => PayloadKind::Frames,
88 Payload::Symbolic(_) => PayloadKind::Symbolic,
89 }
90 }
91
92 pub fn samples(&self) -> Option<&Buffer> {
93 match self {
94 Payload::Samples(buffer) => Some(buffer),
95 _ => None,
96 }
97 }
98
99 pub fn symbolic(&self) -> Option<&SpectralSum> {
100 match self {
101 Payload::Symbolic(sum) => Some(sum),
102 _ => None,
103 }
104 }
105
106 pub fn bytes(&self) -> usize {
107 match self {
108 Payload::Samples(b) => b.len() * b.width * size_of::<f64>(),
109 Payload::Frames(f) => f.width * f.frames * f.bins * 2 * size_of::<f64>(),
110 Payload::Symbolic(n) => {
111 size_of::<SpectralSum>()
112 + n.lanes
113 .iter()
114 .map(|lane| {
115 lane.atoms.len() * size_of::<sva_formula::SpectralAtom>()
116 + (lane.series.len() + lane.modal.len()) * size_of::<SpectralSum>()
117 })
118 .sum::<usize>()
119 }
120 }
121 }
122
123 pub fn answers(&self, expected: Expected) -> bool {
124 match (self, expected) {
125 (
126 Payload::Samples(b),
127 Expected::Samples {
128 rate,
129 width,
130 samples,
131 },
132 ) => b.rate == rate && b.width == width && b.len() == samples,
133 (Payload::Frames(_), Expected::Frames) => true,
134 (Payload::Symbolic(_), Expected::Symbolic) => true,
135 _ => false,
136 }
137 }
138}
139
140#[derive(Clone, Copy)]
143pub struct Cost {
144 #[cfg(not(target_arch = "wasm32"))]
145 began: std::time::Instant,
146}
147
148impl Cost {
149 pub fn begun() -> Cost {
150 Cost {
151 #[cfg(not(target_arch = "wasm32"))]
152 began: std::time::Instant::now(),
153 }
154 }
155
156 pub fn elapsed(self) -> Duration {
157 #[cfg(not(target_arch = "wasm32"))]
158 return self.began.elapsed();
159 #[cfg(target_arch = "wasm32")]
160 return Duration::ZERO;
161 }
162}
163
164pub fn symbolic_key(src: Hash) -> Hash {
166 mixed(src, &[0x73_79_6d_62_6f_6c_69_63])
167}
168
169pub fn frames_key(buffer: Hash, window: usize, hop: usize) -> Hash {
171 mixed(
172 buffer,
173 &[window as u64, hop as u64, 0x66_72_61_6d_65_73_00_01],
174 )
175}
176
177pub fn buffer_key(
180 symbolic: Hash,
181 rate: u32,
182 origin_secs: f64,
183 samples: usize,
184 width: usize,
185 score: sva_samples::AliasScore,
186) -> Hash {
187 mixed(
188 symbolic,
189 &[
190 u64::from(rate),
191 origin_secs.to_bits(),
192 samples as u64,
193 width as u64,
194 u64::from(score == sva_samples::AliasScore::Asked),
195 0x62_75_66_66_65_72_00_01,
196 ],
197 )
198}
199
200fn renamed(traces: &[FilterTrace], node: &str) -> Vec<FilterTrace> {
201 traces
202 .iter()
203 .map(|t| FilterTrace {
204 node: node.to_string(),
205 ..t.clone()
206 })
207 .collect()
208}
209
210const ADDRESS_ROTATE: u32 = 17;
211
212pub(crate) fn mixed(seed: Hash, parts: &[u64]) -> Hash {
213 let mut lanes = sva_formula::Lanes::<ADDRESS_ROTATE>::from(seed);
214 for part in parts {
215 lanes.word(*part);
216 }
217 lanes.finish()
218}
219
220pub trait Cache: Sync {
221 fn load(&self, key: Hash, node: &str, expected: Expected) -> Option<Entry>;
222
223 fn peek(&self, key: Hash, node: &str, expected: Expected) -> Option<Entry>;
225
226 fn store(&self, key: Hash, payload: &Payload, traces: &[FilterTrace], label: Option<&Label>);
227
228 fn holds(&self, key: Hash) -> bool;
229
230 fn worth_storing(&self, cost: Duration, bytes: usize, kind: PayloadKind) -> bool;
231
232 fn sweep(&self);
233
234 fn held_bytes(&self) -> u64;
235
236 fn evicted_bytes(&self) -> u64;
237
238 fn faults(&self) -> u64 {
239 0
240 }
241
242 fn max_bytes(&self) -> u64;
243
244 fn dir(&self) -> Option<&Path> {
245 None
246 }
247}