Coverage Report

Created: 2026-09-02 19:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exec/sink/writer/vfile_result_writer.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <gen_cpp/Types_types.h>
21
#include <gtest/gtest_prod.h>
22
#include <stddef.h>
23
#include <stdint.h>
24
25
#include <cstdint>
26
#include <iosfwd>
27
#include <memory>
28
#include <string>
29
#include <unordered_map>
30
#include <vector>
31
32
#include "common/status.h"
33
#include "core/block/block.h"
34
#include "exec/sink/writer/async_result_writer.h"
35
#include "format/transformer/vfile_format_transformer.h"
36
#include "io/fs/file_writer.h"
37
#include "runtime/descriptors.h"
38
#include "runtime/result_block_buffer.h"
39
#include "runtime/runtime_profile.h"
40
41
namespace doris {
42
class ResultBlockBufferBase;
43
class RuntimeState;
44
45
class GetResultBatchCtx;
46
using MySQLResultBlockBuffer = ResultBlockBuffer<GetResultBatchCtx>;
47
class VExprContext;
48
struct ResultFileOptions;
49
} // namespace doris
50
51
namespace doris {
52
53
// write result to file
54
class VFileResultWriter final : public AsyncResultWriter {
55
public:
56
    VFileResultWriter(const ResultFileOptions* file_option,
57
                      const TStorageBackendType::type storage_type,
58
                      const TUniqueId fragment_instance_id,
59
                      const VExprContextSPtrs& _output_vexpr_ctxs,
60
                      std::shared_ptr<ResultBlockBufferBase> sinker, Block* output_block,
61
                      bool output_object_data, const RowDescriptor& output_row_descriptor,
62
                      std::shared_ptr<Dependency> dep, std::shared_ptr<Dependency> fin_dep);
63
64
    VFileResultWriter(const TDataSink& t_sink, const VExprContextSPtrs& output_exprs,
65
                      std::shared_ptr<Dependency> dep, std::shared_ptr<Dependency> fin_dep);
66
67
    Status write(RuntimeState* state, Block& block) override;
68
69
    Status close(Status exec_status) override;
70
71
    Status open(RuntimeState* state, RuntimeProfile* profile) override;
72
73
    // file result writer always return statistic result in one row
74
0
    int64_t get_written_rows() const override { return 1; }
75
76
0
    void set_header_info(const std::string& header_type, const std::string& header) {
77
0
        _header_type = header_type;
78
0
        _header = header;
79
0
    }
80
81
private:
82
    FRIEND_TEST(VFileResultWriterTest, FailedCloseRemovesClosedOutputFile);
83
    FRIEND_TEST(VFileResultWriterTest, FailedCloseRemovesOnlyOwnedOutputFiles);
84
    FRIEND_TEST(VFileResultWriterTest, LocalOutfilePreservesSynchronousClose);
85
86
    Status _write_file(const Block& block);
87
88
    void _init_profile(RuntimeProfile*);
89
90
    Status _create_file_writer(const std::string& file_name);
91
    Status _create_next_file_writer();
92
    // get next export file name
93
    Status _get_next_file_name(std::string* file_name);
94
    void _get_file_url(std::string* file_url);
95
    std::string _file_format_to_name();
96
    // close file writer, and if !done, it will create new writer for next file.
97
    Status _close_file_writer(bool done);
98
    // create a new file if current file size exceed limit
99
    Status _create_new_file_if_exceed_size();
100
    // send the final statistic result
101
    Status _send_result();
102
    // save result into batch rather than send it
103
    Status _fill_result_block();
104
    // delete the dir of file_path
105
    Status _delete_dir();
106
    Status _cleanup_created_files();
107
    Status _register_created_files_cleanup();
108
    void _record_created_file(int32_t file_system_id,
109
                              std::shared_ptr<doris::io::FileSystem> file_system,
110
                              const doris::io::Path& path);
111
    double _get_write_speed(int64_t write_bytes, int64_t write_time);
112
    std::string _compression_type_to_name();
113
114
private:
115
    RuntimeState* _state; // not owned, set when init
116
    const ResultFileOptions* _file_opts = nullptr;
117
    TStorageBackendType::type _storage_type;
118
    TUniqueId _fragment_instance_id;
119
120
    // If the result file format is plain text, like CSV, this _file_writer is owned by this FileResultWriter.
121
    // If the result file format is Parquet, this _file_writer is owned by _parquet_writer.
122
    std::unique_ptr<doris::io::FileWriter> _file_writer_impl;
123
    std::shared_ptr<doris::io::FileSystem> _file_system;
124
    std::unordered_map<int32_t, std::shared_ptr<doris::io::FileSystem>> _created_file_systems;
125
    std::vector<std::pair<int32_t, doris::io::Path>> _created_files;
126
    // Used to buffer the export data of plain text
127
    // TODO(cmy): I simply use a stringstrteam to buffer the data, to avoid calling
128
    // file writer's write() for every single row.
129
    // But this cannot solve the problem of a row of data that is too large.
130
    // For example: bitmap_to_string() may return large volume of data.
131
    // And the speed is relative low, in my test, is about 6.5MB/s.
132
    std::stringstream _plain_text_outstream;
133
134
    // current written bytes, used for split data
135
    int64_t _current_written_bytes = 0;
136
    // the suffix idx of export file name, start at 0
137
    int _file_idx = 0;
138
139
    // total time cost on append batch operation
140
    RuntimeProfile::Counter* _append_row_batch_timer = nullptr;
141
    // tuple convert timer, child timer of _append_row_batch_timer
142
    RuntimeProfile::Counter* _convert_tuple_timer = nullptr;
143
    // file write timer, child timer of _append_row_batch_timer
144
    RuntimeProfile::Counter* _file_write_timer = nullptr;
145
    // time of closing the file writer
146
    RuntimeProfile::Counter* _writer_close_timer = nullptr;
147
    // number of written rows
148
    RuntimeProfile::Counter* _written_rows_counter = nullptr;
149
    // bytes of written data
150
    RuntimeProfile::Counter* _written_data_bytes = nullptr;
151
152
    // _sinker and _output_batch are not owned by FileResultWriter
153
    std::shared_ptr<MySQLResultBlockBuffer> _sinker = nullptr;
154
    Block* _output_block = nullptr;
155
    // set to true if the final statistic result is sent
156
    bool _is_result_sent = false;
157
    RowDescriptor _output_row_descriptor;
158
    // convert block to parquet/orc/csv fomrat
159
    std::unique_ptr<VFileFormatTransformer> _vfile_writer;
160
161
    std::string_view _header_type;
162
    std::string_view _header;
163
};
164
} // namespace doris