1use std::sync::Arc;
18
19use datatypes::arrow::array::{Array, BinaryArray};
20use datatypes::arrow::compute::concat_batches;
21use datatypes::arrow::record_batch::RecordBatch;
22use futures::{Stream, TryStreamExt};
23use snafu::ResultExt;
24use store_api::storage::{FileId, TimeSeriesRowSelector};
25
26use crate::cache::{
27 CacheStrategy, SelectorResult, SelectorResultKey, SelectorResultValue,
28 selector_result_cache_hit, selector_result_cache_miss,
29};
30use crate::error::{ComputeArrowSnafu, Result};
31use crate::read::read_columns::JsonTargetTypes;
32use crate::read::{BoxedRecordBatchStream, timestamp_array_to_i64_slice};
33use crate::sst::parquet::DEFAULT_READ_BATCH_SIZE;
34use crate::sst::parquet::flat_format::{primary_key_column_index, time_index_column_index};
35use crate::sst::parquet::format::{PrimaryKeyArray, primary_key_offsets};
36use crate::sst::parquet::read_columns::ParquetReadColumns;
37use crate::sst::parquet::reader::FlatRowGroupReader;
38
39pub(crate) enum FlatRowGroupLastRowCachedReader {
43 Hit(FlatLastRowCacheReader),
45 Miss(FlatRowGroupLastRowReader),
47}
48
49impl FlatRowGroupLastRowCachedReader {
50 pub(crate) fn new(
51 file_id: FileId,
52 row_group_idx: usize,
53 cache_strategy: CacheStrategy,
54 read_cols: &ParquetReadColumns,
55 json_target_types: JsonTargetTypes,
56 reader: FlatRowGroupReader,
57 ) -> Self {
58 let key = SelectorResultKey {
59 file_id,
60 row_group_idx,
61 selector: TimeSeriesRowSelector::LastRow { after_merge: false },
62 };
63
64 if let Some(value) = cache_strategy.get_selector_result(&key) {
65 let is_flat = matches!(&value.result, SelectorResult::Flat(_));
66 let schema_matches = value.read_cols == *read_cols;
67 let json_target_types_matches = value.json_target_types == json_target_types;
68 if is_flat && schema_matches && json_target_types_matches {
69 Self::new_hit(value)
70 } else {
71 Self::new_miss(key, read_cols, json_target_types, reader, cache_strategy)
72 }
73 } else {
74 Self::new_miss(key, read_cols, json_target_types, reader, cache_strategy)
75 }
76 }
77
78 pub(crate) async fn next_batch(&mut self) -> Result<Option<RecordBatch>> {
80 match self {
81 FlatRowGroupLastRowCachedReader::Hit(r) => r.next_batch(),
82 FlatRowGroupLastRowCachedReader::Miss(r) => r.next_batch().await,
83 }
84 }
85
86 fn new_hit(value: Arc<SelectorResultValue>) -> Self {
87 selector_result_cache_hit();
88 Self::Hit(FlatLastRowCacheReader { value, idx: 0 })
89 }
90
91 fn new_miss(
92 key: SelectorResultKey,
93 read_cols: &ParquetReadColumns,
94 json_target_types: JsonTargetTypes,
95 reader: FlatRowGroupReader,
96 cache_strategy: CacheStrategy,
97 ) -> Self {
98 selector_result_cache_miss();
99 Self::Miss(FlatRowGroupLastRowReader::new(
100 key,
101 read_cols.clone(),
102 json_target_types,
103 reader,
104 cache_strategy,
105 ))
106 }
107}
108
109pub(crate) struct FlatLastRowCacheReader {
111 value: Arc<SelectorResultValue>,
112 idx: usize,
113}
114
115impl FlatLastRowCacheReader {
116 fn next_batch(&mut self) -> Result<Option<RecordBatch>> {
117 let batches = match &self.value.result {
118 SelectorResult::Flat(batches) => batches,
119 SelectorResult::PrimaryKey(_) => unreachable!(),
120 };
121 if self.idx < batches.len() {
122 let res = Ok(Some(batches[self.idx].clone()));
123 self.idx += 1;
124 res
125 } else {
126 Ok(None)
127 }
128 }
129}
130
131pub(crate) struct BatchBuffer {
133 batches: Vec<RecordBatch>,
134 num_rows: usize,
135}
136
137impl BatchBuffer {
138 fn new() -> Self {
139 Self {
140 batches: Vec::new(),
141 num_rows: 0,
142 }
143 }
144
145 fn is_full(&self) -> bool {
147 self.num_rows >= DEFAULT_READ_BATCH_SIZE
148 }
149
150 fn extend_from_slice(&mut self, batches: &[RecordBatch]) {
152 for batch in batches {
153 self.num_rows += batch.num_rows();
154 }
155 self.batches.extend_from_slice(batches);
156 }
157
158 fn is_empty(&self) -> bool {
160 self.batches.is_empty()
161 }
162
163 fn concat(&mut self) -> Result<RecordBatch> {
165 debug_assert!(!self.batches.is_empty());
166 let schema = self.batches[0].schema();
167 let merged = concat_batches(&schema, &self.batches).context(ComputeArrowSnafu)?;
168 self.batches.clear();
169 self.num_rows = 0;
170 Ok(merged)
171 }
172}
173
174pub(crate) struct FlatRowGroupLastRowReader {
176 key: SelectorResultKey,
177 reader: FlatRowGroupReader,
178 selector: FlatLastTimestampSelector,
179 yielded_batches: Vec<RecordBatch>,
180 cache_strategy: CacheStrategy,
181 read_cols: ParquetReadColumns,
182 json_target_types: JsonTargetTypes,
183 pending: BatchBuffer,
185}
186
187impl FlatRowGroupLastRowReader {
188 fn new(
189 key: SelectorResultKey,
190 read_cols: ParquetReadColumns,
191 json_target_types: JsonTargetTypes,
192 reader: FlatRowGroupReader,
193 cache_strategy: CacheStrategy,
194 ) -> Self {
195 Self {
196 key,
197 reader,
198 selector: FlatLastTimestampSelector::default(),
199 yielded_batches: vec![],
200 cache_strategy,
201 read_cols,
202 json_target_types,
203 pending: BatchBuffer::new(),
204 }
205 }
206
207 fn flush_pending(&mut self) -> Result<Option<RecordBatch>> {
209 if self.pending.is_empty() {
210 return Ok(None);
211 }
212 let merged = self.pending.concat()?;
213 self.yielded_batches.push(merged.clone());
214 Ok(Some(merged))
215 }
216
217 async fn next_batch(&mut self) -> Result<Option<RecordBatch>> {
218 if self.pending.is_full() {
219 return self.flush_pending();
220 }
221
222 while let Some(batch) = self.reader.next_batch().await? {
223 self.selector.on_next(batch, &mut self.pending)?;
224 if self.pending.is_full() {
225 return self.flush_pending();
226 }
227 }
228
229 self.selector.finish(&mut self.pending)?;
231 if !self.pending.is_empty() {
232 let result = self.flush_pending();
233 self.maybe_update_cache();
235 return result;
236 }
237
238 self.maybe_update_cache();
240 Ok(None)
241 }
242
243 fn maybe_update_cache(&mut self) {
244 if self.yielded_batches.is_empty() {
245 return;
246 }
247 let batches = std::mem::take(&mut self.yielded_batches);
248 let value = Arc::new(SelectorResultValue::new_flat(
249 batches,
250 self.read_cols.clone(),
251 self.json_target_types.clone(),
252 ));
253 self.cache_strategy.put_selector_result(self.key, value);
254 }
255}
256
257#[derive(Default)]
262pub(crate) struct FlatLastTimestampSelector {
263 current_key: Option<LastKeyState>,
265}
266
267#[derive(Debug)]
268struct LastKeyState {
269 key: Vec<u8>,
270 last_timestamp: i64,
271 slices: Vec<RecordBatch>,
272}
273
274impl LastKeyState {
275 fn new(key: Vec<u8>, last_timestamp: i64, first_slice: RecordBatch) -> Self {
276 Self {
277 key,
278 last_timestamp,
279 slices: vec![first_slice],
280 }
281 }
282}
283
284impl FlatLastTimestampSelector {
285 pub(crate) fn on_next(
287 &mut self,
288 batch: RecordBatch,
289 output_buffer: &mut BatchBuffer,
290 ) -> Result<()> {
291 if batch.num_rows() == 0 {
292 return Ok(());
293 }
294
295 let num_columns = batch.num_columns();
296 let pk_col_idx = primary_key_column_index(num_columns);
297 let ts_col_idx = time_index_column_index(num_columns);
298
299 let pk_array = batch
300 .column(pk_col_idx)
301 .as_any()
302 .downcast_ref::<PrimaryKeyArray>()
303 .unwrap();
304 let offsets = primary_key_offsets(pk_array)?;
305 if offsets.is_empty() {
306 return Ok(());
307 }
308
309 let ts_values = timestamp_array_to_i64_slice(batch.column(ts_col_idx));
310 for i in 0..offsets.len() - 1 {
311 let range_start = offsets[i];
312 let range_end = offsets[i + 1];
313 let range_key = primary_key_bytes_at(&batch, pk_col_idx, range_start);
314 let range_last_ts = ts_values[range_end - 1];
315 let range_last_ts_start = last_timestamp_start(ts_values, range_start, range_end);
316 let range_slice = batch.slice(range_last_ts_start, range_end - range_last_ts_start);
317
318 match self.current_key.as_mut() {
319 Some(state) if state.key.as_slice() == range_key => {
320 if range_last_ts > state.last_timestamp {
321 state.last_timestamp = range_last_ts;
322 state.slices.clear();
323 state.slices.push(range_slice);
324 } else if range_last_ts == state.last_timestamp {
325 state.slices.push(range_slice);
326 }
327 }
328 Some(_) => {
329 self.flush_current_key(output_buffer);
330 self.current_key = Some(LastKeyState::new(
331 range_key.to_vec(),
332 range_last_ts,
333 range_slice,
334 ));
335 }
336 None => {
337 self.current_key = Some(LastKeyState::new(
338 range_key.to_vec(),
339 range_last_ts,
340 range_slice,
341 ));
342 }
343 }
344 }
345
346 Ok(())
347 }
348
349 pub(crate) fn finish(&mut self, output_buffer: &mut BatchBuffer) -> Result<()> {
351 self.flush_current_key(output_buffer);
352 Ok(())
353 }
354
355 fn flush_current_key(&mut self, output_buffer: &mut BatchBuffer) {
356 let Some(state) = self.current_key.take() else {
357 return;
358 };
359 output_buffer.extend_from_slice(&state.slices);
360 }
361}
362
363pub(crate) struct FlatLastRowReader {
366 stream: BoxedRecordBatchStream,
367 selector: FlatLastTimestampSelector,
368 pending: BatchBuffer,
369}
370
371impl FlatLastRowReader {
372 pub(crate) fn new(stream: BoxedRecordBatchStream) -> Self {
374 Self {
375 stream,
376 selector: FlatLastTimestampSelector::default(),
377 pending: BatchBuffer::new(),
378 }
379 }
380
381 pub(crate) fn into_stream(mut self) -> impl Stream<Item = Result<RecordBatch>> {
383 async_stream::try_stream! {
384 while let Some(batch) = self.stream.try_next().await? {
385 self.selector.on_next(batch, &mut self.pending)?;
386 if self.pending.is_full() {
387 yield self.pending.concat()?;
388 }
389 }
390 self.selector.finish(&mut self.pending)?;
391 if !self.pending.is_empty() {
392 yield self.pending.concat()?;
393 }
394 }
395 }
396}
397
398fn primary_key_bytes_at(batch: &RecordBatch, pk_col_idx: usize, index: usize) -> &[u8] {
400 let pk_dict = batch
401 .column(pk_col_idx)
402 .as_any()
403 .downcast_ref::<PrimaryKeyArray>()
404 .unwrap();
405 let key = pk_dict.keys().value(index);
406 let binary_values = pk_dict
407 .values()
408 .as_any()
409 .downcast_ref::<BinaryArray>()
410 .unwrap();
411 binary_values.value(key as usize)
412}
413
414fn last_timestamp_start(ts_values: &[i64], range_start: usize, range_end: usize) -> usize {
417 debug_assert!(range_start < range_end);
418
419 let last_ts = ts_values[range_end - 1];
420 let mut start = range_end - 1;
421 while start > range_start && ts_values[start - 1] == last_ts {
422 start -= 1;
423 }
424 start
425}
426
427#[cfg(test)]
428mod tests {
429 use std::sync::Arc;
430
431 use datatypes::arrow::array::{
432 ArrayRef, BinaryDictionaryBuilder, Int64Array, TimestampMillisecondArray, UInt8Array,
433 UInt64Array,
434 };
435 use datatypes::arrow::datatypes::{DataType, Field, Schema, SchemaRef, TimeUnit, UInt32Type};
436 use datatypes::arrow::record_batch::RecordBatch;
437
438 use super::*;
439
440 fn new_flat_batch(primary_keys: &[&[u8]], timestamps: &[i64], fields: &[i64]) -> RecordBatch {
442 let num_rows = timestamps.len();
443 assert_eq!(primary_keys.len(), num_rows);
444 assert_eq!(fields.len(), num_rows);
445
446 let columns: Vec<ArrayRef> = vec![
447 Arc::new(Int64Array::from_iter_values(fields.iter().copied())),
449 Arc::new(TimestampMillisecondArray::from_iter_values(
451 timestamps.iter().copied(),
452 )),
453 {
455 let mut builder = BinaryDictionaryBuilder::<UInt32Type>::new();
456 for &pk in primary_keys {
457 builder.append(pk).unwrap();
458 }
459 Arc::new(builder.finish())
460 },
461 Arc::new(UInt64Array::from_iter_values(vec![1u64; num_rows])),
463 Arc::new(UInt8Array::from_iter_values(vec![1u8; num_rows])),
465 ];
466
467 RecordBatch::try_new(test_flat_schema(), columns).unwrap()
468 }
469
470 fn test_flat_schema() -> SchemaRef {
471 let fields = vec![
472 Field::new("field0", DataType::Int64, false),
473 Field::new(
474 "ts",
475 DataType::Timestamp(TimeUnit::Millisecond, None),
476 false,
477 ),
478 Field::new(
479 "__primary_key",
480 DataType::Dictionary(Box::new(DataType::UInt32), Box::new(DataType::Binary)),
481 false,
482 ),
483 Field::new("__sequence", DataType::UInt64, false),
484 Field::new("__op_type", DataType::UInt8, false),
485 ];
486 Arc::new(Schema::new(fields))
487 }
488
489 fn collect_flat_results(
491 selector: &mut FlatLastTimestampSelector,
492 batches: Vec<RecordBatch>,
493 ) -> Vec<(Vec<u8>, i64)> {
494 let mut output_buffer = BatchBuffer::new();
495 let mut results = Vec::new();
496 for batch in batches {
497 selector.on_next(batch, &mut output_buffer).unwrap();
498 for r in output_buffer.batches.drain(..) {
499 extract_flat_rows(&r, &mut results);
500 }
501 output_buffer.num_rows = 0;
502 }
503 selector.finish(&mut output_buffer).unwrap();
504 for r in output_buffer.batches.drain(..) {
505 extract_flat_rows(&r, &mut results);
506 }
507 results
508 }
509
510 fn extract_flat_rows(batch: &RecordBatch, out: &mut Vec<(Vec<u8>, i64)>) {
512 let ts_col = batch
513 .column(1)
514 .as_any()
515 .downcast_ref::<TimestampMillisecondArray>()
516 .unwrap();
517 let pk_col = batch
518 .column(2)
519 .as_any()
520 .downcast_ref::<PrimaryKeyArray>()
521 .unwrap();
522 let binary_values = pk_col
523 .values()
524 .as_any()
525 .downcast_ref::<BinaryArray>()
526 .unwrap();
527
528 for i in 0..batch.num_rows() {
529 let key_idx = pk_col.keys().value(i);
530 let pk = binary_values.value(key_idx as usize).to_vec();
531 let ts = ts_col.value(i);
532 out.push((pk, ts));
533 }
534 }
535
536 #[test]
537 fn test_flat_single_batch_one_key() {
538 let mut selector = FlatLastTimestampSelector::default();
539 let batch = new_flat_batch(&[b"k1", b"k1", b"k1"], &[1, 2, 3], &[10, 20, 30]);
540 let results = collect_flat_results(&mut selector, vec![batch]);
541 assert_eq!(vec![(b"k1".to_vec(), 3)], results);
542 }
543
544 #[test]
545 fn test_flat_single_batch_multiple_keys() {
546 let mut selector = FlatLastTimestampSelector::default();
547 let batch = new_flat_batch(
548 &[b"k1", b"k1", b"k2", b"k2", b"k3"],
549 &[1, 2, 3, 4, 5],
550 &[10, 20, 30, 40, 50],
551 );
552 let results = collect_flat_results(&mut selector, vec![batch]);
553 assert_eq!(
554 vec![
555 (b"k1".to_vec(), 2),
556 (b"k2".to_vec(), 4),
557 (b"k3".to_vec(), 5),
558 ],
559 results
560 );
561 }
562
563 #[test]
564 fn test_flat_key_spans_batches() {
565 let mut selector = FlatLastTimestampSelector::default();
566 let batches = vec![
567 new_flat_batch(&[b"k1", b"k1"], &[1, 2], &[10, 20]),
568 new_flat_batch(&[b"k1", b"k2"], &[3, 4], &[30, 40]),
569 new_flat_batch(&[b"k2", b"k3"], &[5, 6], &[50, 60]),
570 ];
571 let results = collect_flat_results(&mut selector, batches);
572 assert_eq!(
573 vec![
574 (b"k1".to_vec(), 3),
575 (b"k2".to_vec(), 5),
576 (b"k3".to_vec(), 6),
577 ],
578 results
579 );
580 }
581
582 #[test]
583 fn test_flat_duplicate_last_timestamps() {
584 let mut selector = FlatLastTimestampSelector::default();
585 let batch = new_flat_batch(
587 &[b"k1", b"k1", b"k1", b"k2"],
588 &[1, 3, 3, 5],
589 &[10, 20, 30, 40],
590 );
591 let results = collect_flat_results(&mut selector, vec![batch]);
592 assert_eq!(
593 vec![
594 (b"k1".to_vec(), 3),
595 (b"k1".to_vec(), 3),
596 (b"k2".to_vec(), 5),
597 ],
598 results
599 );
600 }
601
602 #[test]
603 fn test_flat_duplicate_last_timestamps_across_batches() {
604 let mut selector = FlatLastTimestampSelector::default();
605 let batches = vec![
607 new_flat_batch(&[b"k1", b"k1"], &[1, 3], &[10, 20]),
608 new_flat_batch(&[b"k1", b"k2"], &[3, 5], &[30, 40]),
609 ];
610 let results = collect_flat_results(&mut selector, batches);
611 assert_eq!(
612 vec![
613 (b"k1".to_vec(), 3),
614 (b"k1".to_vec(), 3),
615 (b"k2".to_vec(), 5),
616 ],
617 results
618 );
619 }
620
621 #[test]
622 fn test_flat_pending_chain_dropped_by_higher_timestamp() {
623 let mut selector = FlatLastTimestampSelector::default();
624 let batches = vec![
625 new_flat_batch(&[b"k1", b"k1"], &[1, 3], &[10, 20]),
626 new_flat_batch(&[b"k1", b"k1"], &[3, 3], &[21, 22]),
627 new_flat_batch(&[b"k1", b"k1"], &[4, 4], &[23, 24]),
628 ];
629 let results = collect_flat_results(&mut selector, batches);
630 assert_eq!(vec![(b"k1".to_vec(), 4), (b"k1".to_vec(), 4)], results);
631 }
632
633 #[test]
634 fn test_flat_finish_is_one_shot() {
635 let mut selector = FlatLastTimestampSelector::default();
636 let batch = new_flat_batch(&[b"k1", b"k1", b"k2"], &[1, 2, 3], &[10, 20, 30]);
637 let mut output_buffer = BatchBuffer::new();
638
639 selector.on_next(batch, &mut output_buffer).unwrap();
641 let mut pre_finish = Vec::new();
642 for r in output_buffer.batches.drain(..) {
643 extract_flat_rows(&r, &mut pre_finish);
644 }
645 output_buffer.num_rows = 0;
646 assert_eq!(vec![(b"k1".to_vec(), 2)], pre_finish);
647
648 selector.finish(&mut output_buffer).unwrap();
650 assert!(!output_buffer.is_empty());
651 output_buffer.batches.clear();
652 output_buffer.num_rows = 0;
653
654 selector.finish(&mut output_buffer).unwrap();
656 assert!(output_buffer.is_empty());
657 }
658}