1use crate::segment::Segment;
17use crate::value::IndexValue;
18
19pub use crate::view_sidecar::{MAX_VIEWS, ViewCatalog};
20
21#[derive(Debug, Clone, PartialEq)]
23pub struct Leaf {
24 pub index: Vec<u8>,
26 pub min: IndexValue,
29 pub max: IndexValue,
31}
32
33#[derive(Debug, Clone, PartialEq)]
36pub enum Tree {
37 Leaf(Leaf),
39 And(Box<Tree>, Box<Tree>),
41 Or(Box<Tree>, Box<Tree>),
43 Diff(Box<Tree>, Box<Tree>),
45}
46
47impl Tree {
48 pub fn leaves(&self) -> usize {
50 match self {
51 Tree::Leaf(_) => 1,
52 Tree::And(a, b) | Tree::Or(a, b) | Tree::Diff(a, b) => a.leaves() + b.leaves(),
53 }
54 }
55
56 pub fn depth(&self) -> usize {
58 match self {
59 Tree::Leaf(_) => 1,
60 Tree::And(a, b) | Tree::Or(a, b) | Tree::Diff(a, b) => 1 + a.depth().max(b.depth()),
61 }
62 }
63
64 pub fn each_leaf<F: FnMut(&Leaf)>(&self, f: &mut F) {
66 match self {
67 Tree::Leaf(l) => f(l),
68 Tree::And(a, b) | Tree::Or(a, b) | Tree::Diff(a, b) => {
69 a.each_leaf(f);
70 b.each_leaf(f);
71 }
72 }
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub enum ViewMode {
79 Virtual,
81 Materialized {
83 top_k: u32,
85 },
86}
87
88#[derive(Debug, Clone, PartialEq)]
90pub struct ViewSpec {
91 pub name: Vec<u8>,
93 pub tree: Tree,
95 pub order_by: Vec<u8>,
98 pub desc: bool,
100 pub mode: ViewMode,
102 pub via: Option<Vec<u8>>,
105}
106
107pub const MAX_TREE_DEPTH: usize = 3;
109pub const MAX_TREE_LEAVES: usize = 4;
111
112impl ViewSpec {
113 pub fn validate(&self) -> Result<(), &'static str> {
115 if self.tree.depth() > MAX_TREE_DEPTH {
116 return Err("ERR view tree deeper than 3");
117 }
118 if self.tree.leaves() > MAX_TREE_LEAVES {
119 return Err("ERR view tree has more than 4 leaves");
120 }
121 Ok(())
122 }
123}
124
125pub fn eval_tree<'a>(
130 tree: &Tree,
131 seg: &impl Fn(&[u8]) -> Option<&'a Segment>,
132) -> Vec<Vec<u8>> {
133 match tree {
134 Tree::Leaf(l) => match seg(&l.index) {
135 Some(s) => {
136 let (hits, _) = s.range(&l.min, &l.max, None, usize::MAX);
137 hits.into_iter().map(|(k, _)| k).collect()
138 }
139 None => Vec::new(),
140 },
141 Tree::And(a, b) => {
142 let (xa, xb) = (eval_tree(a, seg), eval_tree(b, seg));
145 let (mut drive, probe) = if xa.len() <= xb.len() { (xa, xb) } else { (xb, xa) };
146 let set: std::collections::HashSet<&[u8]> =
147 probe.iter().map(Vec::as_slice).collect();
148 drive.retain(|k| set.contains(k.as_slice()));
149 drive
150 }
151 Tree::Or(a, b) => {
152 let mut xa = eval_tree(a, seg);
153 xa.extend(eval_tree(b, seg));
154 xa.sort();
155 xa.dedup();
156 xa
157 }
158 Tree::Diff(a, b) => {
159 let mut xa = eval_tree(a, seg);
160 let xb = eval_tree(b, seg);
161 let set: std::collections::HashSet<&[u8]> = xb.iter().map(Vec::as_slice).collect();
162 xa.retain(|k| !set.contains(k.as_slice()));
163 xa
164 }
165 }
166}
167
168pub fn key_in_tree<'a>(
171 tree: &Tree,
172 key: &[u8],
173 seg: &impl Fn(&[u8]) -> Option<&'a Segment>,
174) -> bool {
175 match tree {
176 Tree::Leaf(l) => seg(&l.index)
177 .and_then(|s| s.verify_entry(key))
178 .is_some_and(|v| *v >= l.min && *v <= l.max),
179 Tree::And(a, b) => key_in_tree(a, key, seg) && key_in_tree(b, key, seg),
180 Tree::Or(a, b) => key_in_tree(a, key, seg) || key_in_tree(b, key, seg),
181 Tree::Diff(a, b) => key_in_tree(a, key, seg) && !key_in_tree(b, key, seg),
182 }
183}
184
185pub fn key_in_tree_vals(
190 tree: &Tree,
191 vals: &impl Fn(&[u8]) -> Option<IndexValue>,
192) -> bool {
193 match tree {
194 Tree::Leaf(l) => vals(&l.index).is_some_and(|v| v >= l.min && v <= l.max),
195 Tree::And(a, b) => key_in_tree_vals(a, vals) && key_in_tree_vals(b, vals),
196 Tree::Or(a, b) => key_in_tree_vals(a, vals) || key_in_tree_vals(b, vals),
197 Tree::Diff(a, b) => key_in_tree_vals(a, vals) && !key_in_tree_vals(b, vals),
198 }
199}
200
201#[derive(Debug, Default)]
206pub struct MaterializedSet {
207 set: std::collections::BTreeSet<(IndexValue, Vec<u8>)>,
208 back: std::collections::HashMap<Vec<u8>, IndexValue>,
209 top_k: u32,
211 desc: bool,
214 pub order_excluded: u64,
216}
217
218impl MaterializedSet {
219 pub fn new(top_k: u32, desc: bool) -> Self {
222 Self { top_k, desc, ..Default::default() }
223 }
224
225 fn cap(&self) -> usize {
226 if self.top_k == 0 {
227 usize::MAX
228 } else {
229 (self.top_k + self.top_k / 4) as usize
230 }
231 }
232
233 pub fn apply(&mut self, key: &[u8], member: bool, order: Option<IndexValue>) -> bool {
237 if self.top_k != 0
243 && member
244 && !self.back.contains_key(key)
245 && self.set.len() >= self.cap()
246 && let Some(v) = &order
247 {
248 let enters = if self.desc {
249 self.set.iter().next().is_some_and(|(worst, _)| v > worst)
250 } else {
251 self.set.iter().next_back().is_some_and(|(worst, _)| v < worst)
252 };
253 if !enters {
254 return false;
255 }
256 }
257 if let Some(old) = self.back.remove(key) {
258 self.set.remove(&(old, key.to_vec()));
259 }
260 match (member, order) {
261 (true, Some(v)) => {
262 self.back.insert(key.to_vec(), v.clone());
263 self.set.insert((v, key.to_vec()));
264 self.evict_past_cap();
265 false
266 }
267 (true, None) => {
268 self.order_excluded += 1;
269 false
270 }
271 _ => {
272 self.top_k != 0 && self.set.len() < self.top_k as usize
273 }
274 }
275 }
276
277 fn evict_past_cap(&mut self) {
280 if self.set.len() > self.cap() {
281 let worst = if self.desc {
282 self.set.iter().next().cloned()
283 } else {
284 self.set.iter().next_back().cloned()
285 };
286 if let Some(w) = worst {
287 self.set.remove(&w);
288 self.back.remove(&w.1);
289 }
290 }
291 }
292
293 pub fn page(
298 &self,
299 after: Option<&(IndexValue, Vec<u8>)>,
300 limit: usize,
301 desc: bool,
302 ) -> Vec<(IndexValue, Vec<u8>)> {
303 if desc {
304 let iter: Box<dyn Iterator<Item = &(IndexValue, Vec<u8>)>> = match after {
305 Some(c) => Box::new(
306 self.set
307 .range((std::ops::Bound::Unbounded, std::ops::Bound::Excluded(c.clone())))
308 .rev(),
309 ),
310 None => Box::new(self.set.iter().rev()),
311 };
312 return iter.take(limit).cloned().collect();
313 }
314 let iter: Box<dyn Iterator<Item = &(IndexValue, Vec<u8>)>> = match after {
315 Some(c) => Box::new(self.set.range((
316 std::ops::Bound::Excluded(c.clone()),
317 std::ops::Bound::Unbounded,
318 ))),
319 None => Box::new(self.set.iter()),
320 };
321 iter.take(limit).cloned().collect()
322 }
323
324 pub fn len(&self) -> usize {
326 self.set.len()
327 }
328
329 pub fn is_empty(&self) -> bool {
331 self.set.is_empty()
332 }
333
334 pub fn clear(&mut self) {
336 self.set.clear();
337 self.back.clear();
338 }
339
340 pub fn approx_bytes(&self) -> u64 {
342 self.set
343 .iter()
344 .map(|(v, k)| (v.approx_bytes() + k.len() + 48) as u64)
345 .sum()
346 }
347}
348
349#[cfg(test)]
350#[path = "view_tests.rs"]
351mod tests;