1use std::collections::BTreeMap;
10use std::collections::BTreeSet;
11use std::collections::HashMap;
12use std::ops::Bound;
13
14use crate::value::IndexValue;
15
16#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Cursor {
20 pub value: IndexValue,
22 pub key: Vec<u8>,
24}
25
26#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
28pub struct SegmentStats {
29 pub entries: u64,
31 pub approx_bytes: u64,
33 pub coerce_failures: u64,
35 pub duplicates: u64,
37}
38
39const ENTRY_OVERHEAD: usize = 48;
41
42#[derive(Debug, Default)]
44pub struct Segment {
45 tree: BTreeSet<(IndexValue, Vec<u8>)>,
46 back: HashMap<Vec<u8>, IndexValue>,
47 value_counts: BTreeMap<IndexValue, u32>,
48 stats: SegmentStats,
49}
50
51impl Segment {
52 pub fn new() -> Self {
54 Self::default()
55 }
56
57 pub fn apply(&mut self, key: &[u8], new: Option<IndexValue>) {
61 if let Some(old) = self.back.remove(key) {
62 self.tree.remove(&(old.clone(), key.to_vec()));
63 self.stats.entries -= 1;
64 self.stats.approx_bytes = self
65 .stats
66 .approx_bytes
67 .saturating_sub((old.approx_bytes() + key.len() + ENTRY_OVERHEAD) as u64);
68 self.dec_count(&old);
69 }
70 match new {
71 Some(v) => {
72 self.stats.entries += 1;
73 self.stats.approx_bytes +=
74 (v.approx_bytes() + key.len() + ENTRY_OVERHEAD) as u64;
75 self.inc_count(&v);
76 self.back.insert(key.to_vec(), v.clone());
77 self.tree.insert((v, key.to_vec()));
78 }
79 None => {
80 self.stats.coerce_failures += 1;
81 }
82 }
83 }
84
85 pub fn remove(&mut self, key: &[u8]) {
87 if let Some(old) = self.back.remove(key) {
88 self.tree.remove(&(old.clone(), key.to_vec()));
89 self.stats.entries -= 1;
90 self.stats.approx_bytes = self
91 .stats
92 .approx_bytes
93 .saturating_sub((old.approx_bytes() + key.len() + ENTRY_OVERHEAD) as u64);
94 self.dec_count(&old);
95 }
96 }
97
98 fn inc_count(&mut self, v: &IndexValue) {
99 let c = self.value_counts.entry(v.clone()).or_insert(0);
100 *c += 1;
101 if *c == 2 {
102 self.stats.duplicates += 1;
103 }
104 }
105
106 fn dec_count(&mut self, v: &IndexValue) {
107 if let Some(c) = self.value_counts.get_mut(v) {
108 if *c == 2 {
109 self.stats.duplicates -= 1;
110 }
111 *c -= 1;
112 if *c == 0 {
113 self.value_counts.remove(v);
114 }
115 }
116 }
117
118 pub fn range(
123 &self,
124 min: &IndexValue,
125 max: &IndexValue,
126 cursor: Option<&Cursor>,
127 limit: usize,
128 ) -> (Vec<(Vec<u8>, IndexValue)>, Option<Cursor>) {
129 let lower: Bound<(IndexValue, Vec<u8>)> = match cursor {
130 Some(c) => Bound::Excluded((c.value.clone(), c.key.clone())),
131 None => Bound::Included((min.clone(), Vec::new())),
132 };
133 let mut out = Vec::with_capacity(limit.min(64));
136 let mut iter = self.tree.range((lower, Bound::Unbounded));
137 for (v, k) in iter.by_ref() {
138 if v > max {
139 break;
140 }
141 out.push((k.clone(), v.clone()));
142 if out.len() == limit {
143 break;
144 }
145 }
146 let next = if out.len() == limit {
147 out.last().map(|(k, v)| Cursor { value: v.clone(), key: k.clone() })
148 } else {
149 None
150 };
151 (out, next)
152 }
153
154 pub fn eq(&self, value: &IndexValue, limit: usize) -> Vec<Vec<u8>> {
157 let lower = Bound::Included((value.clone(), Vec::new()));
158 self.tree
159 .range((lower, Bound::Unbounded))
160 .take_while(|(v, _)| v == value)
161 .take(limit)
162 .map(|(_, k)| k.clone())
163 .collect()
164 }
165
166 pub fn count(&self, min: &IndexValue, max: &IndexValue) -> u64 {
168 let lower = Bound::Included((min.clone(), Vec::new()));
169 self.tree
170 .range((lower, Bound::Unbounded))
171 .take_while(|(v, _)| v <= max)
172 .count() as u64
173 }
174
175 pub fn verify_entry(&self, key: &[u8]) -> Option<&IndexValue> {
178 self.back.get(key)
179 }
180
181 pub fn scan<'s>(
187 &'s self,
188 after: Option<&Cursor>,
189 desc: bool,
190 ) -> Box<dyn Iterator<Item = (&'s IndexValue, &'s [u8])> + 's> {
191 match (after, desc) {
192 (None, false) => Box::new(self.tree.iter().map(|(v, k)| (v, k.as_slice()))),
193 (None, true) => Box::new(self.tree.iter().rev().map(|(v, k)| (v, k.as_slice()))),
194 (Some(c), false) => Box::new(
195 self.tree
196 .range((
197 Bound::Excluded((c.value.clone(), c.key.clone())),
198 Bound::Unbounded,
199 ))
200 .map(|(v, k)| (v, k.as_slice())),
201 ),
202 (Some(c), true) => Box::new(
203 self.tree
204 .range((
205 Bound::Unbounded,
206 Bound::Excluded((c.value.clone(), c.key.clone())),
207 ))
208 .rev()
209 .map(|(v, k)| (v, k.as_slice())),
210 ),
211 }
212 }
213
214 pub fn each_entry<F: FnMut(&[u8], &IndexValue)>(&self, mut f: F) {
216 for (k, v) in &self.back {
217 f(k.as_slice(), v);
218 }
219 }
220
221 pub fn stats(&self) -> SegmentStats {
223 self.stats
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use super::*;
230
231 fn i(v: i64) -> IndexValue {
232 IndexValue::I64(v)
233 }
234
235 fn seeded() -> Segment {
236 let mut s = Segment::new();
237 for (k, v) in [("u1", 30), ("u2", 25), ("u3", 30), ("u4", 40), ("u5", 18)] {
238 s.apply(k.as_bytes(), Some(i(v)));
239 }
240 s
241 }
242
243 #[test]
244 fn apply_replace_remove_and_stats() {
245 let mut s = seeded();
246 assert_eq!(s.stats().entries, 5);
247 assert_eq!(s.stats().duplicates, 1, "30 held twice");
248 s.apply(b"u1", Some(i(31)));
250 assert_eq!(s.stats().entries, 5);
251 assert_eq!(s.stats().duplicates, 0);
252 s.apply(b"u2", None);
254 assert_eq!(s.stats().entries, 4);
255 assert_eq!(s.stats().coerce_failures, 1);
256 s.remove(b"u3");
258 assert_eq!(s.stats().entries, 3);
259 assert_eq!(s.stats().coerce_failures, 1);
260 assert!(s.verify_entry(b"u3").is_none());
261 assert_eq!(s.verify_entry(b"u4"), Some(&i(40)));
262 }
263
264 #[test]
265 fn range_scan_orders_and_paginates() {
266 let s = seeded();
267 let (page1, cur) = s.range(&i(18), &i(30), None, 2);
268 assert_eq!(page1[0], (b"u5".to_vec(), i(18)));
269 assert_eq!(page1[1], (b"u2".to_vec(), i(25)));
270 let cur = cur.expect("more pages");
271 let (page2, cur2) = s.range(&i(18), &i(30), Some(&cur), 10);
272 assert_eq!(
273 page2,
274 vec![(b"u1".to_vec(), i(30)), (b"u3".to_vec(), i(30))],
275 "value tie broken by key"
276 );
277 assert!(cur2.is_none(), "exhausted");
278 assert_eq!(s.count(&i(18), &i(30)), 4);
279 assert_eq!(s.count(&i(99), &i(100)), 0);
280 }
281
282 #[test]
283 fn eq_and_duplicate_fence() {
284 let s = seeded();
285 assert_eq!(s.eq(&i(30), 10), vec![b"u1".to_vec(), b"u3".to_vec()]);
286 assert_eq!(s.eq(&i(40), 10), vec![b"u4".to_vec()]);
287 assert!(s.eq(&i(99), 10).is_empty());
288 }
289
290 #[test]
291 fn long_keys_at_max_value_not_missed() {
292 let mut s = Segment::new();
293 let long_key = vec![0xFFu8; 80]; s.apply(&long_key, Some(i(30)));
295 s.apply(b"short", Some(i(30)));
296 let (hits, _) = s.range(&i(30), &i(30), None, 10);
297 assert_eq!(hits.len(), 2, "max-valued long key must not be missed");
298 assert_eq!(s.eq(&i(30), 10).len(), 2);
299 assert_eq!(s.count(&i(30), &i(30)), 2);
300 }
301
302 #[test]
303 fn f64_and_str_orders() {
304 let mut s = Segment::new();
305 s.apply(b"a", Some(IndexValue::F64(1.5)));
306 s.apply(b"b", Some(IndexValue::F64(-0.5)));
307 let (hits, _) = s.range(&IndexValue::F64(-1.0), &IndexValue::F64(2.0), None, 10);
308 assert_eq!(hits[0].0, b"b".to_vec());
309
310 let mut t = Segment::new();
311 t.apply(b"x", Some(IndexValue::Str(b"banana".to_vec())));
312 t.apply(b"y", Some(IndexValue::Str(b"apple".to_vec())));
313 let (hits, _) = t.range(
314 &IndexValue::Str(b"a".to_vec()),
315 &IndexValue::Str(b"z".to_vec()),
316 None,
317 10,
318 );
319 assert_eq!(hits[0].0, b"y".to_vec());
320 }
321}