1616
1717#include " paimon/core/io/rolling_blob_file_writer.h"
1818
19+ #include < map>
1920#include < memory>
2021#include < string>
2122#include < utility>
2728#include " arrow/c/bridge.h"
2829#include " arrow/c/helpers.h"
2930#include " fmt/format.h"
30- #include " fmt/ranges.h"
3131#include " paimon/common/data/blob_utils.h"
3232#include " paimon/common/utils/arrow/status_utils.h"
3333#include " paimon/common/utils/scope_guard.h"
@@ -55,7 +55,7 @@ RollingBlobFileWriter::RollingBlobFileWriter(
5555Status RollingBlobFileWriter::Write (::ArrowArray* record) {
5656 ScopeGuard guard ([this ]() -> void { this ->Abort (); });
5757 // Open the current writer if write the first record or roll over happen before.
58- if (PAIMON_UNLIKELY (current_writer_ == nullptr )) {
58+ if (writer_factory_ != nullptr && PAIMON_UNLIKELY (current_writer_ == nullptr )) {
5959 PAIMON_RETURN_NOT_OK (OpenCurrentWriter ());
6060 }
6161 if (PAIMON_UNLIKELY (blob_writer_ == nullptr )) {
@@ -69,12 +69,14 @@ Status RollingBlobFileWriter::Write(::ArrowArray* record) {
6969 PAIMON_ASSIGN_OR_RAISE (BlobUtils::SeparatedStructArrays separated_arrays,
7070 BlobUtils::SeparateBlobArray (struct_array, inline_fields_));
7171 // Write main (non-blob) data
72- ::ArrowArray c_main_array;
73- PAIMON_RETURN_NOT_OK_FROM_ARROW (
74- arrow::ExportArray (*separated_arrays.main_array , &c_main_array));
75- ScopeGuard array_lifecycle_guard (
76- [&c_main_array]() -> void { ArrowArrayRelease (&c_main_array); });
77- PAIMON_RETURN_NOT_OK (current_writer_->Write (&c_main_array));
72+ if (current_writer_ != nullptr ) {
73+ ::ArrowArray c_main_array;
74+ PAIMON_RETURN_NOT_OK_FROM_ARROW (
75+ arrow::ExportArray (*separated_arrays.main_array , &c_main_array));
76+ ScopeGuard array_lifecycle_guard (
77+ [&c_main_array]() -> void { ArrowArrayRelease (&c_main_array); });
78+ PAIMON_RETURN_NOT_OK (current_writer_->Write (&c_main_array));
79+ }
7880
7981 // Write blob data via MultipleBlobFileWriter (each blob field independently)
8082 ::ArrowArray c_blob_array;
@@ -84,28 +86,31 @@ Status RollingBlobFileWriter::Write(::ArrowArray* record) {
8486 PAIMON_RETURN_NOT_OK (blob_writer_->Write (&c_blob_array));
8587
8688 record_count_ += record_count;
87- PAIMON_ASSIGN_OR_RAISE (bool need_rolling_file, NeedRollingFile ());
88- if (need_rolling_file) {
89- PAIMON_RETURN_NOT_OK (CloseCurrentWriter ());
89+ if (current_writer_ != nullptr ) {
90+ PAIMON_ASSIGN_OR_RAISE (bool need_rolling_file, NeedRollingFile ());
91+ if (need_rolling_file) {
92+ PAIMON_RETURN_NOT_OK (CloseCurrentWriter ());
93+ }
9094 }
9195 guard.Release ();
9296 return Status::OK ();
9397}
9498
9599Status RollingBlobFileWriter::CloseCurrentWriter () {
96- if (current_writer_ == nullptr ) {
97- return Status::OK ();
98- }
99100 if (blob_writer_ == nullptr ) {
100101 return Status::OK ();
101102 }
102- PAIMON_ASSIGN_OR_RAISE (std::shared_ptr<DataFileMeta> main_data_file_meta, CloseMainWriter ());
103+ std::shared_ptr<DataFileMeta> main_data_file_meta;
104+ if (current_writer_ != nullptr ) {
105+ PAIMON_ASSIGN_OR_RAISE (main_data_file_meta, CloseMainWriter ());
106+ }
103107 PAIMON_ASSIGN_OR_RAISE (std::vector<std::shared_ptr<DataFileMeta>> blob_metas,
104108 CloseBlobWriter ());
105- PAIMON_RETURN_NOT_OK (
106- ValidateFileConsistency (main_data_file_meta, blob_metas, blob_schema_->num_fields ()));
107109
108- results_.push_back (main_data_file_meta);
110+ if (main_data_file_meta != nullptr ) {
111+ PAIMON_RETURN_NOT_OK (ValidateFileConsistency (main_data_file_meta, blob_metas));
112+ results_.push_back (main_data_file_meta);
113+ }
109114 results_.insert (results_.end (), blob_metas.begin (), blob_metas.end ());
110115
111116 current_writer_.reset ();
@@ -137,29 +142,25 @@ Result<std::vector<std::shared_ptr<DataFileMeta>>> RollingBlobFileWriter::CloseB
137142
138143Status RollingBlobFileWriter::ValidateFileConsistency (
139144 const std::shared_ptr<DataFileMeta>& main_data_file_meta,
140- const std::vector<std::shared_ptr<DataFileMeta>>& blob_tagged_metas, int32_t blob_field_count) {
141- if (blob_tagged_metas.empty ()) {
142- return Status::OK ();
143- }
144- // With multiple blob fields, each blob field produces its own set of files.
145- // total_blob_row_count should be exactly main_row_count * blob_field_count.
146- int64_t main_row_count = main_data_file_meta->row_count ;
147- int64_t expected_blob_row_count = main_row_count * blob_field_count;
148- int64_t total_blob_row_count = 0 ;
145+ const std::vector<std::shared_ptr<DataFileMeta>>& blob_tagged_metas) {
146+ std::map<std::string, int64_t > blob_field_row_counts;
149147 for (const auto & blob_tagged_meta : blob_tagged_metas) {
150- total_blob_row_count += blob_tagged_meta->row_count ;
148+ if (!blob_tagged_meta->write_cols || blob_tagged_meta->write_cols ->empty ()) {
149+ return Status::Invalid (
150+ fmt::format (" This is a bug: Blob file {} must contain a write column." ,
151+ blob_tagged_meta->file_name ));
152+ }
153+ blob_field_row_counts[blob_tagged_meta->write_cols ->at (0 )] += blob_tagged_meta->row_count ;
151154 }
152- if (total_blob_row_count != expected_blob_row_count) {
153- std::vector<std::string> blob_file_names;
154- for (const auto & blob_tagged_meta : blob_tagged_metas) {
155- blob_file_names.push_back (blob_tagged_meta->file_name );
155+
156+ int64_t main_row_count = main_data_file_meta->row_count ;
157+ for (const auto & [field_name, row_count] : blob_field_row_counts) {
158+ if (row_count != main_row_count) {
159+ return Status::Invalid (fmt::format (
160+ " This is a bug: The row count of main file and blob file does not match. Main "
161+ " file: {} (row count: {}), blob field name: {} (row count: {})" ,
162+ main_data_file_meta->file_name , main_row_count, field_name, row_count));
156163 }
157- return Status::Invalid (fmt::format (
158- " This is a bug: The row count of main file and blob files does not match. "
159- " Main file: {} (row count: {}), blob field count: {}, "
160- " expected blob row count: {}, blob files: {} (actual total row count: {})" ,
161- main_data_file_meta->file_name , main_row_count, blob_field_count,
162- expected_blob_row_count, fmt::join (blob_file_names, " , " ), total_blob_row_count));
163164 }
164165 return Status::OK ();
165166}
0 commit comments