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>(
129 tree: &Tree,
130 seg: &impl Fn(&[u8]) -> Option<&'a Segment>,
131) -> Vec<Vec<u8>> {
132 match tree {
133 Tree::Leaf(l) => match seg(&l.index) {
134 Some(s) => {
135 let (hits, _) = s.range(&l.min, &l.max, None, usize::MAX);
136 hits.into_iter().map(|(k, _)| k).collect()
137 }
138 None => Vec::new(),
139 },
140 Tree::And(a, b) => {
141 let (xa, xb) = (eval_tree(a, seg), eval_tree(b, seg));
144 let (mut drive, probe) = if xa.len() <= xb.len() { (xa, xb) } else { (xb, xa) };
145 let set: std::collections::HashSet<&[u8]> =
146 probe.iter().map(Vec::as_slice).collect();
147 drive.retain(|k| set.contains(k.as_slice()));
148 drive
149 }
150 Tree::Or(a, b) => {
151 let mut xa = eval_tree(a, seg);
152 xa.extend(eval_tree(b, seg));
153 xa.sort();
154 xa.dedup();
155 xa
156 }
157 Tree::Diff(a, b) => {
158 let mut xa = eval_tree(a, seg);
159 let xb = eval_tree(b, seg);
160 let set: std::collections::HashSet<&[u8]> = xb.iter().map(Vec::as_slice).collect();
161 xa.retain(|k| !set.contains(k.as_slice()));
162 xa
163 }
164 }
165}
166
167pub fn key_in_tree<'a>(
170 tree: &Tree,
171 key: &[u8],
172 seg: &impl Fn(&[u8]) -> Option<&'a Segment>,
173) -> bool {
174 match tree {
175 Tree::Leaf(l) => seg(&l.index)
176 .and_then(|s| s.verify_entry(key))
177 .is_some_and(|v| *v >= l.min && *v <= l.max),
178 Tree::And(a, b) => key_in_tree(a, key, seg) && key_in_tree(b, key, seg),
179 Tree::Or(a, b) => key_in_tree(a, key, seg) || key_in_tree(b, key, seg),
180 Tree::Diff(a, b) => key_in_tree(a, key, seg) && !key_in_tree(b, key, seg),
181 }
182}
183
184pub fn key_in_tree_vals(
189 tree: &Tree,
190 vals: &impl Fn(&[u8]) -> Option<IndexValue>,
191) -> bool {
192 match tree {
193 Tree::Leaf(l) => vals(&l.index).is_some_and(|v| v >= l.min && v <= l.max),
194 Tree::And(a, b) => key_in_tree_vals(a, vals) && key_in_tree_vals(b, vals),
195 Tree::Or(a, b) => key_in_tree_vals(a, vals) || key_in_tree_vals(b, vals),
196 Tree::Diff(a, b) => key_in_tree_vals(a, vals) && !key_in_tree_vals(b, vals),
197 }
198}
199
200#[derive(Debug, Default)]
205pub struct MaterializedSet {
206 set: std::collections::BTreeSet<(IndexValue, Vec<u8>)>,
207 back: std::collections::HashMap<Vec<u8>, IndexValue>,
208 top_k: u32,
210 desc: bool,
213 pub order_excluded: u64,
215}
216
217impl MaterializedSet {
218 pub fn new(top_k: u32, desc: bool) -> Self {
221 Self { top_k, desc, ..Default::default() }
222 }
223
224 fn cap(&self) -> usize {
225 if self.top_k == 0 {
226 usize::MAX
227 } else {
228 (self.top_k + self.top_k / 4) as usize
229 }
230 }
231
232 pub fn apply(&mut self, key: &[u8], member: bool, order: Option<IndexValue>) -> bool {
236 if self.top_k != 0
242 && member
243 && !self.back.contains_key(key)
244 && self.set.len() >= self.cap()
245 && let Some(v) = &order
246 {
247 let enters = if self.desc {
248 self.set.iter().next().is_some_and(|(worst, _)| v > worst)
249 } else {
250 self.set.iter().next_back().is_some_and(|(worst, _)| v < worst)
251 };
252 if !enters {
253 return false;
254 }
255 }
256 if let Some(old) = self.back.remove(key) {
257 self.set.remove(&(old, key.to_vec()));
258 }
259 match (member, order) {
260 (true, Some(v)) => {
261 self.back.insert(key.to_vec(), v.clone());
262 self.set.insert((v, key.to_vec()));
263 self.evict_past_cap();
264 false
265 }
266 (true, None) => {
267 self.order_excluded += 1;
268 false
269 }
270 _ => {
271 self.top_k != 0 && self.set.len() < self.top_k as usize
272 }
273 }
274 }
275
276 fn evict_past_cap(&mut self) {
279 if self.set.len() > self.cap() {
280 let worst = if self.desc {
281 self.set.iter().next().cloned()
282 } else {
283 self.set.iter().next_back().cloned()
284 };
285 if let Some(w) = worst {
286 self.set.remove(&w);
287 self.back.remove(&w.1);
288 }
289 }
290 }
291
292 pub fn page(
297 &self,
298 after: Option<&(IndexValue, Vec<u8>)>,
299 limit: usize,
300 desc: bool,
301 ) -> Vec<(IndexValue, Vec<u8>)> {
302 if desc {
303 let iter: Box<dyn Iterator<Item = &(IndexValue, Vec<u8>)>> = match after {
304 Some(c) => Box::new(
305 self.set
306 .range((std::ops::Bound::Unbounded, std::ops::Bound::Excluded(c.clone())))
307 .rev(),
308 ),
309 None => Box::new(self.set.iter().rev()),
310 };
311 return iter.take(limit).cloned().collect();
312 }
313 let iter: Box<dyn Iterator<Item = &(IndexValue, Vec<u8>)>> = match after {
314 Some(c) => Box::new(self.set.range((
315 std::ops::Bound::Excluded(c.clone()),
316 std::ops::Bound::Unbounded,
317 ))),
318 None => Box::new(self.set.iter()),
319 };
320 iter.take(limit).cloned().collect()
321 }
322
323 pub fn len(&self) -> usize {
325 self.set.len()
326 }
327
328 pub fn is_empty(&self) -> bool {
330 self.set.is_empty()
331 }
332
333 pub fn clear(&mut self) {
335 self.set.clear();
336 self.back.clear();
337 }
338
339 pub fn approx_bytes(&self) -> u64 {
341 self.set
342 .iter()
343 .map(|(v, k)| (v.approx_bytes() + k.len() + 48) as u64)
344 .sum()
345 }
346}
347
348#[cfg(test)]
349#[path = "view_tests.rs"]
350mod tests;