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}