be/src/load/stream_load/stream_load_context.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/BackendService_types.h> |
21 | | #include <gen_cpp/FrontendService_types.h> |
22 | | #include <gen_cpp/PlanNodes_types.h> |
23 | | #include <gen_cpp/Types_types.h> |
24 | | #include <stddef.h> |
25 | | #include <stdint.h> |
26 | | |
27 | | #include <atomic> |
28 | | #include <condition_variable> |
29 | | #include <future> |
30 | | #include <map> |
31 | | #include <memory> |
32 | | #include <string> |
33 | | #include <utility> |
34 | | #include <vector> |
35 | | |
36 | | #include "common/config.h" |
37 | | #include "common/logging.h" |
38 | | #include "common/status.h" |
39 | | #include "common/utils.h" |
40 | | #include "load/stream_load/stream_load_executor.h" |
41 | | #include "runtime/exec_env.h" |
42 | | #include "runtime/thread_context.h" |
43 | | #include "util/byte_buffer.h" |
44 | | #include "util/time.h" |
45 | | #include "util/uid_util.h" |
46 | | |
47 | | namespace doris { |
48 | | namespace io { |
49 | | class StreamLoadPipe; |
50 | | } // namespace io |
51 | | |
52 | | // kafka related info |
53 | | class KafkaLoadInfo { |
54 | | public: |
55 | | KafkaLoadInfo(const TKafkaLoadInfo& t_info) |
56 | 1 | : brokers(t_info.brokers), |
57 | 1 | topic(t_info.topic), |
58 | 1 | begin_offset(t_info.partition_begin_offset), |
59 | 1 | properties(t_info.properties) { |
60 | | // The offset(begin_offset) sent from FE is the starting offset, |
61 | | // and the offset(cmt_offset) reported by BE to FE is the consumed offset, |
62 | | // so we need to minus 1 here. |
63 | 1 | for (auto& p : t_info.partition_begin_offset) { |
64 | 1 | cmt_offset[p.first] = p.second - 1; |
65 | 1 | } |
66 | 1 | } |
67 | | |
68 | 0 | void reset_offset() { |
69 | 0 | // reset the commit offset |
70 | 0 | for (auto& p : begin_offset) { |
71 | 0 | cmt_offset[p.first] = p.second - 1; |
72 | 0 | } |
73 | 0 | } |
74 | | |
75 | | public: |
76 | | std::string brokers; |
77 | | std::string topic; |
78 | | |
79 | | // the following members control the max progress of a consuming |
80 | | // process. if any of them reach, the consuming will finish. |
81 | | int64_t max_interval_s = 5; |
82 | | int64_t max_batch_rows = 1024; |
83 | | int64_t max_batch_size = 100 * 1024 * 1024; // 100MB |
84 | | |
85 | | // partition -> begin offset, inclusive. |
86 | | std::map<int32_t, int64_t> begin_offset; |
87 | | // partition -> commit offset, inclusive. |
88 | | std::map<int32_t, int64_t> cmt_offset; |
89 | | //custom kafka property key -> value |
90 | | std::map<std::string, std::string> properties; |
91 | | }; |
92 | | |
93 | | // AWS Kinesis related info |
94 | | class KinesisLoadInfo { |
95 | | public: |
96 | | KinesisLoadInfo(const TKinesisLoadInfo& t_info) |
97 | 0 | : region(t_info.region), |
98 | 0 | stream(t_info.stream), |
99 | 0 | endpoint(t_info.__isset.endpoint ? t_info.endpoint : ""), |
100 | 0 | begin_sequence_number(t_info.shard_begin_sequence_number), |
101 | 0 | properties(t_info.__isset.properties ? t_info.properties |
102 | 0 | : std::map<std::string, std::string>()) {} |
103 | | |
104 | 0 | void reset_sequence_numbers() { cmt_sequence_number.clear(); } |
105 | | |
106 | | std::string region; |
107 | | std::string stream; |
108 | | std::string endpoint; // Optional custom endpoint (for LocalStack/VPC) |
109 | | |
110 | | // The following members control the max progress of a consuming process |
111 | | // If any of them reach, the consuming will finish. |
112 | | int64_t max_interval_s = 5; |
113 | | int64_t max_batch_rows = 1024; |
114 | | int64_t max_batch_size = 100 * 1024 * 1024; // 100MB |
115 | | |
116 | | // shard_id -> begin sequence number, inclusive |
117 | | std::map<std::string, std::string> begin_sequence_number; |
118 | | // shard_id -> committed sequence number (last consumed). |
119 | | // This starts empty and is populated only after records are successfully consumed. |
120 | | std::map<std::string, std::string> cmt_sequence_number; |
121 | | // shard_id -> millisBehindLatest from the last GetRecords call |
122 | | std::map<std::string, int64_t> millis_behind_latest; |
123 | | // Set of shard IDs that have been closed (split/merge) during consumption |
124 | | std::set<std::string> closed_shard_ids; |
125 | | // AWS credentials and custom Kinesis properties |
126 | | std::map<std::string, std::string> properties; |
127 | | }; |
128 | | |
129 | | class MessageBodySink; |
130 | | |
131 | | class StreamLoadContext { |
132 | | ENABLE_FACTORY_CREATOR(StreamLoadContext); |
133 | | |
134 | | public: |
135 | 15 | StreamLoadContext(ExecEnv* exec_env) : id(UniqueId::gen_uid()), _exec_env(exec_env) { |
136 | 15 | start_millis = UnixMillis(); |
137 | 15 | _active_contexts.fetch_add(1); |
138 | 15 | } |
139 | | |
140 | 15 | ~StreamLoadContext() { |
141 | 15 | if (need_rollback) { |
142 | 2 | _exec_env->stream_load_executor()->rollback_txn(this); |
143 | 2 | need_rollback = false; |
144 | 2 | } |
145 | 15 | _active_contexts.fetch_sub(1); |
146 | 15 | } |
147 | | |
148 | | // Includes upload, planning, transaction commit/rollback and HTTP reply lifetime, |
149 | | // even when the load has no running fragment or receiver channel yet. |
150 | 8 | static size_t num_active_contexts() { return _active_contexts.load(); } |
151 | | |
152 | | private: |
153 | | inline static std::atomic<size_t> _active_contexts {0}; |
154 | | |
155 | | public: |
156 | | std::string data_saved_path; |
157 | | |
158 | | std::string to_json() const; |
159 | | |
160 | | std::string prepare_stream_load_record(const std::string& stream_load_record); |
161 | | static void parse_stream_load_record(const std::string& stream_load_record, |
162 | | TStreamLoadRecord& stream_load_item); |
163 | | |
164 | | // the old mini load result format is not same as stream load. |
165 | | // add this function for compatible with old mini load result format. |
166 | | std::string to_json_for_mini_load() const; |
167 | | |
168 | | // return the brief info of this context. |
169 | | // also print the load source info if detail is set to true |
170 | | std::string brief(bool detail = false) const; |
171 | | |
172 | | bool is_mow_table() const; |
173 | | bool is_tso_enabled() const; |
174 | | |
175 | 0 | Status allocate_schema_buffer() { |
176 | 0 | if (_schema_buffer == nullptr) { |
177 | 0 | SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER( |
178 | 0 | ExecEnv::GetInstance()->stream_load_pipe_tracker()); |
179 | 0 | return ByteBuffer::allocate(config::stream_tvf_buffer_size, &_schema_buffer); |
180 | 0 | } |
181 | 0 | return Status::OK(); |
182 | 0 | } |
183 | | |
184 | 0 | ByteBufferPtr schema_buffer() { return _schema_buffer; } |
185 | | |
186 | | public: |
187 | | static const int default_txn_id = -1; |
188 | | // load type, eg: ROUTINE LOAD/MANUAL LOAD |
189 | | TLoadType::type load_type = TLoadType::type::MANUL_LOAD; |
190 | | // load data source: eg: KAFKA/RAW |
191 | | TLoadSourceType::type load_src_type; |
192 | | |
193 | | // the job this stream load task belongs to, |
194 | | // set to -1 if there is no job |
195 | | int64_t job_id = -1; |
196 | | |
197 | | // id for each load |
198 | | UniqueId id; |
199 | | |
200 | | std::string db; |
201 | | int64_t db_id = -1; |
202 | | int64_t wal_id = -1; |
203 | | std::string table; |
204 | | int64_t table_id = -1; |
205 | | int64_t schema_version = -1; |
206 | | std::string label; |
207 | | std::string sql_str; |
208 | | // optional |
209 | | std::string sub_label; |
210 | | double max_filter_ratio = 0.0; |
211 | | int32_t timeout_second = -1; |
212 | | AuthInfo auth; |
213 | | bool two_phase_commit = false; |
214 | | std::string load_comment; |
215 | | |
216 | | // the following members control the max progress of a consuming |
217 | | // process. if any of them reach, the consuming will finish. |
218 | | // same as values set in fe/fe-core/src/main/java/org/apache/doris/load/routineload/RoutineLoadJob.java |
219 | | int64_t max_interval_s = 60; |
220 | | int64_t max_batch_rows = 20000000; |
221 | | int64_t max_batch_size = 1024 * 1024 * 1024; // 1GB |
222 | | |
223 | | // for parse json-data |
224 | | std::string data_format = ""; |
225 | | std::string jsonpath_file = ""; |
226 | | std::string jsonpath = ""; |
227 | | |
228 | | // only used to check if we receive whole body |
229 | | size_t body_bytes = 0; |
230 | | size_t receive_bytes = 0; |
231 | | bool is_chunked_transfer = false; |
232 | | |
233 | | int64_t txn_id = default_txn_id; |
234 | | |
235 | | // http stream |
236 | | bool is_read_schema = true; |
237 | | |
238 | | std::string txn_operation = ""; |
239 | | |
240 | | bool need_rollback = false; |
241 | | // when use_streaming is true, we use stream_pipe to send source data, |
242 | | // otherwise we save source data to file first, then process it. |
243 | | bool use_streaming = false; |
244 | | TFileFormatType::type format = TFileFormatType::FORMAT_CSV_PLAIN; |
245 | | TFileCompressType::type compress_type = TFileCompressType::UNKNOWN; |
246 | | bool group_commit = false; |
247 | | std::string group_commit_mode = ""; |
248 | | |
249 | | std::shared_ptr<MessageBodySink> body_sink; |
250 | | std::shared_ptr<io::StreamLoadPipe> pipe; |
251 | | |
252 | | TStreamLoadPutResult put_result; |
253 | | TStreamLoadMultiTablePutResult multi_table_put_result; |
254 | | |
255 | | std::vector<TTabletCommitInfo> commit_infos; |
256 | | |
257 | | std::promise<Status> load_status_promise; |
258 | | std::future<Status> load_status_future = load_status_promise.get_future(); |
259 | | |
260 | | Status status; |
261 | | |
262 | | int64_t number_total_rows = 0; |
263 | | int64_t number_loaded_rows = 0; |
264 | | int64_t number_filtered_rows = 0; |
265 | | int64_t number_unselected_rows = 0; |
266 | | int64_t loaded_bytes = 0; |
267 | | int64_t start_millis = 0; |
268 | | int64_t start_write_data_nanos = 0; |
269 | | int64_t load_cost_millis = 0; |
270 | | int64_t begin_txn_cost_nanos = 0; |
271 | | int64_t stream_load_put_cost_nanos = 0; |
272 | | int64_t commit_and_publish_txn_cost_nanos = 0; |
273 | | int64_t pre_commit_txn_cost_nanos = 0; |
274 | | int64_t read_data_cost_nanos = 0; |
275 | | int64_t write_data_cost_nanos = 0; |
276 | | int64_t receive_and_read_data_cost_nanos = 0; |
277 | | int64_t begin_receive_and_read_data_cost_nanos = 0; |
278 | | |
279 | | std::string error_url = ""; |
280 | | std::string first_error_msg = ""; |
281 | | // if label already be used, set existing job's status here |
282 | | // should be RUNNING or FINISHED |
283 | | std::string existing_job_status = ""; |
284 | | |
285 | | std::unique_ptr<KafkaLoadInfo> kafka_info; |
286 | | std::unique_ptr<KinesisLoadInfo> kinesis_info; |
287 | | |
288 | | // consumer_id is used for data consumer cache key. |
289 | | // to identified a specified data consumer. |
290 | | int64_t consumer_id; |
291 | | |
292 | | // If this is an transactional insert operation, this will be true |
293 | | bool need_commit_self = false; |
294 | | |
295 | | // csv with header type |
296 | | std::string header_type = ""; |
297 | | |
298 | | // is this load single-stream-multi-table? |
299 | | bool is_multi_table = false; |
300 | | |
301 | | // for single-stream-multi-table, we have table list |
302 | | std::vector<std::string> table_list; |
303 | | |
304 | | bool memtable_on_sink_node = false; |
305 | | |
306 | | // use for cloud cluster mode |
307 | | std::string qualified_user; |
308 | | std::string cloud_cluster; |
309 | | |
310 | | // 1. _can_send_reply: Ensure `send_reply` is invoked only after on_header/handle complete, |
311 | | // avoid client errors (e.g., broken pipe). |
312 | | // 2. _finish_send_reply: Prevent duplicate reply sending; skip reply if HTTP request is canceled |
313 | | // due to long import execution time. |
314 | | std::mutex _send_reply_lock; |
315 | | std::condition_variable _can_send_reply_cv; |
316 | | bool _can_send_reply = false; |
317 | | bool _finish_send_reply = false; |
318 | | |
319 | | public: |
320 | 1 | ExecEnv* exec_env() { return _exec_env; } |
321 | | |
322 | | private: |
323 | | ExecEnv* _exec_env = nullptr; |
324 | | ByteBufferPtr _schema_buffer; |
325 | | }; |
326 | | |
327 | | } // namespace doris |