1use crate::segment::Segment;
16use crate::value::IndexValue;
17
18pub use crate::view_sidecar::{MAX_VIEWS, ViewCatalog};
19
20#[derive(Debug, Clone, PartialEq)]
22pub struct Leaf {
23 pub index: Vec<u8>,
25 pub min: IndexValue,
28 pub max: IndexValue,
30}
31
32#[derive(Debug, Clone, PartialEq)]
35pub enum Tree {
36 Leaf(Leaf),
38 And(Box<Tree>, Box<Tree>),
40 Or(Box<Tree>, Box<Tree>),
42 Diff(Box<Tree>, Box<Tree>),
44}
45
46impl Tree {
47 pub fn leaves(&self) -> usize {
49 match self {
50 Tree::Leaf(_) => 1,
51 Tree::And(a, b) | Tree::Or(a, b) | Tree::Diff(a, b) => a.leaves() + b.leaves(),
52 }
53 }
54
55 pub fn depth(&self) -> usize {
57 match self {
58 Tree::Leaf(_) => 1,
59 Tree::And(a, b) | Tree::Or(a, b) | Tree::Diff(a, b) => 1 + a.depth().max(b.depth()),
60 }
61 }
62
63 pub fn each_leaf<F: FnMut(&Leaf)>(&self, f: &mut F) {
65 match self {
66 Tree::Leaf(l) => f(l),
67 Tree::And(a, b) | Tree::Or(a, b) | Tree::Diff(a, b) => {
68 a.each_leaf(f);
69 b.each_leaf(f);
70 }
71 }
72 }
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub enum ViewMode {
78 Virtual,
80 Materialized {
82 top_k: u32,
84 },
85}
86
87#[derive(Debug, Clone, PartialEq)]
89pub struct ViewSpec {
90 pub name: Vec<u8>,
92 pub tree: Tree,
94 pub order_by: Vec<u8>,
97 pub desc: bool,
99 pub mode: ViewMode,
101 pub via: Option<Vec<u8>>,
104}
105
106pub const MAX_TREE_DEPTH: usize = 3;
108pub const MAX_TREE_LEAVES: usize = 4;
110
111impl ViewSpec {
112 pub fn validate(&self) -> Result<(), &'static str> {
114 if self.tree.depth() > MAX_TREE_DEPTH {
115 return Err("ERR view tree deeper than 3");
116 }
117 if self.tree.leaves() > MAX_TREE_LEAVES {
118 return Err("ERR view tree has more than 4 leaves");
119 }
120 Ok(())
121 }
122}
123
124pub fn eval_tree<'a>(tree: &Tree, seg: &impl Fn(&[u8]) -> Option<&'a Segment>) -> Vec<Vec<u8>> {
129 match tree {
130 Tree::Leaf(l) => match seg(&l.index) {
131 Some(s) => {
132 let (hits, _) = s.range(&l.min, &l.max, None, usize::MAX);
133 hits.into_iter().map(|(k, _)| k).collect()
134 }
135 None => Vec::new(),
136 },
137 Tree::And(a, b) => {
138 let (xa, xb) = (eval_tree(a, seg), eval_tree(b, seg));
141 let (mut drive, probe) = if xa.len() <= xb.len() { (xa, xb) } else { (xb, xa) };
142 let set: std::collections::HashSet<&[u8]> = probe.iter().map(Vec::as_slice).collect();
143 drive.retain(|k| set.contains(k.as_slice()));
144 drive
145 }
146 Tree::Or(a, b) => {
147 let mut xa = eval_tree(a, seg);
148 xa.extend(eval_tree(b, seg));
149 xa.sort();
150 xa.dedup();
151 xa
152 }
153 Tree::Diff(a, b) => {
154 let mut xa = eval_tree(a, seg);
155 let xb = eval_tree(b, seg);
156 let set: std::collections::HashSet<&[u8]> = xb.iter().map(Vec::as_slice).collect();
157 xa.retain(|k| !set.contains(k.as_slice()));
158 xa
159 }
160 }
161}
162
163pub fn key_in_tree<'a>(
166 tree: &Tree,
167 key: &[u8],
168 seg: &impl Fn(&[u8]) -> Option<&'a Segment>,
169) -> bool {
170 match tree {
171 Tree::Leaf(l) => seg(&l.index)
172 .and_then(|s| s.verify_entry(key))
173 .is_some_and(|v| *v >= l.min && *v <= l.max),
174 Tree::And(a, b) => key_in_tree(a, key, seg) && key_in_tree(b, key, seg),
175 Tree::Or(a, b) => key_in_tree(a, key, seg) || key_in_tree(b, key, seg),
176 Tree::Diff(a, b) => key_in_tree(a, key, seg) && !key_in_tree(b, key, seg),
177 }
178}
179
180pub fn key_in_tree_vals(tree: &Tree, vals: &impl Fn(&[u8]) -> Option<IndexValue>) -> bool {
185 match tree {
186 Tree::Leaf(l) => vals(&l.index).is_some_and(|v| v >= l.min && v <= l.max),
187 Tree::And(a, b) => key_in_tree_vals(a, vals) && key_in_tree_vals(b, vals),
188 Tree::Or(a, b) => key_in_tree_vals(a, vals) || key_in_tree_vals(b, vals),
189 Tree::Diff(a, b) => key_in_tree_vals(a, vals) && !key_in_tree_vals(b, vals),
190 }
191}
192
193#[derive(Debug, Default)]
198pub struct MaterializedSet {
199 set: std::collections::BTreeSet<(IndexValue, Vec<u8>)>,
200 back: std::collections::HashMap<Vec<u8>, IndexValue>,
201 top_k: u32,
203 desc: bool,
206 pub order_excluded: u64,
208}
209
210impl MaterializedSet {
211 pub fn new(top_k: u32, desc: bool) -> Self {
214 Self { top_k, desc, ..Default::default() }
215 }
216
217 fn cap(&self) -> usize {
218 if self.top_k == 0 { usize::MAX } else { (self.top_k + self.top_k / 4) as usize }
219 }
220
221 pub fn apply(&mut self, key: &[u8], member: bool, order: Option<IndexValue>) -> bool {
225 if self.top_k != 0
231 && member
232 && !self.back.contains_key(key)
233 && self.set.len() >= self.cap()
234 && let Some(v) = &order
235 {
236 let enters = if self.desc {
237 self.set.iter().next().is_some_and(|(worst, _)| v > worst)
238 } else {
239 self.set.iter().next_back().is_some_and(|(worst, _)| v < worst)
240 };
241 if !enters {
242 return false;
243 }
244 }
245 if let Some(old) = self.back.remove(key) {
246 self.set.remove(&(old, key.to_vec()));
247 }
248 match (member, order) {
249 (true, Some(v)) => {
250 self.back.insert(key.to_vec(), v.clone());
251 self.set.insert((v, key.to_vec()));
252 self.evict_past_cap();
253 false
254 }
255 (true, None) => {
256 self.order_excluded += 1;
257 false
258 }
259 _ => self.top_k != 0 && self.set.len() < self.top_k as usize,
260 }
261 }
262
263 fn evict_past_cap(&mut self) {
266 if self.set.len() > self.cap() {
267 let worst = if self.desc {
268 self.set.iter().next().cloned()
269 } else {
270 self.set.iter().next_back().cloned()
271 };
272 if let Some(w) = worst {
273 self.set.remove(&w);
274 self.back.remove(&w.1);
275 }
276 }
277 }
278
279 pub fn page(
284 &self,
285 after: Option<&(IndexValue, Vec<u8>)>,
286 limit: usize,
287 desc: bool,
288 ) -> Vec<(IndexValue, Vec<u8>)> {
289 if desc {
290 let iter: Box<dyn Iterator<Item = &(IndexValue, Vec<u8>)>> = match after {
291 Some(c) => Box::new(
292 self.set
293 .range((std::ops::Bound::Unbounded, std::ops::Bound::Excluded(c.clone())))
294 .rev(),
295 ),
296 None => Box::new(self.set.iter().rev()),
297 };
298 return iter.take(limit).cloned().collect();
299 }
300 let iter: Box<dyn Iterator<Item = &(IndexValue, Vec<u8>)>> = match after {
301 Some(c) => Box::new(
302 self.set.range((std::ops::Bound::Excluded(c.clone()), std::ops::Bound::Unbounded)),
303 ),
304 None => Box::new(self.set.iter()),
305 };
306 iter.take(limit).cloned().collect()
307 }
308
309 pub fn len(&self) -> usize {
311 self.set.len()
312 }
313
314 pub fn is_empty(&self) -> bool {
316 self.set.is_empty()
317 }
318
319 pub fn clear(&mut self) {
321 self.set.clear();
322 self.back.clear();
323 }
324
325 pub fn approx_bytes(&self) -> u64 {
327 self.set.iter().map(|(v, k)| (v.approx_bytes() + k.len() + 48) as u64).sum()
328 }
329}
330
331#[cfg(test)]
332#[path = "view_tests.rs"]
333mod tests;