Coverage Report

Created: 2026-10-23 23:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
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