turbo_persistence/
sst_filter.rs1use std::collections::hash_map::Entry;
2
3use rustc_hash::{FxHashMap, FxHashSet};
4
5use crate::meta_file::MetaFile;
6
7enum SstState {
8 Active,
9 UnusedObsolete,
10 Obsolete,
11}
12
13pub struct SstFilter(FxHashMap<u32, SstState>);
14
15impl SstFilter {
16 pub fn new() -> Self {
17 Self(FxHashMap::default())
18 }
19
20 pub fn apply_filter(&mut self, meta: &mut MetaFile) {
22 for seq in meta.obsolete_entries() {
24 if let Some(state) = self.0.get_mut(seq)
25 && matches!(state, SstState::UnusedObsolete)
26 {
27 *state = SstState::Obsolete;
29 }
30 }
31 meta.retain_entries(|seq| match self.0.entry(seq) {
32 Entry::Occupied(mut e) => {
33 let state = e.get_mut();
34 if matches!(state, SstState::UnusedObsolete) {
35 *state = SstState::Obsolete;
37 }
38 false
39 }
40 Entry::Vacant(e) => {
41 e.insert(SstState::Active);
42 true
43 }
44 });
45 for seq in meta.obsolete_sst_files() {
46 self.0.entry(*seq).or_insert(SstState::UnusedObsolete);
47 }
48 }
49
50 pub fn apply_filter_collect(&mut self, meta: &MetaFile) -> FxHashSet<u32> {
55 let mut to_remove = FxHashSet::default();
56 for seq in meta.obsolete_entries() {
58 if let Some(state) = self.0.get_mut(seq)
59 && matches!(state, SstState::UnusedObsolete)
60 {
61 *state = SstState::Obsolete;
63 }
64 }
65 for entry in meta.entries() {
66 let seq = entry.sequence_number();
67 match self.0.entry(seq) {
68 Entry::Occupied(mut e) => {
69 let state = e.get_mut();
70 if matches!(state, SstState::UnusedObsolete) {
71 *state = SstState::Obsolete;
72 }
73 to_remove.insert(seq);
74 }
75 Entry::Vacant(e) => {
76 e.insert(SstState::Active);
77 }
78 }
79 }
80 for seq in meta.obsolete_sst_files() {
81 self.0.entry(*seq).or_insert(SstState::UnusedObsolete);
82 }
83 to_remove
84 }
85
86 pub fn apply_and_get_remove(&mut self, meta: &MetaFile) -> bool {
90 self.apply_and_get_remove_after_removing(meta, &FxHashSet::default())
91 }
92
93 pub fn apply_and_get_remove_after_removing(
98 &mut self,
99 meta: &MetaFile,
100 entries_to_remove: &FxHashSet<u32>,
101 ) -> bool {
102 let mut used = false;
103 for seq in meta.obsolete_sst_files() {
104 if let Entry::Occupied(e) = self.0.entry(*seq) {
105 if matches!(e.get(), SstState::Obsolete) {
106 used = true;
108 }
109 e.remove();
112 }
113 }
114
115 !used
116 && !meta
117 .entries()
118 .iter()
119 .any(|entry| !entries_to_remove.contains(&entry.sequence_number()))
120 }
121}
122
123impl Default for SstFilter {
124 fn default() -> Self {
125 Self::new()
126 }
127}