lsm_tree/vlog/gc/
mod.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
5pub mod report;
6
7use crate::vlog::{BlobFileId, ValueLog};
8
9/// GC strategy
10#[allow(clippy::module_name_repetitions)]
11pub trait GcStrategy {
12    /// Picks blob files based on a predicate.
13    fn pick(&self, value_log: &ValueLog) -> Vec<BlobFileId>;
14}
15
16/// Picks blob files that have a certain percentage of stale blobs
17pub struct StaleThresholdStrategy(f32);
18
19impl StaleThresholdStrategy {
20    /// Creates a new strategy with the given threshold.
21    ///
22    /// # Panics
23    ///
24    /// Panics if the ratio is invalid.
25    #[must_use]
26    pub fn new(ratio: f32) -> Self {
27        assert!(
28            ratio.is_finite() && ratio.is_sign_positive(),
29            "invalid stale ratio"
30        );
31        Self(ratio.min(1.0))
32    }
33}
34
35impl GcStrategy for StaleThresholdStrategy {
36    fn pick(&self, value_log: &ValueLog) -> Vec<BlobFileId> {
37        unimplemented!()
38
39        // value_log
40        //     .manifest
41        //     .blob_files
42        //     .read()
43        //     .expect("lock is poisoned")
44        //     .values()
45        //     .filter(|x| x.stale_ratio() > self.0)
46        //     .map(|x| x.id)
47        //     .collect::<Vec<_>>()
48    }
49}
50
51/// Tries to find a least-effort-selection of blob files to merge to reach a certain space amplification
52pub struct SpaceAmpStrategy(f32);
53
54impl SpaceAmpStrategy {
55    /// Creates a new strategy with the given space amp factor.
56    ///
57    /// # Panics
58    ///
59    /// Panics if the space amp factor is < 1.0.
60    #[must_use]
61    pub fn new(ratio: f32) -> Self {
62        assert!(ratio >= 1.0, "invalid space amp ratio");
63        Self(ratio)
64    }
65}
66
67impl GcStrategy for SpaceAmpStrategy {
68    #[allow(clippy::cast_precision_loss, clippy::significant_drop_tightening)]
69    fn pick(&self, value_log: &ValueLog) -> Vec<BlobFileId> {
70        unimplemented!()
71
72        // let space_amp_target = self.0;
73        // let current_space_amp = value_log.space_amp();
74
75        // if current_space_amp < space_amp_target {
76        //     log::trace!("Space amp is <= target {space_amp_target}, nothing to do");
77        //     vec![]
78        // } else {
79        //     log::debug!("Selecting blob files to GC, space_amp_target={space_amp_target}");
80
81        //     let lock = value_log
82        //         .manifest
83        //         .blob_files
84        //         .read()
85        //         .expect("lock is poisoned");
86
87        //     let mut blob_files = lock
88        //         .values()
89        //         .filter(|x| x.stale_ratio() > 0.0)
90        //         .collect::<Vec<_>>();
91
92        //     // Sort by stale ratio descending
93        //     blob_files.sort_by(|a, b| {
94        //         b.stale_ratio()
95        //             .partial_cmp(&a.stale_ratio())
96        //             .unwrap_or(std::cmp::Ordering::Equal)
97        //     });
98
99        //     let mut selection = vec![];
100
101        //     let mut total_bytes = value_log.manifest.total_bytes();
102        //     let mut stale_bytes = value_log.manifest.stale_bytes();
103
104        //     for blob_file in blob_files {
105        //         let blob_file_stale_bytes = blob_file.gc_stats.stale_bytes();
106        //         stale_bytes -= blob_file_stale_bytes;
107        //         total_bytes -= blob_file_stale_bytes;
108
109        //         selection.push(blob_file.id);
110
111        //         let space_amp_after_gc =
112        //             total_bytes as f32 / (total_bytes as f32 - stale_bytes as f32);
113
114        //         log::debug!(
115        //             "Selected blob file #{} for GC: will reduce space amp to {space_amp_after_gc}",
116        //             blob_file.id,
117        //         );
118
119        //         if space_amp_after_gc <= space_amp_target {
120        //             break;
121        //         }
122        //     }
123
124        //     selection
125        // }
126    }
127}