risingwave_meta/hummock/compaction/
overlap_strategy.rs1use std::cmp;
16use std::fmt::Debug;
17use std::ops::Range;
18
19use itertools::Itertools;
20use risingwave_hummock_sdk::KeyComparator;
21use risingwave_hummock_sdk::key_range::{KeyRange, KeyRangeCommon};
22use risingwave_hummock_sdk::sstable_info::SstableInfo;
23
24pub trait OverlapInfo: Debug {
25 fn check_overlap(&self, a: &SstableInfo) -> bool;
26 fn check_multiple_overlap(&self, others: &[SstableInfo]) -> Range<usize>;
27 fn check_multiple_include(&self, others: &[SstableInfo]) -> Range<usize>;
28 fn update(&mut self, range: &KeyRange);
29}
30
31pub trait OverlapStrategy: Send + Sync {
32 fn check_overlap(&self, a: &SstableInfo, b: &SstableInfo) -> bool;
33 fn check_base_level_overlap(
34 &self,
35 tables: &[SstableInfo],
36 others: &[SstableInfo],
37 ) -> Vec<SstableInfo> {
38 let mut info = self.create_overlap_info();
39 for table in tables {
40 info.update(&table.key_range);
41 }
42 let range = info.check_multiple_overlap(others);
43 if range.is_empty() {
44 vec![]
45 } else {
46 others[range].to_vec()
47 }
48 }
49 fn check_overlap_with_range(
50 &self,
51 range: &KeyRange,
52 others: &[SstableInfo],
53 ) -> Vec<SstableInfo> {
54 if others.is_empty() {
55 return vec![];
56 }
57 let mut info = self.create_overlap_info();
58 info.update(range);
59 others
60 .iter()
61 .filter(|table| info.check_overlap(table))
62 .cloned()
63 .collect_vec()
64 }
65
66 fn check_overlap_range_with_hint(
70 &self,
71 range: &KeyRange,
72 others: &[SstableInfo],
73 _previous: Option<Range<usize>>,
74 ) -> Range<usize> {
75 let mut info = self.create_overlap_info();
76 info.update(range);
77 info.check_multiple_overlap(others)
78 }
79
80 fn create_overlap_info(&self) -> Box<dyn OverlapInfo>;
81}
82
83#[derive(Default, Debug)]
84pub struct RangeOverlapInfo {
85 target_range: Option<KeyRange>,
86}
87
88impl OverlapInfo for RangeOverlapInfo {
89 fn check_overlap(&self, a: &SstableInfo) -> bool {
90 match self.target_range.as_ref() {
91 Some(range) => check_table_overlap(range, a),
92 None => false,
93 }
94 }
95
96 fn check_multiple_overlap(&self, others: &[SstableInfo]) -> Range<usize> {
97 match self.target_range.as_ref() {
98 Some(key_range) => {
99 let overlap_begin = others.partition_point(|table_status| {
100 table_status.key_range.compare_right_with(&key_range.left)
101 == cmp::Ordering::Less
102 });
103 if overlap_begin >= others.len() {
104 return overlap_begin..overlap_begin;
105 }
106 let overlap_end = others.partition_point(|table_status| {
107 key_range.compare_right_with(&table_status.key_range.left)
108 != cmp::Ordering::Less
109 });
110 overlap_begin..overlap_end
111 }
112 None => others.len()..others.len(),
113 }
114 }
115
116 fn check_multiple_include(&self, others: &[SstableInfo]) -> Range<usize> {
117 match self.target_range.as_ref() {
118 Some(key_range) => {
119 let overlap_begin = others.partition_point(|table_status| {
120 KeyComparator::compare_encoded_full_key(
121 &table_status.key_range.left,
122 &key_range.left,
123 ) == cmp::Ordering::Less
124 });
125 if overlap_begin >= others.len() {
126 return overlap_begin..overlap_begin;
127 }
128 let mut overlap_end = overlap_begin;
129 for table in &others[overlap_begin..] {
130 if key_range.compare_right_with(&table.key_range.right) == cmp::Ordering::Less {
131 break;
132 }
133 overlap_end += 1;
134 }
135 overlap_begin..overlap_end
136 }
137 None => others.len()..others.len(),
138 }
139 }
140
141 fn update(&mut self, range: &KeyRange) {
142 let other = range;
143 if let Some(range) = self.target_range.as_mut() {
144 range.full_key_extend(other);
145 return;
146 }
147 self.target_range = Some(other.clone());
148 }
149}
150
151#[derive(Default)]
152pub struct RangeOverlapStrategy {}
153
154impl OverlapStrategy for RangeOverlapStrategy {
155 fn check_overlap(&self, a: &SstableInfo, b: &SstableInfo) -> bool {
156 check_table_overlap(&a.key_range, b)
157 }
158
159 fn check_overlap_range_with_hint(
160 &self,
161 range: &KeyRange,
162 others: &[SstableInfo],
163 previous: Option<Range<usize>>,
164 ) -> Range<usize> {
165 let before = |table: &SstableInfo| {
166 table.key_range.compare_right_with(&range.left) == cmp::Ordering::Less
167 };
168 let overlaps = |table: &SstableInfo| {
169 range.compare_right_with(&table.key_range.left) != cmp::Ordering::Less
170 };
171 if let Some(previous) = previous {
172 let begin = previous.start + partition_point_forward(&others[previous.start..], before);
173 let end = previous.end.max(begin);
174 let end = end + partition_point_forward(&others[end..], overlaps);
175 begin..end
176 } else {
177 let begin = others.partition_point(before);
179 let end = begin + others[begin..].partition_point(overlaps);
180 begin..end
181 }
182 }
183
184 fn create_overlap_info(&self) -> Box<dyn OverlapInfo> {
185 Box::<RangeOverlapInfo>::default()
186 }
187}
188
189fn check_table_overlap(key_range: &KeyRange, table: &SstableInfo) -> bool {
190 key_range.sstable_overlap(&table.key_range)
191}
192
193fn partition_point_forward<T>(items: &[T], mut pred: impl FnMut(&T) -> bool) -> usize {
197 if items.is_empty() || !pred(&items[0]) {
198 return 0;
199 }
200 let mut lo = 1;
201 let mut hi = 2.min(items.len());
202 while hi < items.len() && pred(&items[hi - 1]) {
203 lo = hi;
204 hi = hi.saturating_mul(2).min(items.len());
205 }
206 lo + items[lo..hi].partition_point(pred)
207}