1use crate::coalesce::{InProgressArray, check_filter_len};
6use crate::filter::{FilterPredicate, FilterSelection};
7use arrow_array::cast::AsArray;
8use arrow_array::types::ByteViewType;
9use arrow_array::{Array, ArrayRef, GenericByteViewArray};
10use arrow_buffer::{Buffer, NullBuffer, NullBufferBuilder};
11use arrow_data::{ByteView, MAX_INLINE_VIEW_LEN};
12use arrow_schema::ArrowError;
13use std::marker::PhantomData;
14use std::sync::Arc;
15
16pub(crate) struct InProgressByteViewArray<B: ByteViewType> {
27 source: Option<Source>,
29 batch_size: usize,
31 views: Vec<u128>,
33 nulls: NullBufferBuilder,
35 current: Option<Vec<u8>>,
37 completed: Vec<Buffer>,
39 buffer_source: BufferSource,
41 _phantom: PhantomData<B>,
44 completed_buffers_size: usize,
46 size_of_completed_buffers_from_current_source: usize,
48}
49
50struct Source {
51 array: ArrayRef,
53 need_gc: bool,
55 ideal_buffer_size: usize,
57}
58
59impl<B: ByteViewType> std::fmt::Debug for InProgressByteViewArray<B> {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 f.debug_struct("InProgressByteViewArray")
63 .field("batch_size", &self.batch_size)
64 .field("views", &self.views.len())
65 .field("nulls", &self.nulls)
66 .field("current", &self.current.as_ref().map(|_| "Some(...)"))
67 .field("completed", &self.completed.len())
68 .finish()
69 }
70}
71
72impl<B: ByteViewType> InProgressByteViewArray<B> {
73 pub(crate) fn new(batch_size: usize) -> Self {
74 let buffer_source = BufferSource::new();
75
76 Self {
77 batch_size,
78 source: None,
79 views: Vec::new(), nulls: NullBufferBuilder::new(batch_size), current: None,
82 completed: vec![],
83 completed_buffers_size: 0,
84 size_of_completed_buffers_from_current_source: 0,
85 buffer_source,
86 _phantom: PhantomData,
87 }
88 }
89
90 fn ensure_capacity(&mut self) {
95 if self.views.capacity() == 0 {
96 self.views.reserve(self.batch_size);
97 }
98 }
99
100 fn finish_current(&mut self) {
102 let Some(next_buffer) = self.current.take() else {
103 return;
104 };
105 let buffer: Buffer = next_buffer.into();
106
107 self.completed_buffers_size += buffer.capacity();
108 self.completed.push(buffer);
109 }
110
111 unsafe fn append_views_by_filter(&mut self, views: &[u128], filter: &FilterPredicate) {
115 let selected_count = filter.count();
116 let current_len = self.views.len();
117 self.views.reserve(selected_count);
118
119 let mut written = 0;
120
121 unsafe {
125 let mut out = self.views.spare_capacity_mut().as_mut_ptr().cast::<u128>();
126
127 match filter.selection() {
128 FilterSelection::None => {}
129 FilterSelection::All { .. } => {
130 std::ptr::copy_nonoverlapping(views.as_ptr(), out, selected_count);
131 written = selected_count;
132 }
133 FilterSelection::Slices(slices) => {
134 slices.for_each(|(start, end)| {
135 let len = end - start;
136 std::ptr::copy_nonoverlapping(views.as_ptr().add(start), out, len);
137 out = out.add(len);
138 written += len;
139 });
140 }
141 FilterSelection::Indices(indices) => {
142 indices.for_each(|idx| {
143 out.write(*views.get_unchecked(idx));
144 out = out.add(1);
145 written += 1;
146 });
147 }
148 }
149
150 self.views.set_len(current_len + written);
151 }
152
153 debug_assert_eq!(written, selected_count);
154 }
155
156 fn append_nulls_by_filter(
157 &mut self,
158 filter: &FilterPredicate,
159 source_nulls: Option<&NullBuffer>,
160 ) {
161 if let Some(nulls) = filter.filter_nulls(source_nulls) {
162 self.nulls.append_buffer(&nulls);
163 } else {
164 self.nulls.append_n_non_nulls(filter.count());
165 }
166 }
167
168 #[inline(never)]
178 unsafe fn append_views_and_update_buffer_index(
179 &mut self,
180 views: &[u128],
181 buffers: &[Buffer],
182 is_reused: bool,
183 ) {
184 if let Some(buffer) = self.current.take() {
185 let buffer: Buffer = buffer.into();
186 self.completed_buffers_size += buffer.capacity();
187 self.completed.push(buffer);
188 }
189
190 let buffers_size = buffers.iter().map(|b| b.capacity()).sum::<usize>();
191 if !is_reused {
192 self.completed_buffers_size += buffers_size;
193 } else if self.size_of_completed_buffers_from_current_source == 0 {
194 self.size_of_completed_buffers_from_current_source += buffers_size;
196 }
197
198 let starting_buffer = self.completed.len() as u32;
199 self.completed.extend_from_slice(buffers);
200 assert!(
201 u32::try_from(self.completed.len()).is_ok(),
202 "too many buffers"
203 );
204
205 if starting_buffer == 0 {
206 self.views.extend_from_slice(views);
208 } else {
209 let updated_views = views.iter().map(|v| {
211 let offset = if *v as u32 > MAX_INLINE_VIEW_LEN {
215 starting_buffer
216 } else {
217 0
218 };
219 v + ((offset as u128) << 64)
224 });
225
226 self.views.extend(updated_views);
227 }
228 }
229
230 #[inline(never)]
244 unsafe fn append_views_and_copy_strings(
245 &mut self,
246 views: &[u128],
247 view_buffer_size: usize,
248 buffers: &[Buffer],
249 ) {
250 let Some(current) = self.current.take() else {
256 let new_buffer = self.buffer_source.next_buffer(view_buffer_size);
257 unsafe { self.append_views_and_copy_strings_inner(views, new_buffer, buffers) };
259 return;
260 };
261
262 let mut remaining_capacity = current.capacity() - current.len();
265 if view_buffer_size <= remaining_capacity {
266 unsafe { self.append_views_and_copy_strings_inner(views, current, buffers) };
268 return;
269 }
270
271 let mut num_view_to_current = 0;
277 for view in views {
278 let b = ByteView::from(*view);
279 let str_len = b.length;
280 if remaining_capacity < str_len as usize {
281 break;
282 }
283 if str_len > MAX_INLINE_VIEW_LEN {
284 remaining_capacity -= str_len as usize;
285 }
286 num_view_to_current += 1;
287 }
288
289 let first_views = &views[0..num_view_to_current];
290 let string_bytes_to_copy = current.capacity() - current.len() - remaining_capacity;
291 let remaining_view_buffer_size = view_buffer_size - string_bytes_to_copy;
292
293 unsafe { self.append_views_and_copy_strings_inner(first_views, current, buffers) };
295 let completed: Buffer = self.current.take().expect("completed").into();
296 self.completed_buffers_size += completed.capacity();
297 self.completed.push(completed);
298
299 let remaining_views = &views[num_view_to_current..];
301 let new_buffer = self.buffer_source.next_buffer(remaining_view_buffer_size);
302 unsafe { self.append_views_and_copy_strings_inner(remaining_views, new_buffer, buffers) };
304 }
305
306 #[inline(never)]
319 unsafe fn append_views_and_copy_strings_inner(
320 &mut self,
321 views: &[u128],
322 mut dst_buffer: Vec<u8>,
323 buffers: &[Buffer],
324 ) {
325 assert!(self.current.is_none(), "current buffer should be None");
326
327 if views.is_empty() {
328 self.current = Some(dst_buffer);
329 return;
330 }
331
332 let new_buffer_index: u32 = self.completed.len().try_into().expect("too many buffers");
333
334 #[cfg(debug_assertions)]
337 {
338 let total_length: usize = views
339 .iter()
340 .filter_map(|v| {
341 let b = ByteView::from(*v);
342 if b.length > MAX_INLINE_VIEW_LEN {
343 Some(b.length as usize)
344 } else {
345 None
346 }
347 })
348 .sum();
349 debug_assert!(
350 dst_buffer.capacity() >= total_length,
351 "dst_buffer capacity {} is less than total length {}",
352 dst_buffer.capacity(),
353 total_length
354 );
355 }
356
357 let new_views = views.iter().map(|v| {
359 let mut b: ByteView = ByteView::from(*v);
360 if b.length > MAX_INLINE_VIEW_LEN {
361 let buffer_index = b.buffer_index as usize;
362 let buffer_offset = b.offset as usize;
363 let str_len = b.length as usize;
364
365 b.offset = dst_buffer.len() as u32;
367 b.buffer_index = new_buffer_index;
368
369 let src = unsafe {
371 buffers
372 .get_unchecked(buffer_index)
373 .get_unchecked(buffer_offset..buffer_offset + str_len)
374 };
375 dst_buffer.extend_from_slice(src);
376 }
377 b.as_u128()
378 });
379
380 self.views.extend(new_views);
381 self.current = Some(dst_buffer);
382 }
383}
384
385impl<B: ByteViewType> InProgressArray for InProgressByteViewArray<B> {
386 fn set_source(&mut self, source: Option<ArrayRef>) {
387 self.completed_buffers_size += self.size_of_completed_buffers_from_current_source;
389 self.size_of_completed_buffers_from_current_source = 0;
390
391 self.source = source.map(|array| {
392 let s = array.as_byte_view::<B>();
393
394 let (need_gc, ideal_buffer_size) = if s.data_buffers().is_empty() {
395 (false, 0)
396 } else {
397 let ideal_buffer_size = s.total_buffer_bytes_used();
398 let need_gc = if ideal_buffer_size != 0 {
401 let mut is_sparse = false;
402 let mut curr_buffer_size = 0;
403 for buffer in s.data_buffers().iter() {
404 curr_buffer_size += buffer.capacity();
405 if curr_buffer_size > ideal_buffer_size * 2 {
406 is_sparse = true;
407 break;
408 }
409 }
410 is_sparse
411 } else {
412 false
413 };
414 (need_gc, ideal_buffer_size)
415 };
416
417 Source {
418 array,
419 need_gc,
420 ideal_buffer_size,
421 }
422 });
423 }
424
425 fn copy_rows(&mut self, offset: usize, len: usize) -> Result<(), ArrowError> {
426 self.ensure_capacity();
427 let source = self.source.take().ok_or_else(|| {
428 ArrowError::InvalidArgumentError(
429 "Internal Error: InProgressByteViewArray: source not set".to_string(),
430 )
431 })?;
432
433 let s = source.array.as_byte_view::<B>();
435
436 if let Some(nulls) = s.nulls().as_ref() {
438 let nulls = nulls.slice(offset, len);
439 self.nulls.append_buffer(&nulls);
440 } else {
441 self.nulls.append_n_non_nulls(len);
442 }
443
444 let buffers = s.data_buffers();
445 let views = &s.views().as_ref()[offset..offset + len];
446
447 if source.ideal_buffer_size == 0 {
450 self.views.extend_from_slice(views);
451 self.source = Some(source);
452 return Ok(());
453 }
454
455 if source.need_gc {
458 unsafe { self.append_views_and_copy_strings(views, source.ideal_buffer_size, buffers) };
460 } else {
461 unsafe { self.append_views_and_update_buffer_index(views, buffers, true) };
463 }
464 self.source = Some(source);
465 Ok(())
466 }
467
468 fn copy_rows_by_filter(&mut self, filter: &FilterPredicate) -> Result<(), ArrowError> {
469 self.ensure_capacity();
470 let source = self.source.take().ok_or_else(|| {
471 ArrowError::InvalidArgumentError(
472 "Internal Error: InProgressByteViewArray: source not set".to_string(),
473 )
474 })?;
475
476 let s = source.array.as_byte_view::<B>();
477
478 if !s.data_buffers().is_empty() {
479 self.source = Some(source);
481 return Err(ArrowError::InvalidArgumentError(
482 "Internal Error: InProgressByteViewArray::copy_rows_by_filter requires inline views"
483 .to_string(),
484 ));
485 }
486
487 if let Err(e) = check_filter_len(filter, s.len()) {
488 self.source = Some(source);
490 return Err(e);
491 }
492
493 self.append_nulls_by_filter(filter, s.nulls());
494 unsafe { self.append_views_by_filter(s.views(), filter) };
497
498 self.source = Some(source);
499 Ok(())
500 }
501
502 fn copy_rows_by_filter_from(
503 &mut self,
504 source: ArrayRef,
505 filter: &FilterPredicate,
506 ) -> Result<(), ArrowError> {
507 let s = source.as_byte_view::<B>();
508 if s.data_buffers().is_empty() {
511 check_filter_len(filter, s.len())?;
512 self.ensure_capacity();
513 self.append_nulls_by_filter(filter, s.nulls());
514 unsafe { self.append_views_by_filter(s.views(), filter) };
517 return Ok(());
518 }
519
520 let filtered = filter.filter(source.as_ref())?;
524 let filtered = filtered.as_byte_view::<B>();
525
526 self.ensure_capacity();
527 if let Some(nulls) = filtered.nulls().as_ref() {
528 self.nulls.append_buffer(nulls);
529 } else {
530 self.nulls.append_n_non_nulls(filter.count());
531 }
532 unsafe {
534 self.append_views_and_update_buffer_index(
535 filtered.views(),
536 filtered.data_buffers(),
537 false,
538 )
539 };
540 Ok(())
541 }
542
543 fn finish(&mut self) -> Result<ArrayRef, ArrowError> {
544 self.finish_current();
545 assert!(self.current.is_none());
546 let buffers = std::mem::take(&mut self.completed);
547 let views = std::mem::take(&mut self.views);
548 let nulls = self.nulls.finish();
549 self.nulls = NullBufferBuilder::new(self.batch_size);
550
551 self.size_of_completed_buffers_from_current_source = 0;
553 self.completed_buffers_size = 0;
554
555 let new_array = unsafe {
558 GenericByteViewArray::<B>::new_unchecked(views.into(), buffers.into(), nulls)
559 };
560 Ok(Arc::new(new_array))
561 }
562
563 fn size(&self) -> usize {
564 self.completed_buffers_size
565 + self.current.as_ref().map_or(0, |c| c.capacity())
566 + self.nulls.allocated_size()
567 + self.views.capacity() * size_of::<u128>()
568 + self
569 .source
570 .as_ref()
571 .map_or(0, |s| s.array.get_array_memory_size())
572 }
573}
574
575const STARTING_BLOCK_SIZE: usize = 4 * 1024; const MAX_BLOCK_SIZE: usize = 1024 * 1024; #[derive(Debug)]
580struct BufferSource {
581 current_size: usize,
582}
583
584impl BufferSource {
585 fn new() -> Self {
586 Self {
587 current_size: STARTING_BLOCK_SIZE,
588 }
589 }
590
591 fn next_buffer(&mut self, min_size: usize) -> Vec<u8> {
593 let size = self.next_size(min_size);
594 Vec::with_capacity(size)
595 }
596
597 fn next_size(&mut self, min_size: usize) -> usize {
598 if self.current_size < MAX_BLOCK_SIZE {
599 self.current_size = self.current_size.saturating_mul(2);
602 }
603 if self.current_size >= min_size {
604 self.current_size
605 } else {
606 while self.current_size <= min_size && self.current_size < MAX_BLOCK_SIZE {
608 self.current_size = self.current_size.saturating_mul(2);
609 }
610 self.current_size.max(min_size)
611 }
612 }
613}
614
615#[cfg(test)]
616mod tests {
617 use super::*;
618 use crate::filter::FilterBuilder;
619 use arrow_array::types::BinaryViewType;
620 use arrow_array::{BinaryViewArray, BooleanArray};
621
622 #[test]
623 fn test_buffer_source() {
624 let mut source = BufferSource::new();
625 assert_eq!(source.next_buffer(1000).capacity(), 8192);
626 assert_eq!(source.next_buffer(1000).capacity(), 16384);
627 assert_eq!(source.next_buffer(1000).capacity(), 32768);
628 assert_eq!(source.next_buffer(1000).capacity(), 65536);
629 assert_eq!(source.next_buffer(1000).capacity(), 131072);
630 assert_eq!(source.next_buffer(1000).capacity(), 262144);
631 assert_eq!(source.next_buffer(1000).capacity(), 524288);
632 assert_eq!(source.next_buffer(1000).capacity(), 1024 * 1024);
633 assert_eq!(source.next_buffer(1000).capacity(), 1024 * 1024);
635 assert_eq!(source.next_buffer(10_000_000).capacity(), 10_000_000);
637 }
638
639 #[test]
640 fn test_buffer_source_with_min_small() {
641 let mut source = BufferSource::new();
642 assert_eq!(source.next_buffer(5_600).capacity(), 8 * 1024);
644 assert_eq!(source.next_buffer(5_600).capacity(), 16 * 1024);
646 assert_eq!(source.next_buffer(5_600).capacity(), 32 * 1024);
648 }
649
650 #[test]
651 fn test_buffer_source_with_min_large() {
652 let mut source = BufferSource::new();
653 assert_eq!(source.next_buffer(500_000).capacity(), 512 * 1024);
654 assert_eq!(source.next_buffer(500_000).capacity(), 1024 * 1024);
655 assert_eq!(source.next_buffer(500_000).capacity(), 1024 * 1024);
657 assert_eq!(source.next_buffer(2_000_000).capacity(), 2_000_000);
659 }
660
661 #[test]
662 fn test_copy_rows_by_filter_rejects_non_inline_views() {
663 let values: Vec<Option<&[u8]>> = vec![Some(b"This value is longer than 12 bytes")];
664 let array = BinaryViewArray::from_iter(values);
665 assert!(!array.data_buffers().is_empty());
666
667 let mut in_progress = InProgressByteViewArray::<BinaryViewType>::new(1);
668 in_progress.set_source(Some(Arc::new(array)));
669
670 let filter = BooleanArray::from(vec![true]);
671 let predicate = FilterBuilder::new(&filter).build();
672 let err = in_progress.copy_rows_by_filter(&predicate).unwrap_err();
673
674 assert!(
675 err.to_string().contains("requires inline views"),
676 "unexpected error: {err}"
677 );
678 }
679
680 #[test]
681 fn test_copy_rows_by_filter_from_reuses_non_inline_buffers() {
682 let values = (0..32)
683 .map(|i| format!("This value is longer than 12 bytes: {i}").into_bytes())
684 .collect::<Vec<_>>();
685 let array = BinaryViewArray::from_iter(values.iter().map(|v| Some(v.as_slice())));
686 assert!(!array.data_buffers().is_empty());
687 let source_buffer = array.data_buffers()[0].as_ptr();
688
689 let filter = BooleanArray::from((0..32).map(|i| i == 3 || i == 29).collect::<Vec<_>>());
690 let predicate = FilterBuilder::new(&filter).build();
691
692 let mut in_progress = InProgressByteViewArray::<BinaryViewType>::new(32);
693 in_progress
694 .copy_rows_by_filter_from(Arc::new(array), &predicate)
695 .unwrap();
696 let output = in_progress.finish().unwrap();
697 let output = output.as_binary_view();
698
699 assert_eq!(output.len(), 2);
700 assert_eq!(output.value(0), values[3].as_slice());
701 assert_eq!(output.value(1), values[29].as_slice());
702 assert!(
703 output
704 .data_buffers()
705 .iter()
706 .any(|buffer| std::ptr::addr_eq(buffer.as_ptr(), source_buffer)),
707 "expected filtered output to reuse the source data buffer"
708 );
709 }
710
711 fn non_inline_array(n: usize) -> (BinaryViewArray, usize) {
715 let values = (0..n)
716 .map(|i| format!("This value is longer than 12 bytes: {i}").into_bytes())
717 .collect::<Vec<_>>();
718 let array = BinaryViewArray::from_iter(values.iter().map(|v| Some(v.as_slice()))).gc();
719 assert!(!array.data_buffers().is_empty());
720 let buffer_capacity = array.data_buffers().iter().map(|b| b.capacity()).sum();
721 (array, buffer_capacity)
722 }
723
724 #[test]
725 fn test_size_empty() {
726 let in_progress = InProgressByteViewArray::<BinaryViewType>::new(64);
727 assert_eq!(in_progress.size(), 0);
728 }
729
730 #[test]
731 fn test_size_reused_buffers_not_double_counted() {
732 let (array, buffer_capacity) = non_inline_array(64);
733 let source: ArrayRef = Arc::new(array);
734
735 let mut in_progress = InProgressByteViewArray::<BinaryViewType>::new(64);
736 in_progress.set_source(Some(Arc::clone(&source)));
737
738 in_progress.copy_rows(0, 60).unwrap();
739 in_progress.copy_rows(60, 4).unwrap();
740
741 assert_eq!(in_progress.completed_buffers_size, 0);
745 assert_eq!(
746 in_progress.size_of_completed_buffers_from_current_source,
747 buffer_capacity,
748 );
749
750 let other: ArrayRef = Arc::new(BinaryViewArray::from_iter(std::iter::once(Some(
753 b"short".as_slice(),
754 ))));
755 in_progress.set_source(Some(Arc::clone(&other)));
756 assert_eq!(in_progress.completed_buffers_size, buffer_capacity);
757 assert_eq!(in_progress.size_of_completed_buffers_from_current_source, 0);
758
759 in_progress.finish().unwrap();
761 assert_eq!(in_progress.completed_buffers_size, 0);
762 assert_eq!(in_progress.size_of_completed_buffers_from_current_source, 0);
763 }
764
765 #[test]
766 fn size_should_be_the_same_if_copying_multiple_time_from_same_source_or_once() {
767 let (array, _buffer_capacity) = non_inline_array(64);
768 let source: ArrayRef = Arc::new(array);
769
770 let in_progress_size_with_split = {
771 let mut in_progress = InProgressByteViewArray::<BinaryViewType>::new(64);
772 in_progress.set_source(Some(Arc::clone(&source)));
773
774 in_progress.copy_rows(0, 60).unwrap();
775 in_progress.copy_rows(60, 4).unwrap();
776 in_progress.set_source(None);
777
778 in_progress.size()
779 };
780
781 let in_progress_size_without_split = {
782 let mut in_progress = InProgressByteViewArray::<BinaryViewType>::new(64);
783 in_progress.set_source(Some(Arc::clone(&source)));
784
785 in_progress.copy_rows(0, 64).unwrap();
786 in_progress.set_source(None);
787
788 in_progress.size()
789 };
790
791 assert_eq!(in_progress_size_with_split, in_progress_size_without_split);
792 }
793}