index/inverted_index/create/
sort_create.rs1use std::collections::HashMap;
16use std::num::NonZeroUsize;
17
18use async_trait::async_trait;
19use snafu::ensure;
20
21use crate::BytesRef;
22use crate::bitmap::BitmapType;
23use crate::inverted_index::create::InvertedIndexCreator;
24use crate::inverted_index::create::sort::{SortOutput, Sorter};
25use crate::inverted_index::error::{InconsistentRowCountSnafu, Result};
26use crate::inverted_index::format::writer::InvertedIndexWriter;
27
28type IndexName = String;
29type SegmentRowCount = NonZeroUsize;
30
31pub type SorterFactory = Box<dyn Fn(IndexName, SegmentRowCount) -> Box<dyn Sorter> + Send>;
33
34pub struct SortIndexCreator {
37 sorter_factory: SorterFactory,
39
40 sorters: HashMap<IndexName, Box<dyn Sorter>>,
42
43 segment_row_count: NonZeroUsize,
45
46 pending_spills: Vec<IndexName>,
48}
49
50#[async_trait]
51impl InvertedIndexCreator for SortIndexCreator {
52 fn push_with_name_n(
57 &mut self,
58 index_name: &str,
59 value: Option<BytesRef<'_>>,
60 n: usize,
61 ) -> bool {
62 let sorter = match self.sorters.get_mut(index_name) {
63 Some(sorter) => sorter,
64 None => {
65 let sorter = (self.sorter_factory)(index_name.to_string(), self.segment_row_count);
66 self.sorters.entry(index_name.to_string()).or_insert(sorter)
67 }
68 };
69 if sorter.push_n(value, n) {
70 self.pending_spills.push(index_name.to_string());
71 return true;
72 }
73 false
74 }
75
76 async fn spill(&mut self) -> Result<()> {
77 for index_name in std::mem::take(&mut self.pending_spills) {
78 if let Some(sorter) = self.sorters.get_mut(&index_name) {
79 sorter.spill().await?;
80 }
81 }
82 Ok(())
83 }
84
85 async fn finish(
87 &mut self,
88 writer: &mut dyn InvertedIndexWriter,
89 bitmap_type: BitmapType,
90 ) -> Result<()> {
91 let mut output_row_count = None;
92 for (index_name, mut sorter) in self.sorters.drain() {
93 let SortOutput {
94 segment_null_bitmap,
95 sorted_stream,
96 total_row_count,
97 } = sorter.output().await?;
98
99 let expected_row_count = *output_row_count.get_or_insert(total_row_count);
100 ensure!(
101 expected_row_count == total_row_count,
102 InconsistentRowCountSnafu {
103 index_name,
104 total_row_count,
105 expected_row_count,
106 }
107 );
108
109 writer
110 .add_index(index_name, segment_null_bitmap, sorted_stream, bitmap_type)
111 .await?;
112 }
113
114 let total_row_count = output_row_count.unwrap_or_default() as _;
115 let segment_row_count = self.segment_row_count as _;
116 writer.finish(total_row_count, segment_row_count).await
117 }
118}
119
120impl SortIndexCreator {
121 pub fn new(sorter_factory: SorterFactory, segment_row_count: NonZeroUsize) -> Self {
123 Self {
124 sorter_factory,
125 sorters: HashMap::new(),
126 segment_row_count,
127 pending_spills: Vec::new(),
128 }
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use std::collections::BTreeMap;
135 use std::sync::{Arc, Mutex};
136
137 use common_base::BitVec;
138 use futures::{StreamExt, stream};
139
140 use super::*;
141 use crate::Bytes;
142 use crate::bitmap::Bitmap;
143 use crate::inverted_index::error::Error;
144 use crate::inverted_index::format::writer::{MockInvertedIndexWriter, ValueStream};
145
146 #[tokio::test]
147 async fn test_sort_index_creator_basic() {
148 let mut creator =
149 SortIndexCreator::new(NaiveSorter::factory(), NonZeroUsize::new(1).unwrap());
150
151 let index_values = vec![
152 ("a", vec![b"3", b"2", b"1"]),
153 ("b", vec![b"6", b"5", b"4"]),
154 ("c", vec![b"1", b"2", b"3"]),
155 ];
156
157 for (index_name, values) in index_values {
158 for value in values {
159 assert!(!creator.push_with_name(index_name, Some(value)));
160 }
161 }
162
163 let mut mock_writer = MockInvertedIndexWriter::new();
164 mock_writer.expect_add_index().times(3).returning(
165 |name, null_bitmap, stream, bitmap_type| {
166 assert!(null_bitmap.is_empty());
167 assert_eq!(bitmap_type, BitmapType::Roaring);
168 match name.as_str() {
169 "a" => assert_eq!(stream_to_values(stream), vec![b"1", b"2", b"3"]),
170 "b" => assert_eq!(stream_to_values(stream), vec![b"4", b"5", b"6"]),
171 "c" => assert_eq!(stream_to_values(stream), vec![b"1", b"2", b"3"]),
172 _ => panic!("unexpected index name: {}", name),
173 }
174 Ok(())
175 },
176 );
177 mock_writer
178 .expect_finish()
179 .times(1)
180 .returning(|total_row_count, segment_row_count| {
181 assert_eq!(total_row_count, 3);
182 assert_eq!(segment_row_count.get(), 1);
183 Ok(())
184 });
185
186 creator
187 .finish(&mut mock_writer, BitmapType::Roaring)
188 .await
189 .unwrap();
190 }
191
192 #[tokio::test]
193 async fn test_sort_index_creator_inconsistent_row_count() {
194 let mut creator =
195 SortIndexCreator::new(NaiveSorter::factory(), NonZeroUsize::new(1).unwrap());
196
197 let index_values = vec![
198 ("a", vec![b"3", b"2", b"1"]),
199 ("b", vec![b"6", b"5", b"4"]),
200 ("c", vec![b"1", b"2"]),
201 ];
202
203 for (index_name, values) in index_values {
204 for value in values {
205 assert!(!creator.push_with_name(index_name, Some(value)));
206 }
207 }
208
209 let mut mock_writer = MockInvertedIndexWriter::new();
210 mock_writer
211 .expect_add_index()
212 .returning(|name, null_bitmap, stream, bitmap_type| {
213 assert!(null_bitmap.is_empty());
214 assert_eq!(bitmap_type, BitmapType::Roaring);
215 match name.as_str() {
216 "a" => assert_eq!(stream_to_values(stream), vec![b"1", b"2", b"3"]),
217 "b" => assert_eq!(stream_to_values(stream), vec![b"4", b"5", b"6"]),
218 "c" => assert_eq!(stream_to_values(stream), vec![b"1", b"2"]),
219 _ => panic!("unexpected index name: {}", name),
220 }
221 Ok(())
222 });
223 mock_writer.expect_finish().never();
224
225 let res = creator.finish(&mut mock_writer, BitmapType::Roaring).await;
226 assert!(matches!(res, Err(Error::InconsistentRowCount { .. })));
227 }
228
229 #[tokio::test]
230 async fn test_sort_index_creator_create_indexes_without_data() {
231 let mut creator =
232 SortIndexCreator::new(NaiveSorter::factory(), NonZeroUsize::new(1).unwrap());
233
234 assert!(!creator.push_with_name_n("a", None, 0));
235 assert!(!creator.push_with_name_n("b", None, 0));
236 assert!(!creator.push_with_name_n("c", None, 0));
237
238 let mut mock_writer = MockInvertedIndexWriter::new();
239 mock_writer
240 .expect_add_index()
241 .returning(|name, null_bitmap, stream, bitmap_type| {
242 assert!(null_bitmap.is_empty());
243 assert_eq!(bitmap_type, BitmapType::Roaring);
244 assert!(matches!(name.as_str(), "a" | "b" | "c"));
245 assert!(stream_to_values(stream).is_empty());
246 Ok(())
247 });
248 mock_writer
249 .expect_finish()
250 .times(1)
251 .returning(|total_row_count, segment_row_count| {
252 assert_eq!(total_row_count, 0);
253 assert_eq!(segment_row_count.get(), 1);
254 Ok(())
255 });
256
257 creator
258 .finish(&mut mock_writer, BitmapType::Roaring)
259 .await
260 .unwrap();
261 }
262
263 #[tokio::test]
264 async fn test_sort_index_creator_spills_requested_sorters() {
265 let spilled = Arc::new(Mutex::new(Vec::new()));
266 let factory: SorterFactory = {
267 let spilled = spilled.clone();
268 Box::new(move |index_name, _| {
269 Box::new(SpillRecordingSorter {
270 index_name,
271 spilled: spilled.clone(),
272 })
273 })
274 };
275 let mut creator = SortIndexCreator::new(factory, NonZeroUsize::new(1).unwrap());
276
277 assert!(creator.push_with_name("a", Some(b"1")));
278 assert!(!creator.push_with_name("b", Some(b"1")));
279 creator.spill().await.unwrap();
280 assert_eq!(*spilled.lock().unwrap(), vec!["a"]);
281
282 creator.spill().await.unwrap();
283 assert_eq!(*spilled.lock().unwrap(), vec!["a"]);
284 }
285
286 struct SpillRecordingSorter {
288 index_name: String,
289 spilled: Arc<Mutex<Vec<String>>>,
290 }
291
292 #[async_trait]
293 impl Sorter for SpillRecordingSorter {
294 fn push_n(&mut self, _value: Option<BytesRef<'_>>, _n: usize) -> bool {
295 self.index_name == "a"
296 }
297
298 async fn spill(&mut self) -> Result<()> {
299 self.spilled.lock().unwrap().push(self.index_name.clone());
300 Ok(())
301 }
302
303 async fn output(&mut self) -> Result<SortOutput> {
304 unreachable!()
305 }
306 }
307
308 fn set_bit(bit_vec: &mut BitVec, index: usize) {
309 if index >= bit_vec.len() {
310 bit_vec.resize(index + 1, false);
311 }
312 bit_vec.set(index, true);
313 }
314
315 struct NaiveSorter {
316 total_row_count: usize,
317 segment_row_count: NonZeroUsize,
318 values: BTreeMap<Option<Bytes>, BitVec>,
319 }
320
321 impl NaiveSorter {
322 fn factory() -> SorterFactory {
323 Box::new(|_index_name, segment_row_count| {
324 Box::new(NaiveSorter {
325 total_row_count: 0,
326 segment_row_count,
327 values: BTreeMap::new(),
328 })
329 })
330 }
331 }
332
333 #[async_trait]
334 impl Sorter for NaiveSorter {
335 fn push_n(&mut self, value: Option<BytesRef<'_>>, n: usize) -> bool {
336 for _ in 0..n {
337 let segment_index = self.total_row_count / self.segment_row_count;
338 self.total_row_count += 1;
339
340 let bitmap = self.values.entry(value.map(Into::into)).or_default();
341 set_bit(bitmap, segment_index);
342 }
343 false
344 }
345
346 async fn spill(&mut self) -> Result<()> {
347 Ok(())
348 }
349
350 async fn output(&mut self) -> Result<SortOutput> {
351 let segment_null_bitmap = self.values.remove(&None).unwrap_or_default();
352 let segment_null_bitmap = Bitmap::BitVec(segment_null_bitmap);
353
354 Ok(SortOutput {
355 segment_null_bitmap,
356 sorted_stream: Box::new(stream::iter(
357 std::mem::take(&mut self.values)
358 .into_iter()
359 .map(|(v, b)| Ok((v.unwrap(), Bitmap::BitVec(b)))),
360 )),
361 total_row_count: self.total_row_count,
362 })
363 }
364 }
365
366 fn stream_to_values(stream: ValueStream) -> Vec<Bytes> {
367 futures::executor::block_on(async {
368 stream.map(|r| r.unwrap().0).collect::<Vec<Bytes>>().await
369 })
370 }
371}