2323#include < utility>
2424
2525#include " arrow/api.h"
26- #include " arrow/array/array_base.h"
27- #include " arrow/array/array_binary.h"
28- #include " arrow/array/array_nested.h"
2926#include " arrow/c/abi.h"
30- #include " arrow/c/bridge.h"
3127#include " arrow/c/helpers.h"
32- #include " arrow/util/checked_cast.h"
33- #include " fmt/format.h"
3428#include " paimon/common/metrics/metrics_impl.h"
3529#include " paimon/common/table/special_fields.h"
36- #include " paimon/common/types/data_field.h"
3730#include " paimon/common/utils/arrow/status_utils.h"
3831#include " paimon/common/utils/scope_guard.h"
3932#include " paimon/core/io/async_key_value_producer_and_consumer.h"
4033#include " paimon/core/io/compact_increment.h"
4134#include " paimon/core/io/data_file_path_factory.h"
4235#include " paimon/core/io/data_increment.h"
4336#include " paimon/core/io/key_value_data_file_writer.h"
44- #include " paimon/core/io/key_value_in_memory_record_reader.h"
4537#include " paimon/core/io/key_value_meta_projection_consumer.h"
4638#include " paimon/core/io/key_value_record_reader.h"
4739#include " paimon/core/io/row_to_arrow_array_converter.h"
4840#include " paimon/core/io/single_file_writer.h"
4941#include " paimon/core/manifest/file_source.h"
5042#include " paimon/core/mergetree/compact/sort_merge_reader_with_loser_tree.h"
43+ #include " paimon/core/mergetree/write_buffer.h"
5144#include " paimon/core/utils/commit_increment.h"
52- #include " paimon/data/decimal.h"
5345#include " paimon/format/file_format.h"
5446#include " paimon/format/writer_builder.h"
5547#include " paimon/metrics.h"
5648
5749namespace paimon {
58- class FieldsComparator ;
59- class MemoryPool ;
60- template <typename T>
61- class MergeFunctionWrapper ;
6250class FormatStatsExtractor ;
6351
6452MergeTreeWriter::MergeTreeWriter (
@@ -71,7 +59,6 @@ MergeTreeWriter::MergeTreeWriter(
7159 const CoreOptions& options, const std::shared_ptr<CompactManager>& compact_manager,
7260 const std::shared_ptr<MemoryPool>& pool)
7361 : last_sequence_number_(last_sequence_number + 1 ),
74- current_memory_in_bytes_ (0 ),
7562 pool_ (pool),
7663 trimmed_primary_keys_(trimmed_primary_keys),
7764 options_(options),
@@ -80,10 +67,12 @@ MergeTreeWriter::MergeTreeWriter(
8067 user_defined_seq_comparator_(user_defined_seq_comparator),
8168 merge_function_wrapper_(merge_function_wrapper),
8269 schema_id_(schema_id),
83- value_type_(arrow::struct_(value_schema->fields ())),
8470 compact_manager_(compact_manager),
8571 metrics_(std::make_shared<MetricsImpl>()) {
8672 write_schema_ = SpecialFields::CompleteSequenceAndValueKindField (value_schema);
73+ write_buffer_ = std::make_unique<WriteBuffer>(
74+ arrow::struct_ (value_schema->fields ()), trimmed_primary_keys_,
75+ options_.GetSequenceField (), key_comparator_, merge_function_wrapper_, pool_);
8776}
8877
8978Status MergeTreeWriter::DoClose () {
@@ -114,8 +103,7 @@ Status MergeTreeWriter::DoClose() {
114103 [[maybe_unused]] auto s = options_.GetFileSystem ()->Delete (path_factory_->ToPath (file));
115104 }
116105
117- batch_vec_.clear ();
118- row_kinds_vec_.clear ();
106+ write_buffer_->Clear ();
119107 new_files_.clear ();
120108 deleted_files_.clear ();
121109 compact_before_.clear ();
@@ -129,23 +117,8 @@ Status MergeTreeWriter::DoClose() {
129117}
130118
131119Status MergeTreeWriter::Write (std::unique_ptr<RecordBatch>&& moved_batch) {
132- if (ArrowArrayIsReleased (moved_batch->GetData ())) {
133- return Status::Invalid (" invalid batch: data is released" );
134- }
135- std::unique_ptr<RecordBatch> batch = std::move (moved_batch);
136- PAIMON_ASSIGN_OR_RAISE_FROM_ARROW (std::shared_ptr<arrow::Array> arrow_array,
137- arrow::ImportArray (batch->GetData (), value_type_));
138- auto value_struct_array =
139- arrow::internal::checked_pointer_cast<arrow::StructArray>(arrow_array);
140- if (value_struct_array == nullptr ) {
141- return Status::Invalid (" invalid RecordBatch: cannot cast to StructArray" );
142- }
143- PAIMON_ASSIGN_OR_RAISE (int64_t memory_in_bytes, EstimateMemoryUse (value_struct_array));
144- current_memory_in_bytes_ += memory_in_bytes;
145-
146- batch_vec_.push_back (std::move (value_struct_array));
147- row_kinds_vec_.push_back (batch->GetRowKind ());
148- if (current_memory_in_bytes_ >= options_.GetWriteBufferSize ()) {
120+ PAIMON_RETURN_NOT_OK (write_buffer_->Write (std::move (moved_batch)));
121+ if (write_buffer_->GetMemoryUsage () >= options_.GetWriteBufferSize ()) {
149122 return Flush (/* wait_for_latest_compaction=*/ false , /* forced_full_compaction=*/ false );
150123 }
151124 return Status::OK ();
@@ -247,25 +220,13 @@ Result<bool> MergeTreeWriter::CompactNotCompleted() {
247220}
248221
249222Status MergeTreeWriter::Flush (bool wait_for_latest_compaction, bool forced_full_compaction) {
250- if (!batch_vec_. empty ()) {
223+ if (!write_buffer_-> IsEmpty ()) {
251224 if (compact_manager_->ShouldWaitForLatestCompaction ()) {
252225 wait_for_latest_compaction = true ;
253226 }
254- // 1. create key value iter for each record batch
255- std::vector<std::unique_ptr<KeyValueRecordReader>> readers;
256- readers.reserve (batch_vec_.size ());
257- for (size_t i = 0 ; i < batch_vec_.size (); ++i) {
258- int64_t sequence_number = last_sequence_number_;
259- last_sequence_number_ += batch_vec_[i]->length ();
260- auto in_memory_reader = std::make_unique<KeyValueInMemoryRecordReader>(
261- sequence_number, std::move (batch_vec_[i]), std::move (row_kinds_vec_[i]),
262- trimmed_primary_keys_, options_.GetSequenceField (), key_comparator_,
263- merge_function_wrapper_, pool_);
264- readers.push_back (std::move (in_memory_reader));
265- }
266- batch_vec_.clear ();
267- row_kinds_vec_.clear ();
268- current_memory_in_bytes_ = 0 ;
227+ // 1. flush write buffer to get in-memory readers
228+ PAIMON_ASSIGN_OR_RAISE (std::vector<std::unique_ptr<KeyValueRecordReader>> readers,
229+ write_buffer_->Flush (last_sequence_number_));
269230 // 2. prepare loser tree sort merge reader
270231 auto sort_merge_reader = std::make_unique<SortMergeReaderWithLoserTree>(
271232 std::move (readers), key_comparator_, user_defined_seq_comparator_,
@@ -354,68 +315,4 @@ MergeTreeWriter::CreateRollingRowWriter() const {
354315 options_.GetTargetFileSize (/* has_primary_key=*/ true ), create_file_writer);
355316}
356317
357- Result<int64_t > MergeTreeWriter::EstimateMemoryUse (const std::shared_ptr<arrow::Array>& array) {
358- arrow::Type::type type = array->type ()->id ();
359- int64_t null_bits_size_in_bytes = (array->length () + 7 ) / 8 ;
360- switch (type) {
361- case arrow::Type::type::BOOL :
362- return null_bits_size_in_bytes + array->length () * sizeof (bool );
363- case arrow::Type::type::INT8 :
364- return null_bits_size_in_bytes + array->length () * sizeof (int8_t );
365- case arrow::Type::type::INT16 :
366- return null_bits_size_in_bytes + array->length () * sizeof (int16_t );
367- case arrow::Type::type::INT32 :
368- return null_bits_size_in_bytes + array->length () * sizeof (int32_t );
369- case arrow::Type::type::DATE32 :
370- return null_bits_size_in_bytes + array->length () * sizeof (int32_t );
371- case arrow::Type::type::INT64 :
372- return null_bits_size_in_bytes + array->length () * sizeof (int64_t );
373- case arrow::Type::type::FLOAT :
374- return null_bits_size_in_bytes + array->length () * sizeof (float );
375- case arrow::Type::type::DOUBLE :
376- return null_bits_size_in_bytes + array->length () * sizeof (double );
377- case arrow::Type::type::TIMESTAMP :
378- return null_bits_size_in_bytes + array->length () * sizeof (int64_t );
379- case arrow::Type::type::DECIMAL :
380- return null_bits_size_in_bytes + array->length () * sizeof (Decimal::int128_t );
381- case arrow::Type::type::STRING :
382- case arrow::Type::type::BINARY : {
383- auto binary_array =
384- arrow::internal::checked_cast<const arrow::BinaryArray*>(array.get ());
385- assert (binary_array);
386- int64_t value_length = binary_array->total_values_length ();
387- int64_t offset_length = array->length () * sizeof (int32_t );
388- return null_bits_size_in_bytes + value_length + offset_length;
389- }
390- case arrow::Type::type::LIST : {
391- auto list_array = arrow::internal::checked_cast<const arrow::ListArray*>(array.get ());
392- assert (list_array);
393- PAIMON_ASSIGN_OR_RAISE (int64_t value_mem, EstimateMemoryUse (list_array->values ()));
394- return null_bits_size_in_bytes + value_mem;
395- }
396- case arrow::Type::type::MAP : {
397- auto map_array = arrow::internal::checked_cast<const arrow::MapArray*>(array.get ());
398- assert (map_array);
399- PAIMON_ASSIGN_OR_RAISE (int64_t key_mem, EstimateMemoryUse (map_array->keys ()));
400- PAIMON_ASSIGN_OR_RAISE (int64_t item_mem, EstimateMemoryUse (map_array->items ()));
401- return null_bits_size_in_bytes + key_mem + item_mem;
402- }
403- case arrow::Type::type::STRUCT : {
404- auto struct_array =
405- arrow::internal::checked_cast<const arrow::StructArray*>(array.get ());
406- assert (struct_array);
407- int64_t struct_mem = 0 ;
408- for (const auto & field : struct_array->fields ()) {
409- PAIMON_ASSIGN_OR_RAISE (int64_t field_mem, EstimateMemoryUse (field));
410- struct_mem += field_mem;
411- }
412- return null_bits_size_in_bytes + struct_mem;
413- }
414- default :
415- assert (false );
416- return Status::Invalid (fmt::format (" Do not support type {} in EstimateMemoryUse" ,
417- array->type ()->ToString ()));
418- }
419- }
420-
421318} // namespace paimon
0 commit comments