2323#include " arrow/array/util.h"
2424#include " arrow/c/abi.h"
2525#include " arrow/c/bridge.h"
26- #include " fmt/format.h"
2726#include " paimon/common/metrics/metrics_impl.h"
2827#include " paimon/common/reader/reader_utils.h"
28+ #include " paimon/common/utils/arrow/arrow_utils.h"
2929#include " paimon/common/utils/arrow/mem_utils.h"
3030#include " paimon/common/utils/arrow/status_utils.h"
3131#include " paimon/common/utils/checked_cast.h"
@@ -59,25 +59,43 @@ Result<std::unique_ptr<DataEvolutionFileReader>> DataEvolutionFileReader::Create
5959}
6060
6161Result<BatchReader::ReadBatchWithBitmap> DataEvolutionFileReader::NextBatchWithBitmap () {
62+ int64_t array_length = read_batch_size_;
63+ bool has_active_reader = false ;
64+ bool has_available_array = false ;
65+ bool has_eof_reader = false ;
66+ for (size_t i = 0 ; i < readers_.size (); i++) {
67+ if (!readers_[i]) {
68+ continue ;
69+ }
70+ has_active_reader = true ;
71+ PAIMON_ASSIGN_OR_RAISE (bool has_cached_array, EnsureCachedArray (i));
72+ if (!has_cached_array) {
73+ has_eof_reader = true ;
74+ continue ;
75+ }
76+ has_available_array = true ;
77+ array_length = std::min (array_length, CalculateCachedArrayLength (i));
78+ }
79+ if (!has_active_reader) {
80+ return Status::Invalid (" data evolution reader has no active inner reader" );
81+ }
82+ if (has_eof_reader) {
83+ if (has_available_array) {
84+ return Status::Invalid (" array for single reader length mismatch others" );
85+ }
86+ return BatchReader::MakeEofBatchWithBitmap ();
87+ }
88+
6289 std::vector<std::shared_ptr<arrow::StructArray>> array_for_each_reader;
6390 array_for_each_reader.reserve (readers_.size ());
64- int64_t array_length = -1 ;
6591 for (size_t i = 0 ; i < readers_.size (); i++) {
6692 if (!readers_[i]) {
6793 // no read field from readers_[i]
6894 array_for_each_reader.push_back (nullptr );
6995 continue ;
7096 }
71- PAIMON_ASSIGN_OR_RAISE (std::shared_ptr<arrow::Array> array, NextBatchForSingleReader (i));
72- if (array == nullptr ) {
73- // read eof
74- return BatchReader::MakeEofBatchWithBitmap ();
75- }
76- if (array_length == -1 ) {
77- array_length = array->length ();
78- } else if (array_length != array->length ()) {
79- return Status::Invalid (" array for single reader length mismatch others" );
80- }
97+ PAIMON_ASSIGN_OR_RAISE (std::shared_ptr<arrow::Array> array,
98+ TakeCachedArray (i, array_length));
8199 auto struct_array = checked_pointer_cast<arrow::StructArray>(array);
82100 array_for_each_reader.push_back (struct_array);
83101 }
@@ -132,24 +150,19 @@ int64_t DataEvolutionFileReader::CalculateCachedArrayLength(size_t reader_idx) c
132150 return total_length;
133151}
134152
135- Result<std::shared_ptr<arrow::Array>> DataEvolutionFileReader::NextBatchForSingleReader (
136- size_t reader_idx) {
137- int64_t total_array_length = CalculateCachedArrayLength (reader_idx);
138- if (total_array_length >= read_batch_size_) {
139- assert (false );
140- return Status::Invalid (fmt::format (
141- " Unexpected: the length of cached array in last turn {} exceed read batch size {}" ,
142- total_array_length, read_batch_size_));
143- }
144- // array left for last turn
145- arrow::ArrayVector concat_array_vec = std::move (cached_array_vec_[reader_idx]);
146- cached_array_vec_[reader_idx].clear ();
147- while (total_array_length < read_batch_size_) {
153+ Result<bool > DataEvolutionFileReader::EnsureCachedArray (size_t reader_idx) {
154+ if (!cached_array_vec_[reader_idx].empty ()) {
155+ return true ;
156+ }
157+ if (reader_eof_[reader_idx]) {
158+ return false ;
159+ }
160+ while (cached_array_vec_[reader_idx].empty ()) {
148161 PAIMON_ASSIGN_OR_RAISE (ReadBatchWithBitmap src_array_with_bitmap,
149162 readers_[reader_idx]->NextBatchWithBitmap ());
150163 if (BatchReader::IsEofBatch (src_array_with_bitmap)) {
151- // read finish
152- break ;
164+ reader_eof_[reader_idx] = true ;
165+ return false ;
153166 }
154167 auto & [read_batch, bitmap] = src_array_with_bitmap;
155168 auto & [c_array, c_schema] = read_batch;
@@ -158,36 +171,45 @@ Result<std::shared_ptr<arrow::Array>> DataEvolutionFileReader::NextBatchForSingl
158171 PAIMON_ASSIGN_OR_RAISE (arrow::ArrayVector selected_array_vec,
159172 ReaderUtils::GenerateFilteredArrayVector (src_array, bitmap));
160173 for (const auto & selected_array : selected_array_vec) {
161- if (total_array_length + selected_array->length () > read_batch_size_) {
162- // need truncate current array to align read_batch_size_
163- int64_t truncated_length = read_batch_size_ - total_array_length;
164- if (truncated_length == 0 ) {
165- // total_array_length equals to read_batch_size_, all selected_array left will
166- // be added to cached_array_vec_
167- cached_array_vec_[reader_idx].push_back (selected_array);
168- } else {
169- concat_array_vec.push_back (selected_array->Slice (0 , truncated_length));
170- cached_array_vec_[reader_idx].push_back (
171- selected_array->Slice (truncated_length));
172- total_array_length += truncated_length;
173- }
174- } else {
175- concat_array_vec.push_back (selected_array);
176- total_array_length += selected_array->length ();
174+ if (selected_array->length () > 0 ) {
175+ cached_array_vec_[reader_idx].push_back (selected_array);
177176 }
178177 }
179178 }
180- if (concat_array_vec.empty ()) {
181- return std::shared_ptr<arrow::Array>();
179+ return true ;
180+ }
181+
182+ Result<std::shared_ptr<arrow::Array>> DataEvolutionFileReader::TakeCachedArray (
183+ size_t reader_idx, int64_t array_length) {
184+ if (array_length <= 0 ) {
185+ return Status::Invalid (" array length must be larger than zero" );
186+ }
187+ if (CalculateCachedArrayLength (reader_idx) < array_length) {
188+ return Status::Invalid (" requested array length exceeds cached array length" );
182189 }
183- if (concat_array_vec.size () == 1 && concat_array_vec[0 ]->offset () == 0 ) {
184- // Avoid data copy when the array is already normalized.
185- return concat_array_vec[0 ];
190+ arrow::ArrayVector selected_array_vec;
191+ int64_t remaining_length = array_length;
192+ auto & cached_array_vec = cached_array_vec_[reader_idx];
193+ while (remaining_length > 0 ) {
194+ const auto & cached_array = cached_array_vec.front ();
195+ if (cached_array->length () <= remaining_length) {
196+ selected_array_vec.push_back (cached_array);
197+ remaining_length -= cached_array->length ();
198+ cached_array_vec.erase (cached_array_vec.begin ());
199+ } else {
200+ selected_array_vec.push_back (cached_array->Slice (0 , remaining_length));
201+ cached_array_vec.front () = cached_array->Slice (remaining_length);
202+ remaining_length = 0 ;
203+ }
204+ }
205+ if (selected_array_vec.size () == 1 ) {
206+ return ArrowUtils::NormalizeArrayOffsets (selected_array_vec[0 ], arrow_pool_.get ());
186207 }
187208 PAIMON_ASSIGN_OR_RAISE_FROM_ARROW (std::shared_ptr<arrow::Array> concat_array,
188- arrow::Concatenate (concat_array_vec, arrow_pool_.get ()));
189- assert (concat_array->length () == total_array_length);
190- assert (concat_array->length () <= read_batch_size_);
209+ arrow::Concatenate (selected_array_vec, arrow_pool_.get ()));
210+ if (concat_array->length () != array_length) {
211+ return Status::Invalid (" concatenated array length does not match requested array length" );
212+ }
191213 return concat_array;
192214}
193215
0 commit comments