arrow_select/coalesce/
generic.rs1use super::InProgressArray;
6use crate::concat::concat;
7use crate::filter::FilterPredicate;
8use arrow_array::{Array, ArrayRef};
9use arrow_schema::ArrowError;
10
11#[derive(Debug)]
19pub(crate) struct GenericInProgressArray {
20 source: Option<ArrayRef>,
22
23 source_data_referenced_in_buffers: bool,
25 buffered_arrays: Vec<ArrayRef>,
27
28 total_size_of_non_shared_buffers: usize,
30}
31
32impl GenericInProgressArray {
33 pub(crate) fn new() -> Self {
35 Self {
36 source: None,
37 buffered_arrays: vec![],
38 total_size_of_non_shared_buffers: 0,
39 source_data_referenced_in_buffers: false,
40 }
41 }
42}
43impl InProgressArray for GenericInProgressArray {
44 fn set_source(&mut self, source: Option<ArrayRef>) {
45 if let Some(old_source) = self.source.take() {
46 if self.source_data_referenced_in_buffers {
49 self.total_size_of_non_shared_buffers += old_source.get_array_memory_size();
50 }
51 }
52 self.source_data_referenced_in_buffers = false;
53 self.source = source;
54 }
55
56 fn copy_rows(&mut self, offset: usize, len: usize) -> Result<(), ArrowError> {
57 let source = self.source.as_ref().ok_or_else(|| {
58 ArrowError::InvalidArgumentError(
59 "Internal Error: GenericInProgressArray: source not set".to_string(),
60 )
61 })?;
62 self.source_data_referenced_in_buffers = true;
65 let array = source.slice(offset, len);
66 self.buffered_arrays.push(array);
67 Ok(())
68 }
69
70 fn copy_rows_by_filter_from(
71 &mut self,
72 source: ArrayRef,
73 filter: &FilterPredicate,
74 ) -> Result<(), ArrowError> {
75 let array = filter.filter(source.as_ref())?;
76 self.total_size_of_non_shared_buffers += array.get_array_memory_size();
77 self.buffered_arrays.push(array);
78 Ok(())
79 }
80
81 fn finish(&mut self) -> Result<ArrayRef, ArrowError> {
82 let array = concat(
85 &self
86 .buffered_arrays
87 .iter()
88 .map(|array| array.as_ref())
89 .collect::<Vec<_>>(),
90 )?;
91 self.buffered_arrays.clear();
92 self.total_size_of_non_shared_buffers = 0;
93 self.source_data_referenced_in_buffers = false;
94 Ok(array)
95 }
96
97 fn size(&self) -> usize {
98 self.total_size_of_non_shared_buffers
99 + self.buffered_arrays.capacity() * size_of::<ArrayRef>()
100 + self
101 .source
102 .as_ref()
103 .map_or(0, |a| a.get_array_memory_size())
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110 use arrow_array::Int32Array;
111 use std::sync::Arc;
112
113 fn arr(range: std::ops::Range<i32>) -> ArrayRef {
114 Arc::new(Int32Array::from_iter_values(range))
115 }
116
117 #[test]
118 fn test_size_empty() {
119 let in_progress = GenericInProgressArray::new();
120 assert_eq!(in_progress.size(), 0);
121 }
122
123 #[test]
124 fn test_source_is_counted_in_memory_and_released_when_not_used() {
125 let mut in_progress = GenericInProgressArray::new();
126
127 assert_eq!(in_progress.size(), 0);
129 {
130 let source1 = arr(0..100);
131 in_progress.set_source(Some(Arc::clone(&source1)));
132
133 assert_eq!(in_progress.size(), source1.get_array_memory_size());
135 }
136
137 {
138 let source2 = arr(0..40);
140 in_progress.set_source(Some(Arc::clone(&source2)));
141 assert_eq!(in_progress.size(), source2.get_array_memory_size());
142 }
143
144 in_progress.set_source(None);
146
147 assert_eq!(in_progress.size(), 0);
149 }
150
151 #[test]
152 fn test_double_copy_on_same_source_should_not_double_count() {
153 let mut in_progress = GenericInProgressArray::new();
154
155 assert_eq!(in_progress.size(), 0);
157
158 let source = arr(0..100);
159 in_progress.set_source(Some(Arc::clone(&source)));
160
161 let size_before_copy = in_progress.size();
163 assert_eq!(size_before_copy, source.get_array_memory_size());
164
165 for _ in 0..2 {
166 in_progress.copy_rows(0, 98).unwrap();
168
169 assert!(
171 in_progress.size() > size_before_copy,
172 "size after copy {} should be greater than before copy {size_before_copy}",
173 in_progress.size()
174 );
175 {
176 let in_progress_size = in_progress.size() as f64;
177 let source_size = source.get_array_memory_size();
178 let size_if_source_and_sliced_would_be_counted = (source_size as f64) * 1.8;
179 assert!(
180 in_progress_size < size_if_source_and_sliced_would_be_counted,
181 "size after copy {in_progress_size} should not include the source and sliced array (should be greater than {size_if_source_and_sliced_would_be_counted}), source size is {source_size}"
182 );
183 }
184 }
185
186 let size_before_clear_source = in_progress.size();
187
188 in_progress.set_source(None);
190
191 assert_eq!(in_progress.size(), size_before_clear_source);
193
194 {
195 let source2 = arr(0..40);
196 in_progress.set_source(Some(Arc::clone(&source2)));
197 assert_eq!(
198 in_progress.size(),
199 size_before_clear_source + source2.get_array_memory_size()
200 );
201 in_progress.set_source(None);
202 }
203
204 in_progress.finish().unwrap();
205
206 assert!(in_progress.size() < source.get_array_memory_size());
208 }
209}