1use crate::errors::OutResult;
2use crate::prelude::*;
3use arrow::record_batch::RecordBatch;
4use itertools::Itertools;
5use log::debug;
6use rayon::prelude::*;
7use std::marker::PhantomData;
8
9pub fn set_global_num_thread(num: usize) {
10 rayon::ThreadPoolBuilder::new()
11 .num_threads(num)
12 .build_global()
13 .unwrap();
14}
15
16pub struct ArrowBatchIter<S, TP>
18where
19 S: Source,
20 TP: Transport<
21 TSS = S::TypeSystem,
22 TSD = ArrowStreamTypeSystem,
23 S = S,
24 D = ArrowStreamDestination,
25 >,
26 <S as Source>::Partition: 'static,
27 <S as Source>::TypeSystem: 'static,
28 <TP as Transport>::Error: 'static,
29{
30 dst: ArrowStreamDestination,
31 dst_parts: Option<Vec<ArrowStreamPartitionWriter>>,
32 src_parts: Option<Vec<S::Partition>>,
33 dorder: DataOrder,
34 src_schema: Vec<S::TypeSystem>,
35 dst_schema: Vec<ArrowStreamTypeSystem>,
36 handle: Option<std::thread::JoinHandle<()>>,
37 _phantom: PhantomData<TP>,
38}
39
40impl<S, TP> ArrowBatchIter<S, TP>
41where
42 S: Source,
43 TP: Transport<
44 TSS = S::TypeSystem,
45 TSD = ArrowStreamTypeSystem,
46 S = S,
47 D = ArrowStreamDestination,
48 >,
49{
50 pub fn new(
51 src: S,
52 mut dst: ArrowStreamDestination,
53 origin_query: Option<String>,
54 queries: &[CXQuery<String>],
55 ) -> Result<Self, TP::Error> {
56 let dispatcher = Dispatcher::<_, _, TP>::new(src, &mut dst, queries, origin_query);
57 let (dorder, src_parts, dst_parts, src_schema, dst_schema) = dispatcher.prepare()?;
58
59 Ok(Self {
60 dst,
61 dst_parts: Some(dst_parts),
62 src_parts: Some(src_parts),
63 dorder,
64 src_schema,
65 dst_schema,
66 handle: None,
67 _phantom: PhantomData,
68 })
69 }
70
71 fn run(&mut self)
72 where
73 ConnectorXOutError: From<TP::Error>,
74 {
75 let src_schema = self.src_schema.clone();
76 let dst_schema = self.dst_schema.clone();
77 let src_partitions = self.src_parts.take().unwrap();
78 let dst_partitions = self.dst_parts.take().unwrap();
79 let dorder = self.dorder;
80
81 self.handle = Some(std::thread::spawn(move || {
82 let schemas: Vec<_> = src_schema
83 .iter()
84 .zip_eq(&dst_schema)
85 .map(|(&src_ty, &dst_ty)| (src_ty, dst_ty))
86 .collect();
87
88 debug!("Start writing");
89 let _ = dst_partitions
96 .into_par_iter()
97 .zip_eq(src_partitions)
98 .enumerate()
99 .try_for_each(|(i, (mut dst, mut src))| -> Result<(), ()> {
100 let mut parser = match src.parser() {
101 Ok(parser) => parser,
102 Err(e) => {
103 dst.send_error(TP::Error::from(e).into());
104 return Err(());
105 }
106 };
107
108 let result = (|| -> Result<(), TP::Error> {
109 match dorder {
110 DataOrder::RowMajor => loop {
111 let (n, is_last) = parser.fetch_next()?;
112 dst.aquire_row(n)?;
113 for _ in 0..n {
114 #[allow(clippy::needless_range_loop)]
115 for col in 0..dst.ncols() {
116 {
117 let (s1, s2) = schemas[col];
118 TP::process(s1, s2, &mut parser, &mut dst)?;
119 }
120 }
121 }
122 if is_last {
123 break;
124 }
125 },
126 DataOrder::ColumnMajor => loop {
127 let (n, is_last) = parser.fetch_next()?;
128 dst.aquire_row(n)?;
129 #[allow(clippy::needless_range_loop)]
130 for col in 0..dst.ncols() {
131 for _ in 0..n {
132 {
133 let (s1, s2) = schemas[col];
134 TP::process(s1, s2, &mut parser, &mut dst)?;
135 }
136 }
137 }
138 if is_last {
139 break;
140 }
141 },
142 }
143
144 debug!("Finalize partition {}", i);
145 dst.finalize()?;
146 debug!("Partition {} finished", i);
147 Ok(())
148 })();
149
150 match result {
151 Ok(()) => Ok(()),
152 Err(e) => {
153 debug!("Partition {} failed: {:?}", i, e);
154 dst.send_error(e.into());
157 Err(())
158 }
159 }
160 });
161
162 debug!("Writing finished");
163 }));
164 }
165}
166
167impl<S, TP> Iterator for ArrowBatchIter<S, TP>
168where
169 S: Source,
170 TP: Transport<
171 TSS = S::TypeSystem,
172 TSD = ArrowStreamTypeSystem,
173 S = S,
174 D = ArrowStreamDestination,
175 >,
176 ConnectorXOutError: From<TP::Error>,
177{
178 type Item = OutResult<RecordBatch>;
179
180 fn next(&mut self) -> Option<Self::Item> {
191 match self.dst.record_batch() {
192 Some(msg) => Some(msg),
193 None => {
194 if let Some(handle) = self.handle.take() {
197 if let Err(payload) = handle.join() {
198 std::panic::resume_unwind(payload);
199 }
200 }
201 None
202 }
203 }
204 }
205}
206
207pub trait RecordBatchIterator: Send {
208 fn get_schema(&self) -> (RecordBatch, &[String]);
209 fn prepare(&mut self);
210 fn next_batch(&mut self) -> Option<OutResult<RecordBatch>>;
212}
213
214impl<S, TP> RecordBatchIterator for ArrowBatchIter<S, TP>
215where
216 S: Source,
217 TP: Transport<
218 TSS = S::TypeSystem,
219 TSD = ArrowStreamTypeSystem,
220 S = S,
221 D = ArrowStreamDestination,
222 > + std::marker::Send,
223 ConnectorXOutError: From<TP::Error>,
224{
225 fn get_schema(&self) -> (RecordBatch, &[String]) {
226 (self.dst.empty_batch(), self.dst.names())
227 }
228
229 fn prepare(&mut self) {
230 self.run();
231 }
232
233 fn next_batch(&mut self) -> Option<OutResult<RecordBatch>> {
234 self.next()
235 }
236}