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}