Skip to main content

lsm_tree/
abstract_tree.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    iter_guard::IterGuardImpl, table::Table, version::Version, vlog::BlobFile, AnyTree, BlobTree,
7    Config, Guard, InternalValue, KvPair, Memtable, SeqNo, TableId, Tree, UserKey, UserValue,
8};
9use std::{
10    ops::RangeBounds,
11    sync::{Arc, MutexGuard, RwLockWriteGuard},
12};
13
14pub type RangeItem = crate::Result<KvPair>;
15
16type FlushToTablesResult = (Vec<Table>, Option<Vec<BlobFile>>);
17
18/// Generic Tree API
19#[enum_dispatch::enum_dispatch]
20pub trait AbstractTree {
21    /// Debug method for tracing the MVCC history of a key.
22    #[doc(hidden)]
23    fn print_trace(&self, key: &[u8]) -> crate::Result<()>;
24
25    /// Returns the number of cached table file descriptors.
26    fn table_file_cache_size(&self) -> usize;
27
28    // TODO: remove
29    #[doc(hidden)]
30    fn version_memtable_size_sum(&self) -> u64 {
31        self.get_version_history_lock().memtable_size_sum()
32    }
33
34    #[doc(hidden)]
35    fn next_table_id(&self) -> TableId;
36
37    #[doc(hidden)]
38    fn id(&self) -> crate::TreeId;
39
40    /// Like [`AbstractTree::get`], but returns the actual internal entry, not just the user value.
41    ///
42    /// Used in tests.
43    #[doc(hidden)]
44    fn get_internal_entry(&self, key: &[u8], seqno: SeqNo) -> crate::Result<Option<InternalValue>>;
45
46    #[doc(hidden)]
47    fn current_version(&self) -> Version;
48
49    #[doc(hidden)]
50    fn get_version_history_lock(&self) -> RwLockWriteGuard<'_, crate::version::SuperVersions>;
51
52    /// Seals the active memtable and flushes to table(s).
53    ///
54    /// If there are already other sealed memtables lined up, those will be flushed as well.
55    ///
56    /// Only used in tests.
57    #[doc(hidden)]
58    fn flush_active_memtable(&self, eviction_seqno: SeqNo) -> crate::Result<()> {
59        let lock = self.get_flush_lock();
60        self.rotate_memtable();
61        self.flush(&lock, eviction_seqno)?;
62        Ok(())
63    }
64
65    /// Synchronously flushes pending sealed memtables to tables.
66    ///
67    /// Returns the sum of flushed memtable sizes that were flushed.
68    ///
69    /// The function may not return a result, if nothing was flushed.
70    ///
71    /// # Errors
72    ///
73    /// Will return `Err` if an IO error occurs.
74    fn flush(
75        &self,
76        _lock: &MutexGuard<'_, ()>,
77        seqno_threshold: SeqNo,
78    ) -> crate::Result<Option<u64>> {
79        use crate::{compaction::stream::CompactionStream, merge::Merger};
80
81        let version_history = self.get_version_history_lock();
82        let latest = version_history.latest_version();
83
84        if latest.sealed_memtables.len() == 0 {
85            return Ok(None);
86        }
87
88        let sealed_ids = latest
89            .sealed_memtables
90            .iter()
91            .map(|mt| mt.id)
92            .collect::<Vec<_>>();
93
94        log::debug!("Flushing sealed memtables {sealed_ids:?} to table(s)");
95
96        let flushed_size = latest.sealed_memtables.iter().map(|mt| mt.size()).sum();
97
98        let merger = Merger::new(
99            latest
100                .sealed_memtables
101                .iter()
102                .map(|mt| mt.iter().map(Ok))
103                .collect::<Vec<_>>(),
104        );
105        let stream = CompactionStream::new(merger, seqno_threshold);
106
107        drop(version_history);
108
109        if let Some((tables, blob_files)) = self.flush_to_tables(stream)? {
110            self.register_tables(
111                &tables,
112                blob_files.as_deref(),
113                None,
114                &sealed_ids,
115                seqno_threshold,
116            )?;
117        }
118
119        Ok(Some(flushed_size))
120    }
121
122    /// Returns an iterator that scans through the entire tree.
123    ///
124    /// Avoid using this function, or limit it as otherwise it may scan a lot of items.
125    fn iter(
126        &self,
127        seqno: SeqNo,
128        index: Option<(Arc<Memtable>, SeqNo)>,
129    ) -> Box<dyn DoubleEndedIterator<Item = IterGuardImpl> + Send + 'static> {
130        self.range::<&[u8], _>(.., seqno, index)
131    }
132
133    /// Returns an iterator over a prefixed set of items.
134    ///
135    /// Avoid using an empty prefix as it may scan a lot of items (unless limited).
136    fn prefix<K: AsRef<[u8]>>(
137        &self,
138        prefix: K,
139        seqno: SeqNo,
140        index: Option<(Arc<Memtable>, SeqNo)>,
141    ) -> Box<dyn DoubleEndedIterator<Item = IterGuardImpl> + Send + 'static>;
142
143    /// Returns an iterator over a range of items.
144    ///
145    /// Avoid using full or unbounded ranges as they may scan a lot of items (unless limited).
146    fn range<K: AsRef<[u8]>, R: RangeBounds<K>>(
147        &self,
148        range: R,
149        seqno: SeqNo,
150        index: Option<(Arc<Memtable>, SeqNo)>,
151    ) -> Box<dyn DoubleEndedIterator<Item = IterGuardImpl> + Send + 'static>;
152
153    /// Returns the approximate number of tombstones in the tree.
154    fn tombstone_count(&self) -> u64;
155
156    /// Returns the approximate number of weak tombstones (single deletes) in the tree.
157    fn weak_tombstone_count(&self) -> u64;
158
159    /// Returns the approximate number of values reclaimable once weak tombstones can be GC'd.
160    fn weak_tombstone_reclaimable_count(&self) -> u64;
161
162    /// Drops tables that are fully contained in a given range.
163    ///
164    /// Accepts any `RangeBounds`, including unbounded or exclusive endpoints.
165    /// If the normalized lower bound is greater than the upper bound, the
166    /// method returns without performing any work.
167    ///
168    /// # Errors
169    ///
170    /// Will return `Err` only if an IO error occurs.
171    fn drop_range<K: AsRef<[u8]>, R: RangeBounds<K>>(&self, range: R) -> crate::Result<()>;
172
173    /// Drops all tables and clears all memtables atomically.
174    ///
175    /// # Errors
176    ///
177    /// Will return `Err` only if an IO error occurs.
178    fn clear(&self) -> crate::Result<()>;
179
180    /// Performs major compaction, blocking the caller until it's done.
181    ///
182    /// # Errors
183    ///
184    /// Will return `Err` if an IO error occurs.
185    fn major_compact(&self, target_size: u64, seqno_threshold: SeqNo) -> crate::Result<()>;
186
187    /// Returns the disk space used by stale blobs.
188    fn stale_blob_bytes(&self) -> u64 {
189        0
190    }
191
192    /// Gets the disk space usage of all filters in the tree.
193    ///
194    /// May not correspond to the actual memory size because filter blocks may be paged out.
195    fn filter_size(&self) -> u64;
196
197    /// Gets the memory usage of all pinned filters in the tree.
198    fn pinned_filter_size(&self) -> usize;
199
200    /// Gets the memory usage of all pinned index blocks in the tree.
201    fn pinned_block_index_size(&self) -> usize;
202
203    /// Gets the length of the version free list.
204    fn version_free_list_len(&self) -> usize;
205
206    /// Returns the metrics structure.
207    #[cfg(feature = "metrics")]
208    fn metrics(&self) -> &Arc<crate::Metrics>;
209
210    /// Acquires the flush lock which is required to call [`Tree::flush`].
211    fn get_flush_lock(&self) -> MutexGuard<'_, ()>;
212
213    /// Synchronously flushes a memtable to a table.
214    ///
215    /// This method will not make the table immediately available,
216    /// use [`AbstractTree::register_tables`] for that.
217    ///
218    /// # Errors
219    ///
220    /// Will return `Err` if an IO error occurs.
221    #[warn(clippy::type_complexity)]
222    fn flush_to_tables(
223        &self,
224        stream: impl Iterator<Item = crate::Result<InternalValue>>,
225    ) -> crate::Result<Option<FlushToTablesResult>>;
226
227    /// Atomically registers flushed tables into the tree, removing their associated sealed memtables.
228    ///
229    /// # Errors
230    ///
231    /// Will return `Err` if an IO error occurs.
232    fn register_tables(
233        &self,
234        tables: &[Table],
235        blob_files: Option<&[BlobFile]>,
236        frag_map: Option<crate::blob_tree::FragmentationMap>,
237        sealed_memtables_to_delete: &[crate::tree::inner::MemtableId],
238        gc_watermark: SeqNo,
239    ) -> crate::Result<()>;
240
241    /// Clears the active memtable atomically.
242    fn clear_active_memtable(&self);
243
244    /// Returns the number of sealed memtables.
245    fn sealed_memtable_count(&self) -> usize;
246
247    /// Performs compaction on the tree's levels, blocking the caller until it's done.
248    ///
249    /// # Errors
250    ///
251    /// Will return `Err` if an IO error occurs.
252    fn compact(
253        &self,
254        strategy: Arc<dyn crate::compaction::CompactionStrategy>,
255        seqno_threshold: SeqNo,
256    ) -> crate::Result<()>;
257
258    /// Returns the next table's ID.
259    fn get_next_table_id(&self) -> TableId;
260
261    /// Returns the tree config.
262    fn tree_config(&self) -> &Config;
263
264    /// Returns the highest sequence number.
265    fn get_highest_seqno(&self) -> Option<SeqNo> {
266        let memtable_seqno = self.get_highest_memtable_seqno();
267        let table_seqno = self.get_highest_persisted_seqno();
268        memtable_seqno.max(table_seqno)
269    }
270
271    /// Returns the active memtable.
272    fn active_memtable(&self) -> Arc<Memtable>;
273
274    /// Returns the tree type.
275    fn tree_type(&self) -> crate::TreeType {
276        // NOTE: This is only really safe to do, because we validate
277        // that the config's kv_separation_opts is consistent with the tree type during recovery.
278        if self.tree_config().kv_separation_opts.is_some() {
279            crate::TreeType::Blob
280        } else {
281            crate::TreeType::Standard
282        }
283    }
284
285    /// Seals the active memtable.
286    fn rotate_memtable(&self) -> Option<Arc<Memtable>>;
287
288    /// Returns the number of tables currently in the tree.
289    fn table_count(&self) -> usize;
290
291    /// Returns the number of tables in `levels[idx]`.
292    ///
293    /// Returns `None` if the level does not exist (if idx >= 7).
294    fn level_table_count(&self, idx: usize) -> Option<usize>;
295
296    /// Returns the number of disjoint runs in L0.
297    ///
298    /// Can be used to determine whether to write stall.
299    fn l0_run_count(&self) -> usize;
300
301    /// Returns the number of blob files currently in the tree.
302    fn blob_file_count(&self) -> usize;
303
304    /// Approximates the number of items in the tree.
305    fn approximate_len(&self) -> usize;
306
307    /// Returns the disk space usage.
308    fn disk_space(&self) -> u64;
309
310    /// Returns the highest sequence number of the active memtable.
311    fn get_highest_memtable_seqno(&self) -> Option<SeqNo>;
312
313    /// Returns the highest sequence number that is flushed to disk.
314    fn get_highest_persisted_seqno(&self) -> Option<SeqNo>;
315
316    /// Scans the entire tree, returning the number of items.
317    ///
318    /// ###### Caution
319    ///
320    /// This operation scans the entire tree: O(n) complexity!
321    ///
322    /// Never, under any circumstances, use .`len()` == 0 to check
323    /// if the tree is empty, use [`Tree::is_empty`] instead.
324    ///
325    /// # Examples
326    ///
327    /// ```
328    /// # use lsm_tree::Error as TreeError;
329    /// use lsm_tree::{AbstractTree, Config, Tree};
330    ///
331    /// let folder = tempfile::tempdir()?;
332    /// let tree = Config::new(folder, Default::default(), Default::default()).open()?;
333    ///
334    /// assert_eq!(tree.len(0, None)?, 0);
335    /// tree.insert("1", "abc", 0);
336    /// tree.insert("3", "abc", 1);
337    /// tree.insert("5", "abc", 2);
338    /// assert_eq!(tree.len(3, None)?, 3);
339    /// #
340    /// # Ok::<(), TreeError>(())
341    /// ```
342    ///
343    /// # Errors
344    ///
345    /// Will return `Err` if an IO error occurs.
346    fn len(&self, seqno: SeqNo, index: Option<(Arc<Memtable>, SeqNo)>) -> crate::Result<usize> {
347        let mut count = 0;
348
349        for item in self.iter(seqno, index) {
350            let _ = item.key()?;
351            count += 1;
352        }
353
354        Ok(count)
355    }
356
357    /// Returns `true` if the tree is empty.
358    ///
359    /// This operation has O(log N) complexity.
360    ///
361    /// # Examples
362    ///
363    /// ```
364    /// # let folder = tempfile::tempdir()?;
365    /// use lsm_tree::{AbstractTree, Config, Tree};
366    ///
367    /// let tree = Config::new(folder, Default::default(), Default::default()).open()?;
368    /// assert!(tree.is_empty(0, None)?);
369    ///
370    /// tree.insert("a", "abc", 0);
371    /// assert!(!tree.is_empty(1, None)?);
372    /// #
373    /// # Ok::<(), lsm_tree::Error>(())
374    /// ```
375    ///
376    /// # Errors
377    ///
378    /// Will return `Err` if an IO error occurs.
379    fn is_empty(&self, seqno: SeqNo, index: Option<(Arc<Memtable>, SeqNo)>) -> crate::Result<bool> {
380        Ok(self
381            .first_key_value(seqno, index)
382            .map(crate::Guard::key)
383            .transpose()?
384            .is_none())
385    }
386
387    /// Returns the first key-value pair in the tree.
388    /// The key in this pair is the minimum key in the tree.
389    ///
390    /// # Examples
391    ///
392    /// ```
393    /// # use lsm_tree::Error as TreeError;
394    /// # use lsm_tree::{AbstractTree, Config, Tree, Guard};
395    /// #
396    /// # let folder = tempfile::tempdir()?;
397    /// let tree = Config::new(folder, Default::default(), Default::default()).open()?;
398    ///
399    /// tree.insert("1", "abc", 0);
400    /// tree.insert("3", "abc", 1);
401    /// tree.insert("5", "abc", 2);
402    ///
403    /// let key = tree.first_key_value(3, None).expect("item should exist").key()?;
404    /// assert_eq!(&*key, "1".as_bytes());
405    /// #
406    /// # Ok::<(), TreeError>(())
407    /// ```
408    ///
409    /// # Errors
410    ///
411    /// Will return `Err` if an IO error occurs.
412    fn first_key_value(
413        &self,
414        seqno: SeqNo,
415        index: Option<(Arc<Memtable>, SeqNo)>,
416    ) -> Option<IterGuardImpl> {
417        self.iter(seqno, index).next()
418    }
419
420    /// Returns the last key-value pair in the tree.
421    /// The key in this pair is the maximum key in the tree.
422    ///
423    /// # Examples
424    ///
425    /// ```
426    /// # use lsm_tree::Error as TreeError;
427    /// # use lsm_tree::{AbstractTree, Config, Tree, Guard};
428    /// #
429    /// # let folder = tempfile::tempdir()?;
430    /// # let tree = Config::new(folder, Default::default(), Default::default()).open()?;
431    /// #
432    /// tree.insert("1", "abc", 0);
433    /// tree.insert("3", "abc", 1);
434    /// tree.insert("5", "abc", 2);
435    ///
436    /// let key = tree.last_key_value(3, None).expect("item should exist").key()?;
437    /// assert_eq!(&*key, "5".as_bytes());
438    /// #
439    /// # Ok::<(), TreeError>(())
440    /// ```
441    ///
442    /// # Errors
443    ///
444    /// Will return `Err` if an IO error occurs.
445    fn last_key_value(
446        &self,
447        seqno: SeqNo,
448        index: Option<(Arc<Memtable>, SeqNo)>,
449    ) -> Option<IterGuardImpl> {
450        self.iter(seqno, index).next_back()
451    }
452
453    /// Returns the size of a value if it exists.
454    ///
455    /// # Examples
456    ///
457    /// ```
458    /// # let folder = tempfile::tempdir()?;
459    /// use lsm_tree::{AbstractTree, Config, Tree};
460    ///
461    /// let tree = Config::new(folder, Default::default(), Default::default()).open()?;
462    /// tree.insert("a", "my_value", 0);
463    ///
464    /// let size = tree.size_of("a", 1)?.unwrap_or_default();
465    /// assert_eq!("my_value".len() as u32, size);
466    ///
467    /// let size = tree.size_of("b", 1)?.unwrap_or_default();
468    /// assert_eq!(0, size);
469    /// #
470    /// # Ok::<(), lsm_tree::Error>(())
471    /// ```
472    ///
473    /// # Errors
474    ///
475    /// Will return `Err` if an IO error occurs.
476    fn size_of<K: AsRef<[u8]>>(&self, key: K, seqno: SeqNo) -> crate::Result<Option<u32>>;
477
478    /// Retrieves an item from the tree.
479    ///
480    /// # Examples
481    ///
482    /// ```
483    /// # let folder = tempfile::tempdir()?;
484    /// use lsm_tree::{AbstractTree, Config, Tree};
485    ///
486    /// let tree = Config::new(folder, Default::default(), Default::default()).open()?;
487    /// tree.insert("a", "my_value", 0);
488    ///
489    /// let item = tree.get("a", 1)?;
490    /// assert_eq!(Some("my_value".as_bytes().into()), item);
491    /// #
492    /// # Ok::<(), lsm_tree::Error>(())
493    /// ```
494    ///
495    /// # Errors
496    ///
497    /// Will return `Err` if an IO error occurs.
498    fn get<K: AsRef<[u8]>>(&self, key: K, seqno: SeqNo) -> crate::Result<Option<UserValue>>;
499
500    /// Returns `true` if the tree contains the specified key.
501    ///
502    /// # Examples
503    ///
504    /// ```
505    /// # let folder = tempfile::tempdir()?;
506    /// # use lsm_tree::{AbstractTree, Config, Tree};
507    /// #
508    /// let tree = Config::new(folder, Default::default(), Default::default()).open()?;
509    /// assert!(!tree.contains_key("a", 0)?);
510    ///
511    /// tree.insert("a", "abc", 0);
512    /// assert!(tree.contains_key("a", 1)?);
513    /// #
514    /// # Ok::<(), lsm_tree::Error>(())
515    /// ```
516    ///
517    /// # Errors
518    ///
519    /// Will return `Err` if an IO error occurs.
520    fn contains_key<K: AsRef<[u8]>>(&self, key: K, seqno: SeqNo) -> crate::Result<bool> {
521        self.get(key, seqno).map(|x| x.is_some())
522    }
523
524    /// Inserts a key-value pair into the tree.
525    ///
526    /// If the key already exists, the item will be overwritten.
527    ///
528    /// Returns the added item's size and new size of the memtable.
529    ///
530    /// # Examples
531    ///
532    /// ```
533    /// # let folder = tempfile::tempdir()?;
534    /// use lsm_tree::{AbstractTree, Config, Tree};
535    ///
536    /// let tree = Config::new(folder, Default::default(), Default::default()).open()?;
537    /// tree.insert("a", "abc", 0);
538    /// #
539    /// # Ok::<(), lsm_tree::Error>(())
540    /// ```
541    ///
542    /// # Errors
543    ///
544    /// Will return `Err` if an IO error occurs.
545    fn insert<K: Into<UserKey>, V: Into<UserValue>>(
546        &self,
547        key: K,
548        value: V,
549        seqno: SeqNo,
550    ) -> (u64, u64);
551
552    /// Removes an item from the tree.
553    ///
554    /// Returns the added item's size and new size of the memtable.
555    ///
556    /// # Examples
557    ///
558    /// ```
559    /// # let folder = tempfile::tempdir()?;
560    /// # use lsm_tree::{AbstractTree, Config, Tree};
561    /// #
562    /// # let tree = Config::new(folder, Default::default(), Default::default()).open()?;
563    /// tree.insert("a", "abc", 0);
564    ///
565    /// let item = tree.get("a", 1)?.expect("should have item");
566    /// assert_eq!("abc".as_bytes(), &*item);
567    ///
568    /// tree.remove("a", 1);
569    ///
570    /// let item = tree.get("a", 2)?;
571    /// assert_eq!(None, item);
572    /// #
573    /// # Ok::<(), lsm_tree::Error>(())
574    /// ```
575    ///
576    /// # Errors
577    ///
578    /// Will return `Err` if an IO error occurs.
579    fn remove<K: Into<UserKey>>(&self, key: K, seqno: SeqNo) -> (u64, u64);
580
581    /// Removes an item from the tree.
582    ///
583    /// The tombstone marker of this delete operation will vanish when it
584    /// collides with its corresponding insertion.
585    /// This may cause older versions of the value to be resurrected, so it should
586    /// only be used and preferred in scenarios where a key is only ever written once.
587    ///
588    /// Returns the added item's size and new size of the memtable.
589    ///
590    /// # Examples
591    ///
592    /// ```
593    /// # let folder = tempfile::tempdir()?;
594    /// # use lsm_tree::{AbstractTree, Config, Tree};
595    /// #
596    /// # let tree = Config::new(folder, Default::default(), Default::default()).open()?;
597    /// tree.insert("a", "abc", 0);
598    ///
599    /// let item = tree.get("a", 1)?.expect("should have item");
600    /// assert_eq!("abc".as_bytes(), &*item);
601    ///
602    /// tree.remove_weak("a", 1);
603    ///
604    /// let item = tree.get("a", 2)?;
605    /// assert_eq!(None, item);
606    /// #
607    /// # Ok::<(), lsm_tree::Error>(())
608    /// ```
609    ///
610    /// # Errors
611    ///
612    /// Will return `Err` if an IO error occurs.
613    #[doc(hidden)]
614    fn remove_weak<K: Into<UserKey>>(&self, key: K, seqno: SeqNo) -> (u64, u64);
615}