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