lsm_tree/abstract.rs
1// Copyright (c) 2024-present, fjall-rs
2// This source code is licensed under both the Apache 2.0 and MIT License
3// (found in the LICENSE-* files in the repository)
4
5use crate::{
6 compaction::CompactionStrategy, config::TreeType, tree::inner::MemtableId, AnyTree, BlobTree,
7 Config, KvPair, Memtable, Segment, SegmentId, SeqNo, Snapshot, Tree, UserKey, UserValue,
8};
9use enum_dispatch::enum_dispatch;
10use std::{
11 ops::RangeBounds,
12 sync::{Arc, RwLockWriteGuard},
13};
14
15pub type RangeItem = crate::Result<KvPair>;
16
17/// Generic Tree API
18#[allow(clippy::module_name_repetitions)]
19#[enum_dispatch]
20pub trait AbstractTree {
21 /// Gets the memory usage of all bloom filters in the tree.
22 fn bloom_filter_size(&self) -> usize;
23
24 #[doc(hidden)]
25 fn verify(&self) -> crate::Result<usize>;
26
27 /// Synchronously flushes a memtable to a disk segment.
28 ///
29 /// This method will not make the segment immediately available,
30 /// use [`AbstractTree::register_segments`] for that.
31 ///
32 /// # Errors
33 ///
34 /// Will return `Err` if an IO error occurs.
35 fn flush_memtable(
36 &self,
37 segment_id: SegmentId,
38 memtable: &Arc<Memtable>,
39 seqno_threshold: SeqNo,
40 ) -> crate::Result<Option<Segment>>;
41
42 /// Atomically registers flushed disk segments into the tree, removing their associated sealed memtables.
43 ///
44 /// # Errors
45 ///
46 /// Will return `Err` if an IO error occurs.
47 fn register_segments(&self, segments: &[Segment]) -> crate::Result<()>;
48
49 /// Write-locks the active memtable for exclusive access
50 fn lock_active_memtable(&self) -> RwLockWriteGuard<'_, Memtable>;
51
52 /// Sets the active memtable.
53 ///
54 /// May be used to restore the LSM-tree's in-memory state from a write-ahead log
55 /// after tree recovery.
56 fn set_active_memtable(&self, memtable: Memtable);
57
58 /// Returns the amount of sealed memtables.
59 fn sealed_memtable_count(&self) -> usize;
60
61 /// Adds a sealed memtables.
62 ///
63 /// May be used to restore the LSM-tree's in-memory state from some journals.
64 fn add_sealed_memtable(&self, id: MemtableId, memtable: Arc<Memtable>);
65
66 /// Performs compaction on the tree's levels, blocking the caller until it's done.
67 ///
68 /// # Errors
69 ///
70 /// Will return `Err` if an IO error occurs.
71 fn compact(
72 &self,
73 strategy: Arc<dyn CompactionStrategy>,
74 seqno_threshold: SeqNo,
75 ) -> crate::Result<()>;
76
77 /// Returns the next segment's ID.
78 fn get_next_segment_id(&self) -> SegmentId;
79
80 /// Returns the tree config.
81 fn tree_config(&self) -> &Config;
82
83 /// Returns the highest sequence number.
84 fn get_highest_seqno(&self) -> Option<SeqNo> {
85 let memtable_seqno = self.get_highest_memtable_seqno();
86 let segment_seqno = self.get_highest_persisted_seqno();
87 memtable_seqno.max(segment_seqno)
88 }
89
90 /// Returns the approximate size of the active memtable in bytes.
91 ///
92 /// May be used to flush the memtable if it grows too large.
93 fn active_memtable_size(&self) -> u32;
94
95 /// Returns the tree type.
96 fn tree_type(&self) -> TreeType;
97
98 /// Seals the active memtable, and returns a reference to it.
99 fn rotate_memtable(&self) -> Option<(MemtableId, Arc<Memtable>)>;
100
101 /// Returns the amount of disk segments currently in the tree.
102 fn segment_count(&self) -> usize;
103
104 /// Returns the amount of blob files currently in the tree.
105 fn blob_file_count(&self) -> usize {
106 0
107 }
108
109 /// Returns the amount of disk segments in the first level.
110 fn first_level_segment_count(&self) -> usize;
111
112 /// Returns `true` if the first level is disjoint.
113 fn is_first_level_disjoint(&self) -> bool;
114
115 /// Approximates the amount of items in the tree.
116 fn approximate_len(&self) -> usize;
117
118 /// Returns the disk space usage.
119 fn disk_space(&self) -> u64;
120
121 /// Returns the highest sequence number of the active memtable.
122 fn get_highest_memtable_seqno(&self) -> Option<SeqNo>;
123
124 /// Returns the highest sequence number that is flushed to disk.
125 fn get_highest_persisted_seqno(&self) -> Option<SeqNo>;
126
127 /// Scans the entire tree, returning the amount of items.
128 ///
129 /// ###### Caution
130 ///
131 /// This operation scans the entire tree: O(n) complexity!
132 ///
133 /// Never, under any circumstances, use .`len()` == 0 to check
134 /// if the tree is empty, use [`Tree::is_empty`] instead.
135 ///
136 /// # Examples
137 ///
138 /// ```
139 /// # use lsm_tree::Error as TreeError;
140 /// use lsm_tree::{AbstractTree, Config, Tree};
141 ///
142 /// let folder = tempfile::tempdir()?;
143 /// let tree = Config::new(folder).open()?;
144 ///
145 /// assert_eq!(tree.len(None, None)?, 0);
146 /// tree.insert("1", "abc", 0);
147 /// tree.insert("3", "abc", 1);
148 /// tree.insert("5", "abc", 2);
149 /// assert_eq!(tree.len(None, None)?, 3);
150 /// #
151 /// # Ok::<(), TreeError>(())
152 /// ```
153 ///
154 /// # Errors
155 ///
156 /// Will return `Err` if an IO error occurs.
157 fn len(&self, seqno: Option<SeqNo>, index: Option<Arc<Memtable>>) -> crate::Result<usize> {
158 let mut count = 0;
159
160 for item in self.iter(seqno, index) {
161 let _ = item?;
162 count += 1;
163 }
164
165 Ok(count)
166 }
167
168 /// Returns `true` if the tree is empty.
169 ///
170 /// This operation has O(1) complexity.
171 ///
172 /// # Examples
173 ///
174 /// ```
175 /// # let folder = tempfile::tempdir()?;
176 /// use lsm_tree::{AbstractTree, Config, Tree};
177 ///
178 /// let tree = Config::new(folder).open()?;
179 /// assert!(tree.is_empty(None, None)?);
180 ///
181 /// tree.insert("a", "abc", 0);
182 /// assert!(!tree.is_empty(None, None)?);
183 /// #
184 /// # Ok::<(), lsm_tree::Error>(())
185 /// ```
186 ///
187 /// # Errors
188 ///
189 /// Will return `Err` if an IO error occurs.
190 fn is_empty(&self, seqno: Option<SeqNo>, index: Option<Arc<Memtable>>) -> crate::Result<bool> {
191 self.first_key_value(seqno, index).map(|x| x.is_none())
192 }
193
194 /// Returns the first key-value pair in the tree.
195 /// The key in this pair is the minimum key in the tree.
196 ///
197 /// # Examples
198 ///
199 /// ```
200 /// # use lsm_tree::Error as TreeError;
201 /// # use lsm_tree::{AbstractTree, Config, Tree};
202 /// #
203 /// # let folder = tempfile::tempdir()?;
204 /// let tree = Config::new(folder).open()?;
205 ///
206 /// tree.insert("1", "abc", 0);
207 /// tree.insert("3", "abc", 1);
208 /// tree.insert("5", "abc", 2);
209 ///
210 /// let (key, _) = tree.first_key_value(None, None)?.expect("item should exist");
211 /// assert_eq!(&*key, "1".as_bytes());
212 /// #
213 /// # Ok::<(), TreeError>(())
214 /// ```
215 ///
216 /// # Errors
217 ///
218 /// Will return `Err` if an IO error occurs.
219 fn first_key_value(
220 &self,
221 seqno: Option<SeqNo>,
222 index: Option<Arc<Memtable>>,
223 ) -> crate::Result<Option<KvPair>> {
224 self.iter(seqno, index).next().transpose()
225 }
226
227 /// Returns the last key-value pair in the tree.
228 /// The key in this pair is the maximum key in the tree.
229 ///
230 /// # Examples
231 ///
232 /// ```
233 /// # use lsm_tree::Error as TreeError;
234 /// # use lsm_tree::{AbstractTree, Config, Tree};
235 /// #
236 /// # let folder = tempfile::tempdir()?;
237 /// # let tree = Config::new(folder).open()?;
238 /// #
239 /// tree.insert("1", "abc", 0);
240 /// tree.insert("3", "abc", 1);
241 /// tree.insert("5", "abc", 2);
242 ///
243 /// let (key, _) = tree.last_key_value(None, None)?.expect("item should exist");
244 /// assert_eq!(&*key, "5".as_bytes());
245 /// #
246 /// # Ok::<(), TreeError>(())
247 /// ```
248 ///
249 /// # Errors
250 ///
251 /// Will return `Err` if an IO error occurs.
252 fn last_key_value(
253 &self,
254 seqno: Option<SeqNo>,
255 index: Option<Arc<Memtable>>,
256 ) -> crate::Result<Option<KvPair>> {
257 self.iter(seqno, index).next_back().transpose()
258 }
259
260 /// Returns an iterator that scans through the entire tree.
261 ///
262 /// Avoid using this function, or limit it as otherwise it may scan a lot of items.
263 ///
264 /// # Examples
265 ///
266 /// ```
267 /// # let folder = tempfile::tempdir()?;
268 /// use lsm_tree::{AbstractTree, Config, Tree};
269 ///
270 /// let tree = Config::new(folder).open()?;
271 ///
272 /// tree.insert("a", "abc", 0);
273 /// tree.insert("f", "abc", 1);
274 /// tree.insert("g", "abc", 2);
275 /// assert_eq!(3, tree.iter(None, None).count());
276 /// #
277 /// # Ok::<(), lsm_tree::Error>(())
278 /// ```
279 fn iter(
280 &self,
281 seqno: Option<SeqNo>,
282 index: Option<Arc<Memtable>>,
283 ) -> Box<dyn DoubleEndedIterator<Item = crate::Result<KvPair>> + 'static> {
284 self.range::<&[u8], _>(.., seqno, index)
285 }
286
287 /// Returns an iterator that scans through the entire tree, returning keys only.
288 ///
289 /// Avoid using this function, or limit it as otherwise it may scan a lot of items.
290 ///
291 /// # Examples
292 ///
293 /// ```
294 /// # let folder = tempfile::tempdir()?;
295 /// use lsm_tree::{AbstractTree, Config, Tree};
296 ///
297 /// let tree = Config::new(folder).open()?;
298 ///
299 /// tree.insert("a", "abc", 0);
300 /// tree.insert("f", "abc", 1);
301 /// tree.insert("g", "abc", 2);
302 /// assert_eq!(3, tree.keys(None, None).count());
303 /// #
304 /// # Ok::<(), lsm_tree::Error>(())
305 /// ```
306 fn keys(
307 &self,
308 seqno: Option<SeqNo>,
309 index: Option<Arc<Memtable>>,
310 ) -> Box<dyn DoubleEndedIterator<Item = crate::Result<UserKey>> + 'static>;
311
312 /// Returns an iterator that scans through the entire tree, returning values only.
313 ///
314 /// Avoid using this function, or limit it as otherwise it may scan a lot of items.
315 ///
316 /// # Examples
317 ///
318 /// ```
319 /// # let folder = tempfile::tempdir()?;
320 /// use lsm_tree::{AbstractTree, Config, Tree};
321 ///
322 /// let tree = Config::new(folder).open()?;
323 ///
324 /// tree.insert("a", "abc", 0);
325 /// tree.insert("f", "abc", 1);
326 /// tree.insert("g", "abc", 2);
327 /// assert_eq!(3, tree.values(None, None).count());
328 /// #
329 /// # Ok::<(), lsm_tree::Error>(())
330 /// ```
331 fn values(
332 &self,
333 seqno: Option<SeqNo>,
334 index: Option<Arc<Memtable>>,
335 ) -> Box<dyn DoubleEndedIterator<Item = crate::Result<UserValue>> + 'static>;
336
337 /// Returns an iterator over a range of items.
338 ///
339 /// Avoid using full or unbounded ranges as they may scan a lot of items (unless limited).
340 ///
341 /// # Examples
342 ///
343 /// ```
344 /// # let folder = tempfile::tempdir()?;
345 /// use lsm_tree::{AbstractTree, Config, Tree};
346 ///
347 /// let tree = Config::new(folder).open()?;
348 ///
349 /// tree.insert("a", "abc", 0);
350 /// tree.insert("f", "abc", 1);
351 /// tree.insert("g", "abc", 2);
352 /// assert_eq!(2, tree.range("a"..="f", None, None).into_iter().count());
353 /// #
354 /// # Ok::<(), lsm_tree::Error>(())
355 /// ```
356 fn range<K: AsRef<[u8]>, R: RangeBounds<K>>(
357 &self,
358 range: R,
359 seqno: Option<SeqNo>,
360 index: Option<Arc<Memtable>>,
361 ) -> Box<dyn DoubleEndedIterator<Item = crate::Result<KvPair>> + 'static>;
362
363 /// Returns an iterator over a prefixed set of items.
364 ///
365 /// Avoid using an empty prefix as it may scan a lot of items (unless limited).
366 ///
367 /// # Examples
368 ///
369 /// ```
370 /// # let folder = tempfile::tempdir()?;
371 /// use lsm_tree::{AbstractTree, Config, Tree};
372 ///
373 /// let tree = Config::new(folder).open()?;
374 ///
375 /// tree.insert("a", "abc", 0);
376 /// tree.insert("ab", "abc", 1);
377 /// tree.insert("abc", "abc", 2);
378 /// assert_eq!(2, tree.prefix("ab", None, None).count());
379 /// #
380 /// # Ok::<(), lsm_tree::Error>(())
381 /// ```
382 fn prefix<K: AsRef<[u8]>>(
383 &self,
384 prefix: K,
385 seqno: Option<SeqNo>,
386 index: Option<Arc<Memtable>>,
387 ) -> Box<dyn DoubleEndedIterator<Item = crate::Result<KvPair>> + 'static>;
388
389 /// Returns the size of a value if it exists.
390 ///
391 /// # Examples
392 ///
393 /// ```
394 /// # let folder = tempfile::tempdir()?;
395 /// use lsm_tree::{AbstractTree, Config, Tree};
396 ///
397 /// let tree = Config::new(folder).open()?;
398 /// tree.insert("a", "my_value", 0);
399 ///
400 /// let size = tree.size_of("a", None)?.unwrap_or_default();
401 /// assert_eq!("my_value".len() as u32, size);
402 ///
403 /// let size = tree.size_of("b", None)?.unwrap_or_default();
404 /// assert_eq!(0, size);
405 /// #
406 /// # Ok::<(), lsm_tree::Error>(())
407 /// ```
408 ///
409 /// # Errors
410 ///
411 /// Will return `Err` if an IO error occurs.
412 fn size_of<K: AsRef<[u8]>>(&self, key: K, seqno: Option<SeqNo>) -> crate::Result<Option<u32>>;
413
414 /// Retrieves an item from the tree.
415 ///
416 /// # Examples
417 ///
418 /// ```
419 /// # let folder = tempfile::tempdir()?;
420 /// use lsm_tree::{AbstractTree, Config, Tree};
421 ///
422 /// let tree = Config::new(folder).open()?;
423 /// tree.insert("a", "my_value", 0);
424 ///
425 /// let item = tree.get("a", None)?;
426 /// assert_eq!(Some("my_value".as_bytes().into()), item);
427 /// #
428 /// # Ok::<(), lsm_tree::Error>(())
429 /// ```
430 ///
431 /// # Errors
432 ///
433 /// Will return `Err` if an IO error occurs.
434 fn get<K: AsRef<[u8]>>(&self, key: K, seqno: Option<SeqNo>)
435 -> crate::Result<Option<UserValue>>;
436
437 /// Opens a read-only point-in-time snapshot of the tree
438 ///
439 /// Dropping the snapshot will close the snapshot
440 ///
441 /// # Examples
442 ///
443 /// ```
444 /// # let folder = tempfile::tempdir()?;
445 /// use lsm_tree::{AbstractTree, Config, Tree};
446 ///
447 /// let tree = Config::new(folder).open()?;
448 ///
449 /// tree.insert("a", "abc", 0);
450 ///
451 /// let snapshot = tree.snapshot(1);
452 /// assert_eq!(snapshot.len()?, tree.len(None, None)?);
453 ///
454 /// tree.insert("b", "abc", 1);
455 ///
456 /// assert_eq!(2, tree.len(None, None)?);
457 /// assert_eq!(1, snapshot.len()?);
458 ///
459 /// assert!(snapshot.contains_key("a")?);
460 /// assert!(!snapshot.contains_key("b")?);
461 /// #
462 /// # Ok::<(), lsm_tree::Error>(())
463 /// ```
464 fn snapshot(&self, seqno: SeqNo) -> Snapshot;
465
466 /// Opens a snapshot of this partition with a given sequence number
467 #[must_use]
468 fn snapshot_at(&self, seqno: SeqNo) -> Snapshot {
469 self.snapshot(seqno)
470 }
471
472 /// Returns `true` if the tree contains the specified key.
473 ///
474 /// # Examples
475 ///
476 /// ```
477 /// # let folder = tempfile::tempdir()?;
478 /// # use lsm_tree::{AbstractTree, Config, Tree};
479 /// #
480 /// let tree = Config::new(folder).open()?;
481 /// assert!(!tree.contains_key("a", None)?);
482 ///
483 /// tree.insert("a", "abc", 0);
484 /// assert!(tree.contains_key("a", None)?);
485 /// #
486 /// # Ok::<(), lsm_tree::Error>(())
487 /// ```
488 ///
489 /// # Errors
490 ///
491 /// Will return `Err` if an IO error occurs.
492 fn contains_key<K: AsRef<[u8]>>(&self, key: K, seqno: Option<SeqNo>) -> crate::Result<bool> {
493 self.get(key, seqno).map(|x| x.is_some())
494 }
495
496 /// Inserts a key-value pair into the tree.
497 ///
498 /// If the key already exists, the item will be overwritten.
499 ///
500 /// Returns the added item's size and new size of the memtable.
501 ///
502 /// # Examples
503 ///
504 /// ```
505 /// # let folder = tempfile::tempdir()?;
506 /// use lsm_tree::{AbstractTree, Config, Tree};
507 ///
508 /// let tree = Config::new(folder).open()?;
509 /// tree.insert("a", "abc", 0);
510 /// #
511 /// # Ok::<(), lsm_tree::Error>(())
512 /// ```
513 ///
514 /// # Errors
515 ///
516 /// Will return `Err` if an IO error occurs.
517 fn insert<K: Into<UserKey>, V: Into<UserValue>>(
518 &self,
519 key: K,
520 value: V,
521 seqno: SeqNo,
522 ) -> (u32, u32);
523
524 /// Removes an item from the tree.
525 ///
526 /// Returns the added item's size and new size of the memtable.
527 ///
528 /// # Examples
529 ///
530 /// ```
531 /// # let folder = tempfile::tempdir()?;
532 /// # use lsm_tree::{AbstractTree, Config, Tree};
533 /// #
534 /// # let tree = Config::new(folder).open()?;
535 /// tree.insert("a", "abc", 0);
536 ///
537 /// let item = tree.get("a", None)?.expect("should have item");
538 /// assert_eq!("abc".as_bytes(), &*item);
539 ///
540 /// tree.remove("a", 1);
541 ///
542 /// let item = tree.get("a", None)?;
543 /// assert_eq!(None, item);
544 /// #
545 /// # Ok::<(), lsm_tree::Error>(())
546 /// ```
547 ///
548 /// # Errors
549 ///
550 /// Will return `Err` if an IO error occurs.
551 fn remove<K: Into<UserKey>>(&self, key: K, seqno: SeqNo) -> (u32, u32);
552
553 /// Removes an item from the tree.
554 ///
555 /// The tombstone marker of this delete operation will vanish when it
556 /// collides with its corresponding insertion.
557 /// This may cause older versions of the value to be resurrected, so it should
558 /// only be used and preferred in scenarios where a key is only ever written once.
559 ///
560 /// Returns the added item's size and new size of the memtable.
561 ///
562 /// # Examples
563 ///
564 /// ```
565 /// # let folder = tempfile::tempdir()?;
566 /// # use lsm_tree::{AbstractTree, Config, Tree};
567 /// #
568 /// # let tree = Config::new(folder).open()?;
569 /// tree.insert("a", "abc", 0);
570 ///
571 /// let item = tree.get("a", None)?.expect("should have item");
572 /// assert_eq!("abc".as_bytes(), &*item);
573 ///
574 /// tree.remove_weak("a", 1);
575 ///
576 /// let item = tree.get("a", None)?;
577 /// assert_eq!(None, item);
578 /// #
579 /// # Ok::<(), lsm_tree::Error>(())
580 /// ```
581 ///
582 /// # Errors
583 ///
584 /// Will return `Err` if an IO error occurs.
585 fn remove_weak<K: Into<UserKey>>(&self, key: K, seqno: SeqNo) -> (u32, u32);
586}