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 |