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