Coverage Report

Created: 2026-04-14 10:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/service/internal_service.cpp
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
#include "service/internal_service.h"
19
20
#include <assert.h>
21
#include <brpc/closure_guard.h>
22
#include <brpc/controller.h>
23
#include <bthread/bthread.h>
24
#include <bthread/types.h>
25
#include <butil/errno.h>
26
#include <butil/iobuf.h>
27
#include <fcntl.h>
28
#include <fmt/core.h>
29
#include <gen_cpp/DataSinks_types.h>
30
#include <gen_cpp/MasterService_types.h>
31
#include <gen_cpp/PaloInternalService_types.h>
32
#include <gen_cpp/PlanNodes_types.h>
33
#include <gen_cpp/Status_types.h>
34
#include <gen_cpp/Types_types.h>
35
#include <gen_cpp/internal_service.pb.h>
36
#include <gen_cpp/olap_file.pb.h>
37
#include <gen_cpp/segment_v2.pb.h>
38
#include <gen_cpp/types.pb.h>
39
#include <google/protobuf/stubs/callback.h>
40
#include <stddef.h>
41
#include <stdint.h>
42
#include <sys/stat.h>
43
44
#include <algorithm>
45
#include <exception>
46
#include <filesystem>
47
#include <memory>
48
#include <set>
49
#include <sstream>
50
#include <string>
51
#include <utility>
52
#include <vector>
53
54
#include "cloud/cloud_storage_engine.h"
55
#include "cloud/cloud_tablet_mgr.h"
56
#include "cloud/config.h"
57
#include "common/config.h"
58
#include "common/exception.h"
59
#include "common/logging.h"
60
#include "common/metrics/doris_metrics.h"
61
#include "common/metrics/metrics.h"
62
#include "common/signal_handler.h"
63
#include "common/status.h"
64
#include "core/block/block.h"
65
#include "core/data_type/data_type.h"
66
#include "exec/common/variant_util.h"
67
#include "exec/exchange/vdata_stream_mgr.h"
68
#include "exec/rowid_fetcher.h"
69
#include "exec/sink/writer/varrow_flight_result_writer.h"
70
#include "exec/sink/writer/vmysql_result_writer.h"
71
#include "exprs/function/dictionary_factory.h"
72
#include "format/arrow/arrow_row_batch.h"
73
#include "format/csv/csv_reader.h"
74
#include "format/generic_reader.h"
75
#include "format/jni/jni_reader.h"
76
#include "format/json/new_json_reader.h"
77
#include "format/native/native_reader.h"
78
#include "format/orc/vorc_reader.h"
79
#include "format/parquet/vparquet_reader.h"
80
#include "format/text/text_reader.h"
81
#include "io/fs/local_file_system.h"
82
#include "io/fs/stream_load_pipe.h"
83
#include "io/io_common.h"
84
#include "load/channel/load_channel_mgr.h"
85
#include "load/channel/load_stream_mgr.h"
86
#include "load/delta_writer/delta_writer.h"
87
#include "load/group_commit/wal/wal_manager.h"
88
#include "load/routine_load/routine_load_task_executor.h"
89
#include "load/stream_load/new_load_stream_mgr.h"
90
#include "load/stream_load/stream_load_context.h"
91
#include "runtime/cache/result_cache.h"
92
#include "runtime/cdc_client_mgr.h"
93
#include "runtime/descriptors.h"
94
#include "runtime/exec_env.h"
95
#include "runtime/fold_constant_executor.h"
96
#include "runtime/fragment_mgr.h"
97
#include "runtime/result_block_buffer.h"
98
#include "runtime/result_buffer_mgr.h"
99
#include "runtime/runtime_profile.h"
100
#include "runtime/thread_context.h"
101
#include "runtime/workload_group/workload_group.h"
102
#include "runtime/workload_group/workload_group_manager.h"
103
#include "service/backend_options.h"
104
#include "service/http/http_client.h"
105
#include "service/point_query_executor.h"
106
#include "storage/data_dir.h"
107
#include "storage/index/inverted/inverted_index_desc.h"
108
#include "storage/olap_common.h"
109
#include "storage/olap_define.h"
110
#include "storage/rowset/beta_rowset.h"
111
#include "storage/rowset/rowset.h"
112
#include "storage/rowset/rowset_factory.h"
113
#include "storage/rowset/rowset_meta.h"
114
#include "storage/segment/column_reader.h"
115
#include "storage/storage_engine.h"
116
#include "storage/tablet/tablet_fwd.h"
117
#include "storage/tablet/tablet_manager.h"
118
#include "storage/tablet/tablet_schema.h"
119
#include "storage/txn/txn_manager.h"
120
#include "util/async_io.h"
121
#include "util/brpc_client_cache.h"
122
#include "util/brpc_closure.h"
123
#include "util/jdbc_utils.h"
124
#include "util/jsonb/serialize.h"
125
#include "util/md5.h"
126
#include "util/network_util.h"
127
#include "util/proto_util.h"
128
#include "util/stopwatch.hpp"
129
#include "util/string_util.h"
130
#include "util/thrift_util.h"
131
#include "util/time.h"
132
#include "util/uid_util.h"
133
134
namespace google {
135
namespace protobuf {
136
class RpcController;
137
} // namespace protobuf
138
} // namespace google
139
140
namespace doris {
141
#include "common/compile_check_avoid_begin.h"
142
using namespace ErrorCode;
143
144
const uint32_t DOWNLOAD_FILE_MAX_RETRY = 3;
145
146
DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(heavy_work_pool_queue_size, MetricUnit::NOUNIT);
147
DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(light_work_pool_queue_size, MetricUnit::NOUNIT);
148
DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(heavy_work_active_threads, MetricUnit::NOUNIT);
149
DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(light_work_active_threads, MetricUnit::NOUNIT);
150
151
DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(heavy_work_pool_max_queue_size, MetricUnit::NOUNIT);
152
DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(light_work_pool_max_queue_size, MetricUnit::NOUNIT);
153
DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(heavy_work_max_threads, MetricUnit::NOUNIT);
154
DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(light_work_max_threads, MetricUnit::NOUNIT);
155
156
DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(arrow_flight_work_pool_queue_size, MetricUnit::NOUNIT);
157
DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(arrow_flight_work_active_threads, MetricUnit::NOUNIT);
158
DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(arrow_flight_work_pool_max_queue_size, MetricUnit::NOUNIT);
159
DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(arrow_flight_work_max_threads, MetricUnit::NOUNIT);
160
161
static bvar::LatencyRecorder g_process_remote_fetch_rowsets_latency("process_remote_fetch_rowsets");
162
163
bthread_key_t btls_key;
164
165
2.92M
static void thread_context_deleter(void* d) {
166
2.92M
    delete static_cast<ThreadContext*>(d);
167
2.92M
}
168
169
template <typename T>
170
concept CanCancel = requires(T* response) { response->mutable_status(); };
171
172
template <typename T>
173
0
void offer_failed(T* response, google::protobuf::Closure* done, const FifoThreadPool& pool) {
174
0
    brpc::ClosureGuard closure_guard(done);
175
0
    LOG(WARNING) << "fail to offer request to the work pool, pool=" << pool.get_info();
176
0
}
Unexecuted instantiation: _ZN5doris12offer_failedINS_25PTabletWriterCancelResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedINS_14PCacheResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedINS_17PFetchCacheResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
177
178
template <CanCancel T>
179
0
void offer_failed(T* response, google::protobuf::Closure* done, const FifoThreadPool& pool) {
180
0
    brpc::ClosureGuard closure_guard(done);
181
    // Should use status to generate protobuf message, because it will encoding Backend Info
182
    // into the error message and then we could know which backend's pool is full.
183
0
    Status st = Status::Error<TStatusCode::CANCELLED>(
184
0
            "fail to offer request to the work pool, pool={}", pool.get_info());
185
0
    st.to_protobuf(response->mutable_status());
186
0
    LOG(WARNING) << "cancelled due to fail to offer request to the work pool, pool="
187
0
                 << pool.get_info();
188
0
}
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_23PTabletWriterOpenResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_23PExecPlanFragmentResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_23POpenLoadStreamResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_27PTabletWriterAddBlockResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_25PCancelPlanFragmentResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_21PFetchArrowDataResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_26POutfileWriteSuccessResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_23PFetchTableSchemaResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_29PFetchArrowFlightSchemaResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_24PTabletKeyLookupResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_25PJdbcTestConnectionResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_20PFetchColIdsResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_26PFetchRemoteSchemaResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_12PProxyResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_20PMergeFilterResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_23PSendFilterSizeResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_23PSyncFilterSizeResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_22PPublishFilterResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_15PSendDataResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_13PCommitResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_15PRollbackResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_19PConstantExprResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_26PTransmitRecCTEBlockResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_20PRerunFragmentResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_20PResetGlobalRfResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_19PTransmitDataResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_24PCheckRPCChannelResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_24PResetRPCChannelResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_23PTabletWriteSlaveResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_27PTabletWriteSlaveDoneResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_17PMultiGetResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_13PGlobResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_26PGroupCommitInsertResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_24PGetWalQueueSizeResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_22PGetBeResourceResponseEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
Unexecuted instantiation: _ZN5doris12offer_failedITkNS_9CanCancelENS_23PRequestCdcClientResultEEEvPT_PN6google8protobuf7ClosureERKNS_14WorkThreadPoolILb0EEE
189
190
template <typename T>
191
class NewHttpClosure : public ::google::protobuf::Closure {
192
public:
193
    NewHttpClosure(google::protobuf::Closure* done) : _done(done) {}
194
0
    NewHttpClosure(T* request, google::protobuf::Closure* done) : _request(request), _done(done) {}
Unexecuted instantiation: _ZN5doris14NewHttpClosureINS_28PTabletWriterAddBlockRequestEEC2EPS1_PN6google8protobuf7ClosureE
Unexecuted instantiation: _ZN5doris14NewHttpClosureINS_19PTransmitDataParamsEEC2EPS1_PN6google8protobuf7ClosureE
195
196
0
    void Run() override {
197
0
        if (_request != nullptr) {
198
0
            delete _request;
199
0
            _request = nullptr;
200
0
        }
201
0
        if (_done != nullptr) {
202
0
            _done->Run();
203
0
        }
204
0
        delete this;
205
0
    }
Unexecuted instantiation: _ZN5doris14NewHttpClosureINS_28PTabletWriterAddBlockRequestEE3RunEv
Unexecuted instantiation: _ZN5doris14NewHttpClosureINS_19PTransmitDataParamsEE3RunEv
206
207
private:
208
    T* _request = nullptr;
209
    google::protobuf::Closure* _done = nullptr;
210
};
211
212
PInternalService::PInternalService(ExecEnv* exec_env)
213
7
        : _exec_env(exec_env),
214
          // heavy threadpool is used for load process and other process that will read disk or access network.
215
7
          _heavy_work_pool(config::brpc_heavy_work_pool_threads != -1
216
7
                                   ? config::brpc_heavy_work_pool_threads
217
7
                                   : std::max(128, CpuInfo::num_cores() * 4),
218
7
                           config::brpc_heavy_work_pool_max_queue_size != -1
219
7
                                   ? config::brpc_heavy_work_pool_max_queue_size
220
7
                                   : std::max(10240, CpuInfo::num_cores() * 320),
221
7
                           "brpc_heavy"),
222
223
          // light threadpool should be only used in query processing logic. All hanlers should be very light, not locked, not access disk.
224
7
          _light_work_pool(config::brpc_light_work_pool_threads != -1
225
7
                                   ? config::brpc_light_work_pool_threads
226
7
                                   : std::max(128, CpuInfo::num_cores() * 4),
227
7
                           config::brpc_light_work_pool_max_queue_size != -1
228
7
                                   ? config::brpc_light_work_pool_max_queue_size
229
7
                                   : std::max(10240, CpuInfo::num_cores() * 320),
230
7
                           "brpc_light"),
231
7
          _arrow_flight_work_pool(config::brpc_arrow_flight_work_pool_threads != -1
232
7
                                          ? config::brpc_arrow_flight_work_pool_threads
233
7
                                          : std::max(512, CpuInfo::num_cores() * 2),
234
7
                                  config::brpc_arrow_flight_work_pool_max_queue_size != -1
235
7
                                          ? config::brpc_arrow_flight_work_pool_max_queue_size
236
7
                                          : std::max(20480, CpuInfo::num_cores() * 640),
237
7
                                  "brpc_arrow_flight") {
238
7
    REGISTER_HOOK_METRIC(heavy_work_pool_queue_size,
239
7
                         [this]() { return _heavy_work_pool.get_queue_size(); });
240
7
    REGISTER_HOOK_METRIC(light_work_pool_queue_size,
241
7
                         [this]() { return _light_work_pool.get_queue_size(); });
242
7
    REGISTER_HOOK_METRIC(heavy_work_active_threads,
243
7
                         [this]() { return _heavy_work_pool.get_active_threads(); });
244
7
    REGISTER_HOOK_METRIC(light_work_active_threads,
245
7
                         [this]() { return _light_work_pool.get_active_threads(); });
246
247
7
    REGISTER_HOOK_METRIC(heavy_work_pool_max_queue_size,
248
7
                         []() { return config::brpc_heavy_work_pool_max_queue_size; });
249
7
    REGISTER_HOOK_METRIC(light_work_pool_max_queue_size,
250
7
                         []() { return config::brpc_light_work_pool_max_queue_size; });
251
7
    REGISTER_HOOK_METRIC(heavy_work_max_threads,
252
7
                         []() { return config::brpc_heavy_work_pool_threads; });
253
7
    REGISTER_HOOK_METRIC(light_work_max_threads,
254
7
                         []() { return config::brpc_light_work_pool_threads; });
255
256
7
    REGISTER_HOOK_METRIC(arrow_flight_work_pool_queue_size,
257
7
                         [this]() { return _arrow_flight_work_pool.get_queue_size(); });
258
7
    REGISTER_HOOK_METRIC(arrow_flight_work_active_threads,
259
7
                         [this]() { return _arrow_flight_work_pool.get_active_threads(); });
260
7
    REGISTER_HOOK_METRIC(arrow_flight_work_pool_max_queue_size,
261
7
                         []() { return config::brpc_arrow_flight_work_pool_max_queue_size; });
262
7
    REGISTER_HOOK_METRIC(arrow_flight_work_max_threads,
263
7
                         []() { return config::brpc_arrow_flight_work_pool_threads; });
264
265
7
    _exec_env->load_stream_mgr()->set_heavy_work_pool(&_heavy_work_pool);
266
267
7
    CHECK_EQ(0, bthread_key_create(&btls_key, thread_context_deleter));
268
7
    CHECK_EQ(0, bthread_key_create(&AsyncIO::btls_io_ctx_key, AsyncIO::io_ctx_key_deleter));
269
7
}
270
271
PInternalServiceImpl::PInternalServiceImpl(StorageEngine& engine, ExecEnv* exec_env)
272
6
        : PInternalService(exec_env), _engine(engine) {}
273
274
3
PInternalServiceImpl::~PInternalServiceImpl() = default;
275
276
3
PInternalService::~PInternalService() {
277
3
    DEREGISTER_HOOK_METRIC(heavy_work_pool_queue_size);
278
3
    DEREGISTER_HOOK_METRIC(light_work_pool_queue_size);
279
3
    DEREGISTER_HOOK_METRIC(heavy_work_active_threads);
280
3
    DEREGISTER_HOOK_METRIC(light_work_active_threads);
281
282
3
    DEREGISTER_HOOK_METRIC(heavy_work_pool_max_queue_size);
283
3
    DEREGISTER_HOOK_METRIC(light_work_pool_max_queue_size);
284
3
    DEREGISTER_HOOK_METRIC(heavy_work_max_threads);
285
3
    DEREGISTER_HOOK_METRIC(light_work_max_threads);
286
287
3
    DEREGISTER_HOOK_METRIC(arrow_flight_work_pool_queue_size);
288
3
    DEREGISTER_HOOK_METRIC(arrow_flight_work_active_threads);
289
3
    DEREGISTER_HOOK_METRIC(arrow_flight_work_pool_max_queue_size);
290
3
    DEREGISTER_HOOK_METRIC(arrow_flight_work_max_threads);
291
292
3
    CHECK_EQ(0, bthread_key_delete(btls_key));
293
3
    CHECK_EQ(0, bthread_key_delete(AsyncIO::btls_io_ctx_key));
294
3
}
295
296
void PInternalService::tablet_writer_open(google::protobuf::RpcController* controller,
297
                                          const PTabletWriterOpenRequest* request,
298
                                          PTabletWriterOpenResult* response,
299
55.9k
                                          google::protobuf::Closure* done) {
300
56.1k
    bool ret = _heavy_work_pool.try_offer([this, request, response, done]() {
301
56.1k
        VLOG_RPC << "tablet writer open, id=" << request->id()
302
1
                 << ", index_id=" << request->index_id() << ", txn_id=" << request->txn_id();
303
56.1k
        signal::SignalTaskIdKeeper keeper(request->id());
304
56.1k
        brpc::ClosureGuard closure_guard(done);
305
56.1k
        auto st = _exec_env->load_channel_mgr()->open(*request);
306
56.1k
        if (!st.ok()) {
307
0
            LOG(WARNING) << "load channel open failed, message=" << st << ", id=" << request->id()
308
0
                         << ", index_id=" << request->index_id()
309
0
                         << ", txn_id=" << request->txn_id();
310
0
        }
311
56.1k
        st.to_protobuf(response->mutable_status());
312
56.1k
    });
313
55.9k
    if (!ret) {
314
0
        offer_failed(response, done, _heavy_work_pool);
315
0
        return;
316
0
    }
317
55.9k
}
318
319
void PInternalService::exec_plan_fragment(google::protobuf::RpcController* controller,
320
                                          const PExecPlanFragmentRequest* request,
321
                                          PExecPlanFragmentResult* response,
322
167k
                                          google::protobuf::Closure* done) {
323
167k
    timeval tv {};
324
167k
    gettimeofday(&tv, nullptr);
325
167k
    response->set_received_time(tv.tv_sec * 1000LL + tv.tv_usec / 1000);
326
167k
    bool ret = _light_work_pool.try_offer([this, controller, request, response, done]() {
327
167k
        _exec_plan_fragment_in_pthread(controller, request, response, done);
328
167k
    });
329
167k
    if (!ret) {
330
0
        offer_failed(response, done, _light_work_pool);
331
0
        return;
332
0
    }
333
167k
}
334
335
void PInternalService::_exec_plan_fragment_in_pthread(google::protobuf::RpcController* controller,
336
                                                      const PExecPlanFragmentRequest* request,
337
                                                      PExecPlanFragmentResult* response,
338
283k
                                                      google::protobuf::Closure* done) {
339
283k
    timeval tv1 {};
340
283k
    gettimeofday(&tv1, nullptr);
341
283k
    response->set_execution_time(tv1.tv_sec * 1000LL + tv1.tv_usec / 1000);
342
283k
    brpc::ClosureGuard closure_guard(done);
343
283k
    auto st = Status::OK();
344
18.4E
    bool compact = request->has_compact() ? request->compact() : false;
345
283k
    PFragmentRequestVersion version =
346
18.4E
            request->has_version() ? request->version() : PFragmentRequestVersion::VERSION_1;
347
283k
    try {
348
283k
        st = _exec_plan_fragment_impl(request->request(), version, compact);
349
283k
    } catch (const Exception& e) {
350
0
        st = e.to_status();
351
0
    } catch (const std::exception& e) {
352
0
        st = Status::Error(ErrorCode::INTERNAL_ERROR, e.what());
353
0
    } catch (...) {
354
0
        st = Status::Error(ErrorCode::INTERNAL_ERROR,
355
0
                           "_exec_plan_fragment_impl meet unknown error");
356
0
    }
357
283k
    if (!st.ok()) {
358
1.20k
        LOG(WARNING) << "exec plan fragment failed, errmsg=" << st;
359
1.20k
    }
360
283k
    st.to_protobuf(response->mutable_status());
361
283k
    timeval tv2 {};
362
283k
    gettimeofday(&tv2, nullptr);
363
283k
    response->set_execution_done_time(tv2.tv_sec * 1000LL + tv2.tv_usec / 1000);
364
283k
}
365
366
void PInternalService::exec_plan_fragment_prepare(google::protobuf::RpcController* controller,
367
                                                  const PExecPlanFragmentRequest* request,
368
                                                  PExecPlanFragmentResult* response,
369
116k
                                                  google::protobuf::Closure* done) {
370
116k
    timeval tv {};
371
116k
    gettimeofday(&tv, nullptr);
372
116k
    response->set_received_time(tv.tv_sec * 1000LL + tv.tv_usec / 1000);
373
116k
    bool ret = _light_work_pool.try_offer([this, controller, request, response, done]() {
374
116k
        _exec_plan_fragment_in_pthread(controller, request, response, done);
375
116k
    });
376
116k
    if (!ret) {
377
0
        offer_failed(response, done, _light_work_pool);
378
0
        return;
379
0
    }
380
116k
}
381
382
void PInternalService::exec_plan_fragment_start(google::protobuf::RpcController* /*controller*/,
383
                                                const PExecPlanFragmentStartRequest* request,
384
                                                PExecPlanFragmentResult* result,
385
116k
                                                google::protobuf::Closure* done) {
386
116k
    timeval tv {};
387
116k
    gettimeofday(&tv, nullptr);
388
116k
    result->set_received_time(tv.tv_sec * 1000LL + tv.tv_usec / 1000);
389
116k
    bool ret = _light_work_pool.try_offer([this, request, result, done]() {
390
116k
        timeval tv1 {};
391
116k
        gettimeofday(&tv1, nullptr);
392
116k
        result->set_execution_time(tv1.tv_sec * 1000LL + tv1.tv_usec / 1000);
393
116k
        brpc::ClosureGuard closure_guard(done);
394
116k
        auto st = _exec_env->fragment_mgr()->start_query_execution(request);
395
116k
        st.to_protobuf(result->mutable_status());
396
116k
        timeval tv2 {};
397
116k
        gettimeofday(&tv2, nullptr);
398
116k
        result->set_execution_done_time(tv2.tv_sec * 1000LL + tv2.tv_usec / 1000);
399
116k
    });
400
116k
    if (!ret) {
401
0
        offer_failed(result, done, _light_work_pool);
402
0
        return;
403
0
    }
404
116k
}
405
406
void PInternalService::open_load_stream(google::protobuf::RpcController* controller,
407
                                        const POpenLoadStreamRequest* request,
408
                                        POpenLoadStreamResponse* response,
409
3.98k
                                        google::protobuf::Closure* done) {
410
3.98k
    bool ret = _heavy_work_pool.try_offer([this, controller, request, response, done]() {
411
3.98k
        signal::SignalTaskIdKeeper keeper(request->load_id());
412
3.98k
        brpc::ClosureGuard done_guard(done);
413
3.98k
        brpc::Controller* cntl = static_cast<brpc::Controller*>(controller);
414
3.98k
        brpc::StreamOptions stream_options;
415
416
3.98k
        LOG(INFO) << "open load stream, load_id=" << request->load_id()
417
3.98k
                  << ", src_id=" << request->src_id();
418
419
3.98k
        std::vector<BaseTabletSPtr> tablets;
420
3.98k
        for (const auto& req : request->tablets()) {
421
2.04k
            BaseTabletSPtr tablet;
422
2.04k
            if (auto res = ExecEnv::get_tablet(req.tablet_id()); !res.has_value()) [[unlikely]] {
423
0
                auto st = std::move(res).error();
424
0
                st.to_protobuf(response->mutable_status());
425
0
                cntl->SetFailed(st.to_string());
426
0
                return;
427
2.04k
            } else {
428
2.04k
                tablet = std::move(res).value();
429
2.04k
            }
430
2.04k
            auto resp = response->add_tablet_schemas();
431
2.04k
            resp->set_index_id(req.index_id());
432
2.04k
            resp->set_enable_unique_key_merge_on_write(tablet->enable_unique_key_merge_on_write());
433
2.04k
            tablet->tablet_schema()->to_schema_pb(resp->mutable_tablet_schema());
434
2.04k
            tablets.push_back(tablet);
435
2.04k
        }
436
3.98k
        if (!tablets.empty()) {
437
2.04k
            auto* tablet_load_infos = response->mutable_tablet_load_rowset_num_infos();
438
2.04k
            for (const auto& tablet : tablets) {
439
2.04k
                BaseDeltaWriter::collect_tablet_load_rowset_num_info(tablet.get(),
440
2.04k
                                                                     tablet_load_infos);
441
2.04k
            }
442
2.04k
        }
443
444
3.98k
        LoadStream* load_stream = nullptr;
445
3.98k
        auto st = _exec_env->load_stream_mgr()->open_load_stream(request, load_stream);
446
3.98k
        if (!st.ok()) {
447
0
            st.to_protobuf(response->mutable_status());
448
0
            return;
449
0
        }
450
451
3.98k
        stream_options.handler = load_stream;
452
3.98k
        stream_options.idle_timeout_ms = request->idle_timeout_ms();
453
3.98k
        DBUG_EXECUTE_IF("PInternalServiceImpl.open_load_stream.set_idle_timeout",
454
3.98k
                        { stream_options.idle_timeout_ms = 1; });
455
456
3.98k
        StreamId streamid;
457
3.98k
        if (brpc::StreamAccept(&streamid, *cntl, &stream_options) != 0) {
458
0
            st = Status::Cancelled("Fail to accept stream {}", streamid);
459
0
            st.to_protobuf(response->mutable_status());
460
0
            cntl->SetFailed(st.to_string());
461
0
            return;
462
0
        }
463
464
3.98k
        VLOG_DEBUG << "get streamid =" << streamid;
465
3.98k
        st.to_protobuf(response->mutable_status());
466
3.98k
    });
467
3.98k
    if (!ret) {
468
0
        offer_failed(response, done, _heavy_work_pool);
469
0
    }
470
3.98k
}
471
472
void PInternalService::tablet_writer_add_block_by_http(google::protobuf::RpcController* controller,
473
                                                       const ::doris::PEmptyRequest* request,
474
                                                       PTabletWriterAddBlockResult* response,
475
0
                                                       google::protobuf::Closure* done) {
476
0
    PTabletWriterAddBlockRequest* new_request = new PTabletWriterAddBlockRequest();
477
0
    google::protobuf::Closure* new_done =
478
0
            new NewHttpClosure<PTabletWriterAddBlockRequest>(new_request, done);
479
0
    brpc::Controller* cntl = static_cast<brpc::Controller*>(controller);
480
0
    Status st = attachment_extract_request_contain_block<PTabletWriterAddBlockRequest>(new_request,
481
0
                                                                                       cntl);
482
0
    if (st.ok()) {
483
0
        tablet_writer_add_block(controller, new_request, response, new_done);
484
0
    } else {
485
0
        st.to_protobuf(response->mutable_status());
486
0
    }
487
0
}
488
489
void PInternalService::tablet_writer_add_block(google::protobuf::RpcController* controller,
490
                                               const PTabletWriterAddBlockRequest* request,
491
                                               PTabletWriterAddBlockResult* response,
492
57.8k
                                               google::protobuf::Closure* done) {
493
57.8k
    int64_t submit_task_time_ns = MonotonicNanos();
494
58.0k
    bool ret = _heavy_work_pool.try_offer([request, response, done, submit_task_time_ns, this]() {
495
58.0k
        int64_t wait_execution_time_ns = MonotonicNanos() - submit_task_time_ns;
496
58.0k
        brpc::ClosureGuard closure_guard(done);
497
58.0k
        int64_t execution_time_ns = 0;
498
58.0k
        {
499
58.0k
            SCOPED_RAW_TIMER(&execution_time_ns);
500
58.0k
            signal::SignalTaskIdKeeper keeper(request->id());
501
58.0k
            auto st = _exec_env->load_channel_mgr()->add_batch(*request, response);
502
58.0k
            if (!st.ok()) {
503
47
                LOG(WARNING) << "tablet writer add block failed, message=" << st
504
47
                             << ", id=" << request->id() << ", index_id=" << request->index_id()
505
47
                             << ", sender_id=" << request->sender_id()
506
47
                             << ", backend id=" << request->backend_id();
507
47
            }
508
58.0k
            st.to_protobuf(response->mutable_status());
509
58.0k
        }
510
58.0k
        response->set_execution_time_us(execution_time_ns / NANOS_PER_MICRO);
511
58.0k
        response->set_wait_execution_time_us(wait_execution_time_ns / NANOS_PER_MICRO);
512
58.0k
    });
513
57.8k
    if (!ret) {
514
0
        offer_failed(response, done, _heavy_work_pool);
515
0
        return;
516
0
    }
517
57.8k
}
518
519
void PInternalService::tablet_writer_cancel(google::protobuf::RpcController* controller,
520
                                            const PTabletWriterCancelRequest* request,
521
                                            PTabletWriterCancelResult* response,
522
146
                                            google::protobuf::Closure* done) {
523
146
    bool ret = _heavy_work_pool.try_offer([this, request, done]() {
524
146
        VLOG_RPC << "tablet writer cancel, id=" << request->id()
525
0
                 << ", index_id=" << request->index_id() << ", sender_id=" << request->sender_id();
526
146
        signal::SignalTaskIdKeeper keeper(request->id());
527
146
        brpc::ClosureGuard closure_guard(done);
528
146
        auto st = _exec_env->load_channel_mgr()->cancel(*request);
529
146
        if (!st.ok()) {
530
0
            LOG(WARNING) << "tablet writer cancel failed, id=" << request->id()
531
0
                         << ", index_id=" << request->index_id()
532
0
                         << ", sender_id=" << request->sender_id();
533
0
        }
534
146
    });
535
146
    if (!ret) {
536
0
        offer_failed(response, done, _heavy_work_pool);
537
0
        return;
538
0
    }
539
146
}
540
541
Status PInternalService::_exec_plan_fragment_impl(
542
        const std::string& ser_request, PFragmentRequestVersion version, bool compact,
543
284k
        const std::function<void(RuntimeState*, Status*)>& cb) {
544
    // Sometimes the BE do not receive the first heartbeat message and it receives request from FE
545
    // If BE execute this fragment, it will core when it wants to get some property from master info.
546
284k
    if (ExecEnv::GetInstance()->cluster_info() == nullptr) {
547
0
        return Status::InternalError(
548
0
                "Have not receive the first heartbeat message from master, not ready to provide "
549
0
                "service");
550
0
    }
551
284k
    CHECK(version == PFragmentRequestVersion::VERSION_3)
552
1
            << "only support version 3, received " << version;
553
284k
    if (version == PFragmentRequestVersion::VERSION_3) {
554
284k
        TPipelineFragmentParamsList t_request;
555
284k
        {
556
284k
            const uint8_t* buf = (const uint8_t*)ser_request.data();
557
284k
            uint32_t len = ser_request.size();
558
284k
            RETURN_IF_ERROR(deserialize_thrift_msg(buf, &len, compact, &t_request));
559
284k
        }
560
561
284k
        const auto& fragment_list = t_request.params_list;
562
284k
        if (fragment_list.empty()) {
563
0
            return Status::InternalError("Invalid TPipelineFragmentParamsList!");
564
0
        }
565
284k
        MonotonicStopWatch timer;
566
284k
        timer.start();
567
568
        // work for old version frontend
569
284k
        if (!t_request.__isset.runtime_filter_info) {
570
117k
            TRuntimeFilterInfo runtime_filter_info;
571
117k
            auto local_param = fragment_list[0].local_params[0];
572
117k
            if (local_param.__isset.runtime_filter_params) {
573
117k
                runtime_filter_info.__set_runtime_filter_params(local_param.runtime_filter_params);
574
117k
            }
575
117k
            if (local_param.__isset.topn_filter_descs) {
576
0
                runtime_filter_info.__set_topn_filter_descs(local_param.topn_filter_descs);
577
0
            }
578
117k
            t_request.__set_runtime_filter_info(runtime_filter_info);
579
117k
        }
580
581
425k
        for (const TPipelineFragmentParams& fragment : fragment_list) {
582
425k
            if (cb) {
583
29
                RETURN_IF_ERROR(_exec_env->fragment_mgr()->exec_plan_fragment(
584
29
                        fragment, QuerySource::INTERNAL_FRONTEND, cb, t_request));
585
425k
            } else {
586
425k
                RETURN_IF_ERROR(_exec_env->fragment_mgr()->exec_plan_fragment(
587
425k
                        fragment, QuerySource::INTERNAL_FRONTEND, t_request));
588
425k
            }
589
425k
        }
590
282k
        timer.stop();
591
282k
        double cost_secs = static_cast<double>(timer.elapsed_time()) / 1000000000ULL;
592
282k
        if (cost_secs > 5) {
593
27
            LOG_WARNING("Prepare {} fragments of query {} costs {} seconds, it costs too much",
594
27
                        fragment_list.size(), print_id(fragment_list.front().query_id), cost_secs);
595
27
        }
596
597
282k
        return Status::OK();
598
284k
    } else {
599
0
        return Status::InternalError("invalid version");
600
0
    }
601
284k
}
602
603
void PInternalService::cancel_plan_fragment(google::protobuf::RpcController* /*controller*/,
604
                                            const PCancelPlanFragmentRequest* request,
605
                                            PCancelPlanFragmentResult* result,
606
166k
                                            google::protobuf::Closure* done) {
607
166k
    bool ret = _light_work_pool.try_offer([this, request, result, done]() {
608
166k
        brpc::ClosureGuard closure_guard(done);
609
166k
        signal::SignalTaskIdKeeper keeper(request->finst_id());
610
166k
        Status st = Status::OK();
611
612
166k
        const bool has_cancel_reason = request->has_cancel_reason();
613
166k
        const bool has_cancel_status = request->has_cancel_status();
614
        // During upgrade only LIMIT_REACH is used, other reason is changed to internal error
615
166k
        Status actual_cancel_status = Status::OK();
616
        // Convert PPlanFragmentCancelReason to Status
617
166k
        if (has_cancel_status) {
618
            // If fe set cancel status, then it is new FE now, should use cancel status.
619
166k
            actual_cancel_status = Status::create<false>(request->cancel_status());
620
166k
        } else if (has_cancel_reason) {
621
            // If fe not set cancel status, but set cancel reason, should convert cancel reason
622
            // to cancel status here.
623
0
            if (request->cancel_reason() == PPlanFragmentCancelReason::LIMIT_REACH) {
624
0
                actual_cancel_status = Status::Error<ErrorCode::LIMIT_REACH>("limit reach");
625
0
            } else {
626
                // Use cancel reason as error message
627
0
                actual_cancel_status = Status::InternalError(
628
0
                        PPlanFragmentCancelReason_Name(request->cancel_reason()));
629
0
            }
630
0
        } else {
631
0
            actual_cancel_status = Status::InternalError("unknown error");
632
0
        }
633
634
166k
        TUniqueId query_id;
635
166k
        query_id.__set_hi(request->query_id().hi());
636
166k
        query_id.__set_lo(request->query_id().lo());
637
166k
        LOG(INFO) << fmt::format("Cancel query {}, reason: {}", print_id(query_id),
638
166k
                                 actual_cancel_status.to_string());
639
166k
        _exec_env->fragment_mgr()->cancel_query(query_id, actual_cancel_status);
640
641
        // TODO: the logic seems useless, cancel only return Status::OK. remove it
642
166k
        st.to_protobuf(result->mutable_status());
643
166k
    });
644
166k
    if (!ret) {
645
0
        offer_failed(result, done, _light_work_pool);
646
0
        return;
647
0
    }
648
166k
}
649
650
void PInternalService::fetch_data(google::protobuf::RpcController* controller,
651
                                  const PFetchDataRequest* request, PFetchDataResult* result,
652
402k
                                  google::protobuf::Closure* done) {
653
    // fetch_data is a light operation which will put a request rather than wait inplace when there's no data ready.
654
    // when there's data ready, use brpc to send. there's queue in brpc service. won't take it too long.
655
402k
    auto ctx = GetResultBatchCtx::create_shared(result, done);
656
402k
    TUniqueId unique_id = UniqueId(request->finst_id()).to_thrift(); // query_id or instance_id
657
402k
    std::shared_ptr<MySQLResultBlockBuffer> buffer;
658
402k
    Status st = ExecEnv::GetInstance()->result_mgr()->find_buffer(unique_id, buffer);
659
402k
    if (!st.ok()) {
660
0
        LOG(WARNING) << "Result buffer not found! finst ID: " << print_id(unique_id);
661
0
        return;
662
0
    }
663
402k
    if (st = buffer->get_batch(ctx); !st.ok()) {
664
11
        LOG(WARNING) << "fetch_data failed: " << st.to_string();
665
11
    }
666
402k
}
667
668
void PInternalService::fetch_arrow_data(google::protobuf::RpcController* controller,
669
                                        const PFetchArrowDataRequest* request,
670
                                        PFetchArrowDataResult* result,
671
0
                                        google::protobuf::Closure* done) {
672
0
    bool ret = _arrow_flight_work_pool.try_offer([request, result, done]() {
673
0
        auto ctx = GetArrowResultBatchCtx::create_shared(result, done);
674
0
        TUniqueId unique_id = UniqueId(request->finst_id()).to_thrift(); // query_id or instance_id
675
0
        std::shared_ptr<ArrowFlightResultBlockBuffer> arrow_buffer;
676
0
        auto st = ExecEnv::GetInstance()->result_mgr()->find_buffer(unique_id, arrow_buffer);
677
0
        if (!st.ok()) {
678
0
            LOG(WARNING) << "Result buffer not found! Query ID: " << print_id(unique_id);
679
0
            return;
680
0
        }
681
0
        if (st = arrow_buffer->get_batch(ctx); !st.ok()) {
682
0
            LOG(WARNING) << "fetch_arrow_data failed: " << st.to_string();
683
0
        }
684
0
    });
685
0
    if (!ret) {
686
0
        offer_failed(result, done, _arrow_flight_work_pool);
687
0
        return;
688
0
    }
689
0
}
690
691
void PInternalService::outfile_write_success(google::protobuf::RpcController* controller,
692
                                             const POutfileWriteSuccessRequest* request,
693
                                             POutfileWriteSuccessResult* result,
694
4
                                             google::protobuf::Closure* done) {
695
4
    bool ret = _heavy_work_pool.try_offer([request, result, done]() {
696
4
        VLOG_RPC << "outfile write success file";
697
4
        brpc::ClosureGuard closure_guard(done);
698
4
        TResultFileSink result_file_sink;
699
4
        Status st = Status::OK();
700
4
        {
701
4
            const uint8_t* buf = (const uint8_t*)(request->result_file_sink().data());
702
4
            uint32_t len = request->result_file_sink().size();
703
4
            st = deserialize_thrift_msg(buf, &len, false, &result_file_sink);
704
4
            if (!st.ok()) {
705
0
                LOG(WARNING) << "outfile write success file failed, errmsg = " << st;
706
0
                st.to_protobuf(result->mutable_status());
707
0
                return;
708
0
            }
709
4
        }
710
711
4
        TResultFileSinkOptions file_options = result_file_sink.file_options;
712
4
        std::stringstream ss;
713
4
        ss << file_options.file_path << file_options.success_file_name;
714
4
        std::string file_name = ss.str();
715
4
        if (result_file_sink.storage_backend_type == TStorageBackendType::LOCAL) {
716
            // For local file writer, the file_path is a local dir.
717
            // Here we do a simple security verification by checking whether the file exists.
718
            // Because the file path is currently arbitrarily specified by the user,
719
            // Doris is not responsible for ensuring the correctness of the path.
720
            // This is just to prevent overwriting the existing file.
721
4
            bool exists = true;
722
4
            st = io::global_local_filesystem()->exists(file_name, &exists);
723
4
            if (!st.ok()) {
724
0
                LOG(WARNING) << "outfile write success filefailed, errmsg = " << st;
725
0
                st.to_protobuf(result->mutable_status());
726
0
                return;
727
0
            }
728
4
            if (exists) {
729
0
                st = Status::InternalError("File already exists: {}", file_name);
730
0
            }
731
4
            if (!st.ok()) {
732
0
                LOG(WARNING) << "outfile write success file failed, errmsg = " << st;
733
0
                st.to_protobuf(result->mutable_status());
734
0
                return;
735
0
            }
736
4
        }
737
738
4
        auto file_type_res =
739
4
                FileFactory::convert_storage_type(result_file_sink.storage_backend_type);
740
4
        if (!file_type_res.has_value()) [[unlikely]] {
741
0
            st = std::move(file_type_res).error();
742
0
            st.to_protobuf(result->mutable_status());
743
0
            LOG(WARNING) << "encounter unkonw type=" << result_file_sink.storage_backend_type
744
0
                         << ", st=" << st;
745
0
            return;
746
0
        }
747
748
4
        auto&& res = FileFactory::create_file_writer(file_type_res.value(), ExecEnv::GetInstance(),
749
4
                                                     file_options.broker_addresses,
750
4
                                                     file_options.broker_properties, file_name,
751
4
                                                     {
752
4
                                                             .write_file_cache = false,
753
4
                                                             .sync_file_data = false,
754
4
                                                     });
755
4
        using T = std::decay_t<decltype(res)>;
756
4
        if (!res.has_value()) [[unlikely]] {
757
0
            st = std::forward<T>(res).error();
758
0
            st.to_protobuf(result->mutable_status());
759
0
            return;
760
0
        }
761
762
4
        std::unique_ptr<doris::io::FileWriter> _file_writer_impl = std::forward<T>(res).value();
763
        // must write somthing because s3 file writer can not writer empty file
764
4
        st = _file_writer_impl->append({"success"});
765
4
        if (!st.ok()) {
766
0
            LOG(WARNING) << "outfile write success filefailed, errmsg=" << st;
767
0
            st.to_protobuf(result->mutable_status());
768
0
            return;
769
0
        }
770
4
        st = _file_writer_impl->close();
771
4
        if (!st.ok()) {
772
0
            LOG(WARNING) << "outfile write success filefailed, errmsg=" << st;
773
0
            st.to_protobuf(result->mutable_status());
774
0
            return;
775
0
        }
776
4
    });
777
4
    if (!ret) {
778
0
        offer_failed(result, done, _heavy_work_pool);
779
0
        return;
780
0
    }
781
4
}
782
783
void PInternalService::fetch_table_schema(google::protobuf::RpcController* controller,
784
                                          const PFetchTableSchemaRequest* request,
785
                                          PFetchTableSchemaResult* result,
786
3.94k
                                          google::protobuf::Closure* done) {
787
3.94k
    bool ret = _heavy_work_pool.try_offer([request, result, done]() {
788
3.94k
        VLOG_RPC << "fetch table schema";
789
3.94k
        brpc::ClosureGuard closure_guard(done);
790
3.94k
        TFileScanRange file_scan_range;
791
3.94k
        Status st = Status::OK();
792
3.94k
        {
793
3.94k
            const uint8_t* buf = (const uint8_t*)(request->file_scan_range().data());
794
3.94k
            uint32_t len = request->file_scan_range().size();
795
3.94k
            st = deserialize_thrift_msg(buf, &len, false, &file_scan_range);
796
3.94k
            if (!st.ok()) {
797
0
                LOG(WARNING) << "fetch table schema failed, errmsg=" << st;
798
0
                st.to_protobuf(result->mutable_status());
799
0
                return;
800
0
            }
801
3.94k
        }
802
3.94k
        if (file_scan_range.__isset.ranges == false) {
803
0
            st = Status::InternalError("can not get TFileRangeDesc.");
804
0
            st.to_protobuf(result->mutable_status());
805
0
            return;
806
0
        }
807
3.94k
        if (file_scan_range.__isset.params == false) {
808
0
            st = Status::InternalError("can not get TFileScanRangeParams.");
809
0
            st.to_protobuf(result->mutable_status());
810
0
            return;
811
0
        }
812
3.94k
        const TFileRangeDesc& range = file_scan_range.ranges.at(0);
813
3.94k
        const TFileScanRangeParams& params = file_scan_range.params;
814
815
3.94k
        std::shared_ptr<MemTrackerLimiter> mem_tracker = MemTrackerLimiter::create_shared(
816
3.94k
                MemTrackerLimiter::Type::OTHER,
817
3.94k
                fmt::format("InternalService::fetch_table_schema:{}#{}", params.format_type,
818
3.94k
                            params.file_type));
819
3.94k
        SCOPED_ATTACH_TASK(mem_tracker);
820
821
        // make sure profile is desctructed after reader cause PrefetchBufferedReader
822
        // might asynchronouslly access the profile
823
3.94k
        std::unique_ptr<RuntimeProfile> profile =
824
3.94k
                std::make_unique<RuntimeProfile>("FetchTableSchema");
825
3.94k
        std::unique_ptr<GenericReader> reader(nullptr);
826
3.94k
        auto io_ctx = std::make_shared<io::IOContext>();
827
3.94k
        auto file_cache_statis = std::make_shared<io::FileCacheStatistics>();
828
3.94k
        auto file_reader_stats = std::make_shared<io::FileReaderStats>();
829
3.94k
        io_ctx->file_cache_stats = file_cache_statis.get();
830
3.94k
        io_ctx->file_reader_stats = file_reader_stats.get();
831
        // file_slots is no use, but the lifetime should be longer than reader
832
3.94k
        std::vector<SlotDescriptor*> file_slots;
833
3.94k
        switch (params.format_type) {
834
790
        case TFileFormatType::FORMAT_CSV_PLAIN:
835
790
        case TFileFormatType::FORMAT_CSV_GZ:
836
790
        case TFileFormatType::FORMAT_CSV_BZ2:
837
790
        case TFileFormatType::FORMAT_CSV_LZ4FRAME:
838
790
        case TFileFormatType::FORMAT_CSV_LZ4BLOCK:
839
790
        case TFileFormatType::FORMAT_CSV_SNAPPYBLOCK:
840
790
        case TFileFormatType::FORMAT_CSV_LZOP:
841
790
        case TFileFormatType::FORMAT_CSV_DEFLATE: {
842
790
            reader = CsvReader::create_unique(nullptr, profile.get(), nullptr, params, range,
843
790
                                              file_slots, io_ctx.get(), io_ctx);
844
790
            break;
845
790
        }
846
4
        case TFileFormatType::FORMAT_TEXT: {
847
4
            reader = TextReader::create_unique(nullptr, profile.get(), nullptr, params, range,
848
4
                                               file_slots, io_ctx.get());
849
4
            break;
850
790
        }
851
2.35k
        case TFileFormatType::FORMAT_PARQUET: {
852
2.35k
            reader = ParquetReader::create_unique(params, range, io_ctx, nullptr);
853
2.35k
            break;
854
790
        }
855
714
        case TFileFormatType::FORMAT_ORC: {
856
714
            reader = OrcReader::create_unique(params, range, "", io_ctx);
857
714
            break;
858
790
        }
859
2
        case TFileFormatType::FORMAT_NATIVE: {
860
2
            reader = NativeReader::create_unique(profile.get(), params, range, io_ctx.get(),
861
2
                                                 nullptr);
862
2
            break;
863
790
        }
864
71
        case TFileFormatType::FORMAT_JSON: {
865
71
            reader = NewJsonReader::create_unique(profile.get(), params, range, file_slots,
866
71
                                                  io_ctx.get(), io_ctx);
867
71
            break;
868
790
        }
869
0
        default:
870
0
            st = Status::InternalError("Not supported file format in fetch table schema: {}",
871
0
                                       params.format_type);
872
0
            st.to_protobuf(result->mutable_status());
873
0
            return;
874
3.94k
        }
875
3.94k
        if (!st.ok()) {
876
0
            LOG(WARNING) << "failed to create reader, errmsg=" << st;
877
0
            st.to_protobuf(result->mutable_status());
878
0
            return;
879
0
        }
880
3.94k
        st = reader->init_schema_reader();
881
3.94k
        if (!st.ok()) {
882
19
            LOG(WARNING) << "failed to init reader, errmsg=" << st;
883
19
            st.to_protobuf(result->mutable_status());
884
19
            return;
885
19
        }
886
3.92k
        std::vector<std::string> col_names;
887
3.92k
        std::vector<DataTypePtr> col_types;
888
3.92k
        st = reader->get_parsed_schema(&col_names, &col_types);
889
3.92k
        if (!st.ok()) {
890
10
            LOG(WARNING) << "fetch table schema failed, errmsg=" << st;
891
10
            st.to_protobuf(result->mutable_status());
892
10
            return;
893
10
        }
894
3.91k
        result->set_column_nums(col_names.size());
895
28.5k
        for (size_t idx = 0; idx < col_names.size(); ++idx) {
896
24.6k
            result->add_column_names(col_names[idx]);
897
24.6k
        }
898
28.5k
        for (size_t idx = 0; idx < col_types.size(); ++idx) {
899
24.6k
            PTypeDesc* type_desc = result->add_column_types();
900
24.6k
            col_types[idx]->to_protobuf(type_desc);
901
24.6k
        }
902
3.91k
        st.to_protobuf(result->mutable_status());
903
3.91k
    });
904
3.94k
    if (!ret) {
905
0
        offer_failed(result, done, _heavy_work_pool);
906
0
        return;
907
0
    }
908
3.94k
}
909
910
void PInternalService::fetch_arrow_flight_schema(google::protobuf::RpcController* controller,
911
                                                 const PFetchArrowFlightSchemaRequest* request,
912
                                                 PFetchArrowFlightSchemaResult* result,
913
101
                                                 google::protobuf::Closure* done) {
914
101
    bool ret = _arrow_flight_work_pool.try_offer([request, result, done]() {
915
101
        brpc::ClosureGuard closure_guard(done);
916
101
        std::shared_ptr<arrow::Schema> schema;
917
101
        std::shared_ptr<ArrowFlightResultBlockBuffer> buffer;
918
101
        auto st = ExecEnv::GetInstance()->result_mgr()->find_buffer(
919
101
                UniqueId(request->finst_id()).to_thrift(), buffer);
920
101
        if (!st.ok()) {
921
0
            LOG(WARNING) << "fetch arrow flight schema failed, errmsg=" << st;
922
0
            st.to_protobuf(result->mutable_status());
923
0
            return;
924
0
        }
925
101
        st = buffer->get_schema(&schema);
926
101
        if (!st.ok()) {
927
0
            LOG(WARNING) << "fetch arrow flight schema failed, errmsg=" << st;
928
0
            st.to_protobuf(result->mutable_status());
929
0
            return;
930
0
        }
931
932
101
        std::string schema_str;
933
101
        st = serialize_arrow_schema(&schema, &schema_str);
934
101
        if (st.ok()) {
935
101
            result->set_schema(std::move(schema_str));
936
101
            if (!config::public_host.empty()) {
937
0
                result->set_be_arrow_flight_ip(config::public_host);
938
0
            }
939
101
            if (config::arrow_flight_sql_proxy_port != -1) {
940
0
                result->set_be_arrow_flight_port(config::arrow_flight_sql_proxy_port);
941
0
            }
942
101
        }
943
101
        st.to_protobuf(result->mutable_status());
944
101
    });
945
101
    if (!ret) {
946
0
        offer_failed(result, done, _arrow_flight_work_pool);
947
0
        return;
948
0
    }
949
101
}
950
951
Status PInternalService::_tablet_fetch_data(const PTabletKeyLookupRequest* request,
952
263
                                            PTabletKeyLookupResponse* response) {
953
263
    PointQueryExecutor executor;
954
263
    RETURN_IF_ERROR(executor.init(request, response));
955
263
    RETURN_IF_ERROR(executor.lookup_up());
956
260
    executor.print_profile();
957
260
    return Status::OK();
958
263
}
959
960
void PInternalService::tablet_fetch_data(google::protobuf::RpcController* controller,
961
                                         const PTabletKeyLookupRequest* request,
962
                                         PTabletKeyLookupResponse* response,
963
263
                                         google::protobuf::Closure* done) {
964
263
    bool ret = _light_work_pool.try_offer([this, controller, request, response, done]() {
965
263
        [[maybe_unused]] auto* cntl = static_cast<brpc::Controller*>(controller);
966
263
        brpc::ClosureGuard guard(done);
967
263
        Status st = _tablet_fetch_data(request, response);
968
263
        st.to_protobuf(response->mutable_status());
969
263
    });
970
263
    if (!ret) {
971
0
        offer_failed(response, done, _light_work_pool);
972
0
        return;
973
0
    }
974
263
}
975
976
void PInternalService::test_jdbc_connection(google::protobuf::RpcController* controller,
977
                                            const PJdbcTestConnectionRequest* request,
978
                                            PJdbcTestConnectionResult* result,
979
305
                                            google::protobuf::Closure* done) {
980
305
    if (!doris::config::enable_java_support) {
981
0
        doris::Status status = doris::Status::InternalError(
982
0
                "you can change be config enable_java_support to true and restart be.");
983
0
        status.to_protobuf(result->mutable_status());
984
0
        done->Run();
985
0
        return;
986
0
    }
987
305
    bool ret = _heavy_work_pool.try_offer([request, result, done]() {
988
305
        VLOG_RPC << "test jdbc connection";
989
305
        brpc::ClosureGuard closure_guard(done);
990
305
        std::shared_ptr<MemTrackerLimiter> mem_tracker = MemTrackerLimiter::create_shared(
991
305
                MemTrackerLimiter::Type::OTHER,
992
305
                fmt::format("InternalService::test_jdbc_connection"));
993
305
        SCOPED_ATTACH_TASK(mem_tracker);
994
305
        TTableDescriptor table_desc;
995
305
        Status st = Status::OK();
996
305
        {
997
305
            const uint8_t* buf = (const uint8_t*)request->jdbc_table().data();
998
305
            uint32_t len = request->jdbc_table().size();
999
305
            st = deserialize_thrift_msg(buf, &len, false, &table_desc);
1000
305
            if (!st.ok()) {
1001
0
                LOG(WARNING) << "test jdbc connection failed, errmsg=" << st;
1002
0
                st.to_protobuf(result->mutable_status());
1003
0
                return;
1004
0
            }
1005
305
        }
1006
305
        TJdbcTable jdbc_table = (table_desc.jdbcTable);
1007
1008
        // Resolve driver URL to absolute file:// path
1009
305
        std::string driver_url;
1010
305
        st = JdbcUtils::resolve_driver_url(jdbc_table.jdbc_driver_url, &driver_url);
1011
305
        if (!st.ok()) {
1012
0
            st.to_protobuf(result->mutable_status());
1013
0
            return;
1014
0
        }
1015
1016
        // Build params for JdbcConnectionTester
1017
305
        std::map<std::string, std::string> params;
1018
305
        params["jdbc_url"] = jdbc_table.jdbc_url;
1019
305
        params["jdbc_user"] = jdbc_table.jdbc_user;
1020
305
        params["jdbc_password"] = jdbc_table.jdbc_password;
1021
305
        params["jdbc_driver_class"] = jdbc_table.jdbc_driver_class;
1022
305
        params["jdbc_driver_url"] = driver_url;
1023
305
        params["query_sql"] = request->query_str();
1024
305
        params["catalog_id"] = std::to_string(jdbc_table.catalog_id);
1025
305
        params["connection_pool_min_size"] = std::to_string(jdbc_table.connection_pool_min_size);
1026
305
        params["connection_pool_max_size"] = std::to_string(jdbc_table.connection_pool_max_size);
1027
305
        params["connection_pool_max_wait_time"] =
1028
305
                std::to_string(jdbc_table.connection_pool_max_wait_time);
1029
305
        params["connection_pool_max_life_time"] =
1030
305
                std::to_string(jdbc_table.connection_pool_max_life_time);
1031
305
        params["connection_pool_keep_alive"] =
1032
305
                jdbc_table.connection_pool_keep_alive ? "true" : "false";
1033
305
        params["clean_datasource"] = "true";
1034
        // Map jdbc_table_type (TOdbcTableType enum value) to string name
1035
        // for JdbcTypeHandlerFactory to select the correct type handler.
1036
        // This ensures the right validation query is used (e.g. Oracle: "SELECT 1 FROM dual").
1037
305
        if (request->has_jdbc_table_type()) {
1038
305
            std::string type_name;
1039
305
            switch (request->jdbc_table_type()) {
1040
203
            case 0:
1041
203
                type_name = "MYSQL";
1042
203
                break;
1043
38
            case 1:
1044
38
                type_name = "ORACLE";
1045
38
                break;
1046
24
            case 2:
1047
24
                type_name = "POSTGRESQL";
1048
24
                break;
1049
14
            case 3:
1050
14
                type_name = "SQLSERVER";
1051
14
                break;
1052
16
            case 6:
1053
16
                type_name = "CLICKHOUSE";
1054
16
                break;
1055
0
            case 7:
1056
0
                type_name = "SAP_HANA";
1057
0
                break;
1058
0
            case 8:
1059
0
                type_name = "TRINO";
1060
0
                break;
1061
0
            case 9:
1062
0
                type_name = "PRESTO";
1063
0
                break;
1064
4
            case 10:
1065
4
                type_name = "OCEANBASE";
1066
4
                break;
1067
0
            case 11:
1068
0
                type_name = "OCEANBASE_ORACLE";
1069
0
                break;
1070
4
            case 13:
1071
4
                type_name = "DB2";
1072
4
                break;
1073
0
            case 14:
1074
0
                type_name = "GBASE";
1075
0
                break;
1076
0
            default:
1077
0
                break;
1078
305
            }
1079
305
            if (!type_name.empty()) {
1080
305
                params["table_type"] = type_name;
1081
305
            }
1082
305
        }
1083
        // required_fields and columns_types are required by JniReader
1084
305
        params["required_fields"] = "result";
1085
305
        params["columns_types"] = "int";
1086
1087
        // Use JniReader to create JdbcConnectionTester, which tests
1088
        // the connection in its open() method.
1089
305
        auto jni_reader =
1090
305
                std::make_unique<JniReader>("org/apache/doris/jdbc/JdbcConnectionTester", params);
1091
305
        st = jni_reader->open(nullptr, nullptr);
1092
305
        st.to_protobuf(result->mutable_status());
1093
1094
305
        Status close_st = jni_reader->close();
1095
305
        if (!close_st.ok()) {
1096
0
            LOG(WARNING) << "Failed to close JDBC connection tester: " << close_st.msg();
1097
0
        }
1098
305
    });
1099
1100
305
    if (!ret) {
1101
0
        offer_failed(result, done, _heavy_work_pool);
1102
0
        return;
1103
0
    }
1104
305
}
1105
1106
void PInternalServiceImpl::get_column_ids_by_tablet_ids(google::protobuf::RpcController* controller,
1107
                                                        const PFetchColIdsRequest* request,
1108
                                                        PFetchColIdsResponse* response,
1109
0
                                                        google::protobuf::Closure* done) {
1110
0
    bool ret = _light_work_pool.try_offer([this, controller, request, response, done]() {
1111
0
        _get_column_ids_by_tablet_ids(controller, request, response, done);
1112
0
    });
1113
0
    if (!ret) {
1114
0
        offer_failed(response, done, _light_work_pool);
1115
0
        return;
1116
0
    }
1117
0
}
1118
1119
void PInternalServiceImpl::_get_column_ids_by_tablet_ids(
1120
        google::protobuf::RpcController* controller, const PFetchColIdsRequest* request,
1121
0
        PFetchColIdsResponse* response, google::protobuf::Closure* done) {
1122
0
    brpc::ClosureGuard guard(done);
1123
0
    [[maybe_unused]] auto* cntl = static_cast<brpc::Controller*>(controller);
1124
0
    TabletManager* tablet_mgr = _engine.tablet_manager();
1125
0
    const auto& params = request->params();
1126
0
    for (const auto& param : params) {
1127
0
        int64_t index_id = param.indexid();
1128
0
        const auto& tablet_ids = param.tablet_ids();
1129
0
        std::set<std::set<int32_t>> filter_set;
1130
0
        std::map<int32_t, const TabletColumn*> id_to_column;
1131
0
        for (const int64_t tablet_id : tablet_ids) {
1132
0
            TabletSharedPtr tablet = tablet_mgr->get_tablet(tablet_id);
1133
0
            if (tablet == nullptr) {
1134
0
                std::stringstream ss;
1135
0
                ss << "cannot get tablet by id:" << tablet_id;
1136
0
                LOG(WARNING) << ss.str();
1137
0
                response->mutable_status()->set_status_code(TStatusCode::ILLEGAL_STATE);
1138
0
                response->mutable_status()->add_error_msgs(ss.str());
1139
0
                return;
1140
0
            }
1141
            // check schema consistency, column ids should be the same
1142
0
            const auto& columns = tablet->tablet_schema()->columns();
1143
1144
0
            std::set<int32_t> column_ids;
1145
0
            for (const auto& col : columns) {
1146
0
                column_ids.insert(col->unique_id());
1147
0
            }
1148
0
            filter_set.insert(std::move(column_ids));
1149
1150
0
            if (id_to_column.empty()) {
1151
0
                for (const auto& col : columns) {
1152
0
                    id_to_column.insert(std::pair {col->unique_id(), col.get()});
1153
0
                }
1154
0
            } else {
1155
0
                for (const auto& col : columns) {
1156
0
                    auto it = id_to_column.find(col->unique_id());
1157
0
                    if (it == id_to_column.end() || *(it->second) != *col) {
1158
0
                        ColumnPB prev_col_pb;
1159
0
                        ColumnPB curr_col_pb;
1160
0
                        if (it != id_to_column.end()) {
1161
0
                            it->second->to_schema_pb(&prev_col_pb);
1162
0
                        }
1163
0
                        col->to_schema_pb(&curr_col_pb);
1164
0
                        std::stringstream ss;
1165
0
                        ss << "consistency check failed: index{ " << index_id << " }"
1166
0
                           << " got inconsistent schema, prev column: " << prev_col_pb.DebugString()
1167
0
                           << " current column: " << curr_col_pb.DebugString();
1168
0
                        LOG(WARNING) << ss.str();
1169
0
                        response->mutable_status()->set_status_code(TStatusCode::ILLEGAL_STATE);
1170
0
                        response->mutable_status()->add_error_msgs(ss.str());
1171
0
                        return;
1172
0
                    }
1173
0
                }
1174
0
            }
1175
0
        }
1176
1177
0
        if (filter_set.size() > 1) {
1178
            // consistecy check failed
1179
0
            std::stringstream ss;
1180
0
            ss << "consistency check failed: index{" << index_id << "}"
1181
0
               << "got inconsistent schema";
1182
0
            LOG(WARNING) << ss.str();
1183
0
            response->mutable_status()->set_status_code(TStatusCode::ILLEGAL_STATE);
1184
0
            response->mutable_status()->add_error_msgs(ss.str());
1185
0
            return;
1186
0
        }
1187
        // consistency check passed, use the first tablet to be the representative
1188
0
        TabletSharedPtr tablet = tablet_mgr->get_tablet(tablet_ids[0]);
1189
0
        const auto& columns = tablet->tablet_schema()->columns();
1190
0
        auto entry = response->add_entries();
1191
0
        entry->set_index_id(index_id);
1192
0
        auto col_name_to_id = entry->mutable_col_name_to_id();
1193
0
        for (const auto& column : columns) {
1194
0
            (*col_name_to_id)[column->name()] = column->unique_id();
1195
0
        }
1196
0
    }
1197
0
    response->mutable_status()->set_status_code(TStatusCode::OK);
1198
0
}
1199
1200
template <class RPCResponse>
1201
struct AsyncRPCContext {
1202
    RPCResponse response;
1203
    brpc::Controller cntl;
1204
    brpc::CallId cid;
1205
};
1206
1207
void PInternalService::fetch_remote_tablet_schema(google::protobuf::RpcController* controller,
1208
                                                  const PFetchRemoteSchemaRequest* request,
1209
                                                  PFetchRemoteSchemaResponse* response,
1210
214
                                                  google::protobuf::Closure* done) {
1211
214
    bool ret = _heavy_work_pool.try_offer([request, response, done]() {
1212
214
        brpc::ClosureGuard closure_guard(done);
1213
214
        Status st = Status::OK();
1214
214
        std::shared_ptr<MemTrackerLimiter> mem_tracker = MemTrackerLimiter::create_shared(
1215
214
                MemTrackerLimiter::Type::OTHER,
1216
214
                fmt::format("InternalService::fetch_remote_tablet_schema"));
1217
214
        SCOPED_ATTACH_TASK(mem_tracker);
1218
214
        if (request->is_coordinator()) {
1219
            // Spawn rpc request to none coordinator nodes, and finally merge them all
1220
107
            PFetchRemoteSchemaRequest remote_request(*request);
1221
            // set it none coordinator to get merged schema
1222
107
            remote_request.set_is_coordinator(false);
1223
107
            using PFetchRemoteTabletSchemaRpcContext = AsyncRPCContext<PFetchRemoteSchemaResponse>;
1224
107
            std::vector<PFetchRemoteTabletSchemaRpcContext> rpc_contexts(
1225
107
                    request->tablet_location_size());
1226
214
            for (int i = 0; i < request->tablet_location_size(); ++i) {
1227
107
                std::string host = request->tablet_location(i).host();
1228
107
                int32_t brpc_port = request->tablet_location(i).brpc_port();
1229
107
                std::shared_ptr<PBackendService_Stub> stub(
1230
107
                        ExecEnv::GetInstance()->brpc_internal_client_cache()->get_client(
1231
107
                                host, brpc_port));
1232
107
                if (stub == nullptr) {
1233
0
                    LOG(WARNING) << "Failed to init rpc to " << host << ":" << brpc_port;
1234
0
                    st = Status::InternalError("Failed to init rpc to {}:{}", host, brpc_port);
1235
0
                    continue;
1236
0
                }
1237
107
                rpc_contexts[i].cid = rpc_contexts[i].cntl.call_id();
1238
107
                rpc_contexts[i].cntl.set_timeout_ms(config::fetch_remote_schema_rpc_timeout_ms);
1239
107
                stub->fetch_remote_tablet_schema(&rpc_contexts[i].cntl, &remote_request,
1240
107
                                                 &rpc_contexts[i].response, brpc::DoNothing());
1241
107
            }
1242
107
            std::vector<TabletSchemaSPtr> schemas;
1243
107
            for (auto& rpc_context : rpc_contexts) {
1244
107
                brpc::Join(rpc_context.cid);
1245
107
                if (!st.ok()) {
1246
                    // make sure all flying rpc request is joined
1247
0
                    continue;
1248
0
                }
1249
107
                if (rpc_context.cntl.Failed()) {
1250
0
                    LOG(WARNING) << "fetch_remote_tablet_schema rpc err:"
1251
0
                                 << rpc_context.cntl.ErrorText();
1252
0
                    ExecEnv::GetInstance()->brpc_internal_client_cache()->erase(
1253
0
                            rpc_context.cntl.remote_side());
1254
0
                    st = Status::InternalError("fetch_remote_tablet_schema rpc err: {}",
1255
0
                                               rpc_context.cntl.ErrorText());
1256
0
                }
1257
107
                if (rpc_context.response.status().status_code() != 0) {
1258
0
                    st = Status::create(rpc_context.response.status());
1259
0
                }
1260
107
                if (rpc_context.response.has_merged_schema()) {
1261
107
                    TabletSchemaSPtr schema = std::make_shared<TabletSchema>();
1262
107
                    schema->init_from_pb(rpc_context.response.merged_schema());
1263
107
                    schemas.push_back(schema);
1264
107
                }
1265
107
            }
1266
107
            if (!schemas.empty() && st.ok()) {
1267
                // merge all
1268
107
                TabletSchemaSPtr merged_schema;
1269
107
                st = variant_util::get_least_common_schema(schemas, nullptr, merged_schema);
1270
107
                if (!st.ok()) {
1271
0
                    LOG(WARNING) << "Failed to get least common schema: " << st.to_string();
1272
0
                    st = Status::InternalError("Failed to get least common schema: {}",
1273
0
                                               st.to_string());
1274
0
                }
1275
107
                VLOG_DEBUG << "dump schema:" << merged_schema->dump_structure();
1276
107
                merged_schema->reserve_extracted_columns();
1277
107
                merged_schema->to_schema_pb(response->mutable_merged_schema());
1278
107
            }
1279
107
            st.to_protobuf(response->mutable_status());
1280
107
            return;
1281
107
        } else {
1282
            // This is not a coordinator, get it's tablet and merge schema
1283
107
            std::vector<int64_t> target_tablets;
1284
107
            for (int i = 0; i < request->tablet_location_size(); ++i) {
1285
107
                const auto& location = request->tablet_location(i);
1286
107
                auto backend = BackendOptions::get_local_backend();
1287
                // If this is the target backend
1288
107
                if (backend.host == location.host() && config::brpc_port == location.brpc_port()) {
1289
107
                    target_tablets.assign(location.tablet_id().begin(), location.tablet_id().end());
1290
107
                    break;
1291
107
                }
1292
107
            }
1293
107
            if (!target_tablets.empty()) {
1294
107
                std::vector<TabletSchemaSPtr> tablet_schemas;
1295
1.41k
                for (int64_t tablet_id : target_tablets) {
1296
1.41k
                    auto res = ExecEnv::get_tablet(tablet_id);
1297
1.41k
                    if (!res.has_value()) {
1298
                        // just ignore
1299
0
                        LOG(WARNING) << "tablet does not exist, tablet id is " << tablet_id;
1300
0
                        continue;
1301
0
                    }
1302
1.41k
                    auto tablet = res.value();
1303
1.41k
                    auto rowsets = tablet->get_snapshot_rowset();
1304
1.41k
                    auto schema =
1305
1.41k
                            variant_util::VariantCompactionUtil::calculate_variant_extended_schema(
1306
1.41k
                                    rowsets, tablet->tablet_schema());
1307
1.41k
                    tablet_schemas.push_back(schema);
1308
1.41k
                }
1309
107
                if (!tablet_schemas.empty()) {
1310
                    // merge all
1311
107
                    TabletSchemaSPtr merged_schema;
1312
107
                    st = variant_util::get_least_common_schema(tablet_schemas, nullptr,
1313
107
                                                               merged_schema);
1314
107
                    if (!st.ok()) {
1315
0
                        LOG(WARNING) << "Failed to get least common schema: " << st.to_string();
1316
0
                        st = Status::InternalError("Failed to get least common schema: {}",
1317
0
                                                   st.to_string());
1318
0
                    }
1319
107
                    merged_schema->to_schema_pb(response->mutable_merged_schema());
1320
107
                    VLOG_DEBUG << "dump schema:" << merged_schema->dump_structure();
1321
107
                }
1322
107
            }
1323
107
            st.to_protobuf(response->mutable_status());
1324
107
        }
1325
214
    });
1326
214
    if (!ret) {
1327
0
        offer_failed(response, done, _heavy_work_pool);
1328
0
    }
1329
214
}
1330
1331
void PInternalService::report_stream_load_status(google::protobuf::RpcController* controller,
1332
                                                 const PReportStreamLoadStatusRequest* request,
1333
                                                 PReportStreamLoadStatusResponse* response,
1334
0
                                                 google::protobuf::Closure* done) {
1335
0
    TUniqueId load_id;
1336
0
    load_id.__set_hi(request->load_id().hi());
1337
0
    load_id.__set_lo(request->load_id().lo());
1338
0
    Status st = Status::OK();
1339
0
    auto stream_load_ctx = _exec_env->new_load_stream_mgr()->get(load_id);
1340
0
    if (!stream_load_ctx) {
1341
0
        st = Status::InternalError("unknown stream load id: {}", UniqueId(load_id).to_string());
1342
0
    }
1343
0
    stream_load_ctx->load_status_promise.set_value(st);
1344
0
    st.to_protobuf(response->mutable_status());
1345
0
}
1346
1347
void PInternalService::get_info(google::protobuf::RpcController* controller,
1348
                                const PProxyRequest* request, PProxyResult* response,
1349
619
                                google::protobuf::Closure* done) {
1350
619
    bool ret = _exec_env->routine_load_task_executor()->get_thread_pool().submit_func([this,
1351
619
                                                                                       request,
1352
619
                                                                                       response,
1353
619
                                                                                       done]() {
1354
619
        brpc::ClosureGuard closure_guard(done);
1355
        // PProxyRequest is defined in gensrc/proto/internal_service.proto
1356
        // Currently it supports 2 kinds of requests:
1357
        // 1. get all kafka partition ids for given topic
1358
        // 2. get all kafka partition offsets for given topic and timestamp.
1359
619
        int timeout_ms = request->has_timeout_secs() ? request->timeout_secs() * 1000 : 60 * 1000;
1360
619
        if (request->has_kafka_meta_request()) {
1361
619
            const PKafkaMetaProxyRequest& kafka_request = request->kafka_meta_request();
1362
619
            if (!kafka_request.offset_flags().empty()) {
1363
65
                std::vector<PIntegerPair> partition_offsets;
1364
65
                Status st = _exec_env->routine_load_task_executor()
1365
65
                                    ->get_kafka_real_offsets_for_partitions(
1366
65
                                            request->kafka_meta_request(), &partition_offsets,
1367
65
                                            timeout_ms);
1368
65
                if (st.ok()) {
1369
65
                    PKafkaPartitionOffsets* part_offsets = response->mutable_partition_offsets();
1370
65
                    for (const auto& entry : partition_offsets) {
1371
65
                        PIntegerPair* res = part_offsets->add_offset_times();
1372
65
                        res->set_key(entry.key());
1373
65
                        res->set_val(entry.val());
1374
65
                    }
1375
65
                }
1376
65
                st.to_protobuf(response->mutable_status());
1377
65
                return;
1378
554
            } else if (!kafka_request.partition_id_for_latest_offsets().empty()) {
1379
                // get latest offsets for specified partition ids
1380
479
                std::vector<PIntegerPair> partition_offsets;
1381
479
                Status st = _exec_env->routine_load_task_executor()
1382
479
                                    ->get_kafka_latest_offsets_for_partitions(
1383
479
                                            request->kafka_meta_request(), &partition_offsets,
1384
479
                                            timeout_ms);
1385
479
                if (st.ok()) {
1386
479
                    PKafkaPartitionOffsets* part_offsets = response->mutable_partition_offsets();
1387
479
                    for (const auto& entry : partition_offsets) {
1388
479
                        PIntegerPair* res = part_offsets->add_offset_times();
1389
479
                        res->set_key(entry.key());
1390
479
                        res->set_val(entry.val());
1391
479
                    }
1392
479
                }
1393
479
                st.to_protobuf(response->mutable_status());
1394
479
                return;
1395
479
            } else if (!kafka_request.offset_times().empty()) {
1396
                // if offset_times() has elements, which means this request is to get offset by timestamp.
1397
1
                std::vector<PIntegerPair> partition_offsets;
1398
1
                Status st = _exec_env->routine_load_task_executor()
1399
1
                                    ->get_kafka_partition_offsets_for_times(
1400
1
                                            request->kafka_meta_request(), &partition_offsets,
1401
1
                                            timeout_ms);
1402
1
                if (st.ok()) {
1403
1
                    PKafkaPartitionOffsets* part_offsets = response->mutable_partition_offsets();
1404
1
                    for (const auto& entry : partition_offsets) {
1405
1
                        PIntegerPair* res = part_offsets->add_offset_times();
1406
1
                        res->set_key(entry.key());
1407
1
                        res->set_val(entry.val());
1408
1
                    }
1409
1
                }
1410
1
                st.to_protobuf(response->mutable_status());
1411
1
                return;
1412
74
            } else {
1413
                // get partition ids of topic
1414
74
                std::vector<int32_t> partition_ids;
1415
74
                Status st = _exec_env->routine_load_task_executor()->get_kafka_partition_meta(
1416
74
                        request->kafka_meta_request(), &partition_ids);
1417
74
                if (st.ok()) {
1418
71
                    PKafkaMetaProxyResult* kafka_result = response->mutable_kafka_meta_result();
1419
71
                    for (int32_t id : partition_ids) {
1420
71
                        kafka_result->add_partition_ids(id);
1421
71
                    }
1422
71
                }
1423
74
                st.to_protobuf(response->mutable_status());
1424
74
                return;
1425
74
            }
1426
619
        }
1427
0
        Status::OK().to_protobuf(response->mutable_status());
1428
0
    });
1429
619
    if (!ret) {
1430
0
        offer_failed(response, done, _heavy_work_pool);
1431
0
        return;
1432
0
    }
1433
619
}
1434
1435
void PInternalService::update_cache(google::protobuf::RpcController* controller,
1436
                                    const PUpdateCacheRequest* request, PCacheResponse* response,
1437
64.2k
                                    google::protobuf::Closure* done) {
1438
64.2k
    bool ret = _light_work_pool.try_offer([this, request, response, done]() {
1439
64.2k
        brpc::ClosureGuard closure_guard(done);
1440
64.2k
        _exec_env->result_cache()->update(request, response);
1441
64.2k
    });
1442
64.2k
    if (!ret) {
1443
0
        offer_failed(response, done, _light_work_pool);
1444
0
        return;
1445
0
    }
1446
64.2k
}
1447
1448
void PInternalService::fetch_cache(google::protobuf::RpcController* controller,
1449
                                   const PFetchCacheRequest* request, PFetchCacheResult* result,
1450
3.49k
                                   google::protobuf::Closure* done) {
1451
3.49k
    bool ret = _light_work_pool.try_offer([this, request, result, done]() {
1452
3.49k
        brpc::ClosureGuard closure_guard(done);
1453
3.49k
        _exec_env->result_cache()->fetch(request, result);
1454
3.49k
    });
1455
3.49k
    if (!ret) {
1456
0
        offer_failed(result, done, _light_work_pool);
1457
0
        return;
1458
0
    }
1459
3.49k
}
1460
1461
void PInternalService::clear_cache(google::protobuf::RpcController* controller,
1462
                                   const PClearCacheRequest* request, PCacheResponse* response,
1463
0
                                   google::protobuf::Closure* done) {
1464
0
    bool ret = _light_work_pool.try_offer([this, request, response, done]() {
1465
0
        brpc::ClosureGuard closure_guard(done);
1466
0
        _exec_env->result_cache()->clear(request, response);
1467
0
    });
1468
0
    if (!ret) {
1469
0
        offer_failed(response, done, _light_work_pool);
1470
0
        return;
1471
0
    }
1472
0
}
1473
1474
void PInternalService::merge_filter(::google::protobuf::RpcController* controller,
1475
                                    const ::doris::PMergeFilterRequest* request,
1476
                                    ::doris::PMergeFilterResponse* response,
1477
2.65k
                                    ::google::protobuf::Closure* done) {
1478
2.66k
    bool ret = _light_work_pool.try_offer([this, controller, request, response, done]() {
1479
2.66k
        signal::SignalTaskIdKeeper keeper(request->query_id());
1480
2.66k
        brpc::ClosureGuard closure_guard(done);
1481
2.66k
        auto attachment = static_cast<brpc::Controller*>(controller)->request_attachment();
1482
2.66k
        butil::IOBufAsZeroCopyInputStream zero_copy_input_stream(attachment);
1483
2.66k
        Status st;
1484
2.66k
        try {
1485
2.66k
            st = _exec_env->fragment_mgr()->merge_filter(request, &zero_copy_input_stream);
1486
2.66k
        } catch (Exception& e) {
1487
0
            st = e.to_status();
1488
0
        }
1489
2.66k
        st.to_protobuf(response->mutable_status());
1490
2.65k
    });
1491
2.65k
    if (!ret) {
1492
0
        offer_failed(response, done, _light_work_pool);
1493
0
        return;
1494
0
    }
1495
2.65k
}
1496
1497
void PInternalService::send_filter_size(::google::protobuf::RpcController* controller,
1498
                                        const ::doris::PSendFilterSizeRequest* request,
1499
                                        ::doris::PSendFilterSizeResponse* response,
1500
291
                                        ::google::protobuf::Closure* done) {
1501
291
    bool ret = _light_work_pool.try_offer([this, request, response, done]() {
1502
291
        signal::SignalTaskIdKeeper keeper(request->query_id());
1503
291
        brpc::ClosureGuard closure_guard(done);
1504
291
        Status st;
1505
291
        try {
1506
291
            st = _exec_env->fragment_mgr()->send_filter_size(request);
1507
291
        } catch (Exception& e) {
1508
0
            st = e.to_status();
1509
0
        }
1510
291
        st.to_protobuf(response->mutable_status());
1511
291
    });
1512
291
    if (!ret) {
1513
0
        offer_failed(response, done, _light_work_pool);
1514
0
        return;
1515
0
    }
1516
291
}
1517
1518
void PInternalService::sync_filter_size(::google::protobuf::RpcController* controller,
1519
                                        const ::doris::PSyncFilterSizeRequest* request,
1520
                                        ::doris::PSyncFilterSizeResponse* response,
1521
291
                                        ::google::protobuf::Closure* done) {
1522
291
    bool ret = _light_work_pool.try_offer([this, request, response, done]() {
1523
291
        signal::SignalTaskIdKeeper keeper(request->query_id());
1524
291
        brpc::ClosureGuard closure_guard(done);
1525
291
        Status st;
1526
291
        try {
1527
291
            st = _exec_env->fragment_mgr()->sync_filter_size(request);
1528
291
        } catch (Exception& e) {
1529
0
            st = e.to_status();
1530
0
        }
1531
291
        st.to_protobuf(response->mutable_status());
1532
291
    });
1533
291
    if (!ret) {
1534
0
        offer_failed(response, done, _light_work_pool);
1535
0
        return;
1536
0
    }
1537
291
}
1538
1539
void PInternalService::apply_filterv2(::google::protobuf::RpcController* controller,
1540
                                      const ::doris::PPublishFilterRequestV2* request,
1541
                                      ::doris::PPublishFilterResponse* response,
1542
1.72k
                                      ::google::protobuf::Closure* done) {
1543
1.72k
    bool ret = _light_work_pool.try_offer([this, controller, request, response, done]() {
1544
1.72k
        signal::SignalTaskIdKeeper keeper(request->query_id());
1545
1.72k
        brpc::ClosureGuard closure_guard(done);
1546
1.72k
        auto attachment = static_cast<brpc::Controller*>(controller)->request_attachment();
1547
1.72k
        butil::IOBufAsZeroCopyInputStream zero_copy_input_stream(attachment);
1548
1.72k
        VLOG_NOTICE << "rpc apply_filterv2 recv";
1549
1.72k
        Status st;
1550
1.72k
        try {
1551
1.72k
            st = _exec_env->fragment_mgr()->apply_filterv2(request, &zero_copy_input_stream);
1552
1.72k
        } catch (Exception& e) {
1553
0
            st = e.to_status();
1554
0
        }
1555
1.72k
        if (!st.ok()) {
1556
0
            LOG(WARNING) << "apply filter meet error: " << st.to_string();
1557
0
        }
1558
1.71k
        st.to_protobuf(response->mutable_status());
1559
1.71k
    });
1560
1.72k
    if (!ret) {
1561
0
        offer_failed(response, done, _light_work_pool);
1562
0
        return;
1563
0
    }
1564
1.72k
}
1565
1566
void PInternalService::send_data(google::protobuf::RpcController* controller,
1567
                                 const PSendDataRequest* request, PSendDataResult* response,
1568
43
                                 google::protobuf::Closure* done) {
1569
43
    bool ret = _heavy_work_pool.try_offer([this, request, response, done]() {
1570
43
        brpc::ClosureGuard closure_guard(done);
1571
43
        TUniqueId load_id;
1572
43
        load_id.hi = request->load_id().hi();
1573
43
        load_id.lo = request->load_id().lo();
1574
        // On 1.2.3 we add load id to send data request and using load id to get pipe
1575
43
        auto stream_load_ctx = _exec_env->new_load_stream_mgr()->get(load_id);
1576
43
        if (stream_load_ctx == nullptr) {
1577
0
            response->mutable_status()->set_status_code(1);
1578
0
            response->mutable_status()->add_error_msgs("could not find stream load context");
1579
43
        } else {
1580
43
            auto pipe = stream_load_ctx->pipe;
1581
154
            for (int i = 0; i < request->data_size(); ++i) {
1582
111
                std::unique_ptr<PDataRow> row(new PDataRow());
1583
111
                row->CopyFrom(request->data(i));
1584
111
                Status s = pipe->append(std::move(row));
1585
111
                if (!s.ok()) {
1586
0
                    response->mutable_status()->set_status_code(1);
1587
0
                    response->mutable_status()->add_error_msgs(s.to_string());
1588
0
                    return;
1589
0
                }
1590
111
            }
1591
43
            response->mutable_status()->set_status_code(0);
1592
43
        }
1593
43
    });
1594
43
    if (!ret) {
1595
0
        offer_failed(response, done, _heavy_work_pool);
1596
0
        return;
1597
0
    }
1598
43
}
1599
1600
void PInternalService::commit(google::protobuf::RpcController* controller,
1601
                              const PCommitRequest* request, PCommitResult* response,
1602
43
                              google::protobuf::Closure* done) {
1603
43
    bool ret = _heavy_work_pool.try_offer([this, request, response, done]() {
1604
43
        brpc::ClosureGuard closure_guard(done);
1605
43
        TUniqueId load_id;
1606
43
        load_id.hi = request->load_id().hi();
1607
43
        load_id.lo = request->load_id().lo();
1608
1609
43
        auto stream_load_ctx = _exec_env->new_load_stream_mgr()->get(load_id);
1610
43
        if (stream_load_ctx == nullptr) {
1611
0
            response->mutable_status()->set_status_code(1);
1612
0
            response->mutable_status()->add_error_msgs("could not find stream load context");
1613
43
        } else {
1614
43
            static_cast<void>(stream_load_ctx->pipe->finish());
1615
43
            response->mutable_status()->set_status_code(0);
1616
43
        }
1617
43
    });
1618
43
    if (!ret) {
1619
0
        offer_failed(response, done, _heavy_work_pool);
1620
0
        return;
1621
0
    }
1622
43
}
1623
1624
void PInternalService::rollback(google::protobuf::RpcController* controller,
1625
                                const PRollbackRequest* request, PRollbackResult* response,
1626
5
                                google::protobuf::Closure* done) {
1627
5
    bool ret = _heavy_work_pool.try_offer([this, request, response, done]() {
1628
5
        brpc::ClosureGuard closure_guard(done);
1629
5
        TUniqueId load_id;
1630
5
        load_id.hi = request->load_id().hi();
1631
5
        load_id.lo = request->load_id().lo();
1632
5
        auto stream_load_ctx = _exec_env->new_load_stream_mgr()->get(load_id);
1633
5
        if (stream_load_ctx == nullptr) {
1634
0
            response->mutable_status()->set_status_code(1);
1635
0
            response->mutable_status()->add_error_msgs("could not find stream load context");
1636
5
        } else {
1637
5
            stream_load_ctx->pipe->cancel("rollback");
1638
5
            response->mutable_status()->set_status_code(0);
1639
5
        }
1640
5
    });
1641
5
    if (!ret) {
1642
0
        offer_failed(response, done, _heavy_work_pool);
1643
0
        return;
1644
0
    }
1645
5
}
1646
1647
void PInternalService::fold_constant_expr(google::protobuf::RpcController* controller,
1648
                                          const PConstantExprRequest* request,
1649
                                          PConstantExprResult* response,
1650
571
                                          google::protobuf::Closure* done) {
1651
571
    bool ret = _light_work_pool.try_offer([request, response, done]() {
1652
571
        brpc::ClosureGuard closure_guard(done);
1653
571
        TFoldConstantParams t_request;
1654
571
        Status st = Status::OK();
1655
571
        {
1656
571
            const uint8_t* buf = (const uint8_t*)request->request().data();
1657
571
            uint32_t len = request->request().size();
1658
571
            st = deserialize_thrift_msg(buf, &len, false, &t_request);
1659
571
        }
1660
571
        if (!st.ok()) {
1661
0
            LOG(WARNING) << "exec fold constant expr failed, errmsg=" << st
1662
0
                         << " .and query_id_is: " << t_request.query_id;
1663
0
            st.to_protobuf(response->mutable_status());
1664
0
            return;
1665
0
        }
1666
571
        auto fold_func = [&]() -> Status {
1667
571
            std::unique_ptr<FoldConstantExecutor> fold_executor =
1668
571
                    std::make_unique<FoldConstantExecutor>();
1669
571
            RETURN_IF_ERROR_OR_CATCH_EXCEPTION(
1670
571
                    fold_executor->fold_constant_vexpr(t_request, response));
1671
533
            return Status::OK();
1672
571
        };
1673
571
        st = fold_func();
1674
571
        if (!st.ok()) {
1675
38
            LOG(WARNING) << "exec fold constant expr failed, errmsg=" << st
1676
38
                         << " .and query_id_is: " << t_request.query_id;
1677
38
        }
1678
571
        st.to_protobuf(response->mutable_status());
1679
571
    });
1680
571
    if (!ret) {
1681
0
        offer_failed(response, done, _light_work_pool);
1682
0
        return;
1683
0
    }
1684
571
}
1685
1686
void PInternalService::transmit_rec_cte_block(google::protobuf::RpcController* controller,
1687
                                              const PTransmitRecCTEBlockParams* request,
1688
                                              PTransmitRecCTEBlockResult* response,
1689
3.76k
                                              google::protobuf::Closure* done) {
1690
3.76k
    bool ret = _light_work_pool.try_offer([this, request, response, done]() {
1691
3.76k
        brpc::ClosureGuard closure_guard(done);
1692
3.76k
        auto st = _exec_env->fragment_mgr()->transmit_rec_cte_block(
1693
3.76k
                UniqueId(request->query_id()).to_thrift(),
1694
3.76k
                UniqueId(request->fragment_instance_id()).to_thrift(), request->node_id(),
1695
3.76k
                request->blocks(), request->eos());
1696
3.76k
        st.to_protobuf(response->mutable_status());
1697
3.76k
    });
1698
3.76k
    if (!ret) {
1699
0
        offer_failed(response, done, _light_work_pool);
1700
0
        return;
1701
0
    }
1702
3.76k
}
1703
1704
void PInternalService::rerun_fragment(google::protobuf::RpcController* controller,
1705
                                      const PRerunFragmentParams* request,
1706
                                      PRerunFragmentResult* response,
1707
10.0k
                                      google::protobuf::Closure* done) {
1708
10.0k
    bool ret = _light_work_pool.try_offer([this, request, response, done]() {
1709
        // Use shared_ptr<ClosureGuard> so we can transfer ownership to the PFC.
1710
        // For wait_for_destroy/final_close, the guard is stored in the PFC and the RPC
1711
        // response is deferred until the PFC is fully destroyed. For rebuild/submit,
1712
        // the guard fires immediately when this lambda returns.
1713
10.0k
        std::shared_ptr<brpc::ClosureGuard> closure_guard =
1714
10.0k
                std::make_shared<brpc::ClosureGuard>(done);
1715
10.0k
        auto st = _exec_env->fragment_mgr()->rerun_fragment(
1716
10.0k
                closure_guard, UniqueId(request->query_id()).to_thrift(), request->fragment_id(),
1717
10.0k
                request->stage());
1718
10.0k
        st.to_protobuf(response->mutable_status());
1719
10.0k
    });
1720
10.0k
    if (!ret) {
1721
0
        offer_failed(response, done, _light_work_pool);
1722
0
        return;
1723
0
    }
1724
10.0k
}
1725
1726
void PInternalService::reset_global_rf(google::protobuf::RpcController* controller,
1727
                                       const PResetGlobalRfParams* request,
1728
                                       PResetGlobalRfResult* response,
1729
1.82k
                                       google::protobuf::Closure* done) {
1730
1.82k
    bool ret = _light_work_pool.try_offer([this, request, response, done]() {
1731
1.82k
        brpc::ClosureGuard closure_guard(done);
1732
1.82k
        auto st = _exec_env->fragment_mgr()->reset_global_rf(
1733
1.82k
                UniqueId(request->query_id()).to_thrift(), request->filter_ids());
1734
1.82k
        st.to_protobuf(response->mutable_status());
1735
1.82k
    });
1736
1.82k
    if (!ret) {
1737
0
        offer_failed(response, done, _light_work_pool);
1738
0
        return;
1739
0
    }
1740
1.82k
}
1741
1742
void PInternalService::transmit_block(google::protobuf::RpcController* controller,
1743
                                      const PTransmitDataParams* request,
1744
                                      PTransmitDataResult* response,
1745
2.60M
                                      google::protobuf::Closure* done) {
1746
2.60M
    int64_t receive_time = GetCurrentTimeNanos();
1747
2.63M
    if (config::enable_bthread_transmit_block) {
1748
2.63M
        response->set_receive_time(receive_time);
1749
        // under high concurrency, thread pool will have a lot of lock contention.
1750
        // May offer failed to the thread pool, so that we should avoid using thread
1751
        // pool here.
1752
2.63M
        _transmit_block(controller, request, response, done, Status::OK(), 0);
1753
18.4E
    } else {
1754
18.4E
        bool ret = _light_work_pool.try_offer([this, controller, request, response, done,
1755
18.4E
                                               receive_time]() {
1756
0
            response->set_receive_time(receive_time);
1757
            // Sometimes transmit block function is the last owner of PlanFragmentExecutor
1758
            // It will release the object. And the object maybe a JNIContext.
1759
            // JNIContext will hold some TLS object. It could not work correctly under bthread
1760
            // Context. So that put the logic into pthread.
1761
            // But this is rarely happens, so this config is disabled by default.
1762
0
            _transmit_block(controller, request, response, done, Status::OK(),
1763
0
                            GetCurrentTimeNanos() - receive_time);
1764
0
        });
1765
18.4E
        if (!ret) {
1766
0
            offer_failed(response, done, _light_work_pool);
1767
0
            return;
1768
0
        }
1769
18.4E
    }
1770
2.60M
}
1771
1772
void PInternalService::transmit_block_by_http(google::protobuf::RpcController* controller,
1773
                                              const PEmptyRequest* request,
1774
                                              PTransmitDataResult* response,
1775
0
                                              google::protobuf::Closure* done) {
1776
0
    int64_t receive_time = GetCurrentTimeNanos();
1777
0
    bool ret = _heavy_work_pool.try_offer([this, controller, response, done, receive_time]() {
1778
0
        PTransmitDataParams* new_request = new PTransmitDataParams();
1779
0
        google::protobuf::Closure* new_done =
1780
0
                new NewHttpClosure<PTransmitDataParams>(new_request, done);
1781
0
        brpc::Controller* cntl = static_cast<brpc::Controller*>(controller);
1782
0
        Status st =
1783
0
                attachment_extract_request_contain_block<PTransmitDataParams>(new_request, cntl);
1784
0
        _transmit_block(controller, new_request, response, new_done, st,
1785
0
                        GetCurrentTimeNanos() - receive_time);
1786
0
    });
1787
0
    if (!ret) {
1788
0
        offer_failed(response, done, _heavy_work_pool);
1789
0
        return;
1790
0
    }
1791
0
}
1792
1793
void PInternalService::_transmit_block(google::protobuf::RpcController* controller,
1794
                                       const PTransmitDataParams* request,
1795
                                       PTransmitDataResult* response,
1796
                                       google::protobuf::Closure* done, const Status& extract_st,
1797
2.60M
                                       const int64_t wait_for_worker) {
1798
2.61M
    if (request->has_query_id()) {
1799
18.4E
        VLOG_ROW << "transmit block: fragment_instance_id=" << print_id(request->finst_id())
1800
18.4E
                 << " query_id=" << print_id(request->query_id()) << " node=" << request->node_id();
1801
2.61M
    }
1802
1803
    // The response is accessed when done->Run is called in transmit_block(),
1804
    // give response a default value to avoid null pointers in high concurrency.
1805
2.60M
    Status st;
1806
2.60M
    if (extract_st.ok()) {
1807
2.60M
        st = _exec_env->vstream_mgr()->transmit_block(request, &done, wait_for_worker);
1808
2.60M
        if (!st.ok() && !st.is<END_OF_FILE>()) {
1809
0
            LOG(WARNING) << "transmit_block failed, message=" << st
1810
0
                         << ", fragment_instance_id=" << print_id(request->finst_id())
1811
0
                         << ", node=" << request->node_id()
1812
0
                         << ", from sender_id: " << request->sender_id()
1813
0
                         << ", be_number: " << request->be_number()
1814
0
                         << ", packet_seq: " << request->packet_seq();
1815
0
        }
1816
2.60M
    } else {
1817
214
        st = extract_st;
1818
214
    }
1819
2.62M
    if (done != nullptr) {
1820
2.62M
        st.to_protobuf(response->mutable_status());
1821
2.62M
        done->Run();
1822
2.62M
    }
1823
2.60M
}
1824
1825
void PInternalService::check_rpc_channel(google::protobuf::RpcController* controller,
1826
                                         const PCheckRPCChannelRequest* request,
1827
                                         PCheckRPCChannelResponse* response,
1828
0
                                         google::protobuf::Closure* done) {
1829
0
    bool ret = _light_work_pool.try_offer([request, response, done]() {
1830
0
        brpc::ClosureGuard closure_guard(done);
1831
0
        response->mutable_status()->set_status_code(0);
1832
0
        if (request->data().size() != request->size()) {
1833
0
            std::stringstream ss;
1834
0
            ss << "data size not same, expected: " << request->size()
1835
0
               << ", actual: " << request->data().size();
1836
0
            response->mutable_status()->add_error_msgs(ss.str());
1837
0
            response->mutable_status()->set_status_code(1);
1838
1839
0
        } else {
1840
0
            Md5Digest digest;
1841
0
            digest.update(static_cast<const void*>(request->data().c_str()),
1842
0
                          request->data().size());
1843
0
            digest.digest();
1844
0
            if (!iequal(digest.hex(), request->md5())) {
1845
0
                std::stringstream ss;
1846
0
                ss << "md5 not same, expected: " << request->md5() << ", actual: " << digest.hex();
1847
0
                response->mutable_status()->add_error_msgs(ss.str());
1848
0
                response->mutable_status()->set_status_code(1);
1849
0
            }
1850
0
        }
1851
0
    });
1852
0
    if (!ret) {
1853
0
        offer_failed(response, done, _light_work_pool);
1854
0
        return;
1855
0
    }
1856
0
}
1857
1858
void PInternalService::reset_rpc_channel(google::protobuf::RpcController* controller,
1859
                                         const PResetRPCChannelRequest* request,
1860
                                         PResetRPCChannelResponse* response,
1861
0
                                         google::protobuf::Closure* done) {
1862
0
    bool ret = _light_work_pool.try_offer([request, response, done]() {
1863
0
        brpc::ClosureGuard closure_guard(done);
1864
0
        response->mutable_status()->set_status_code(0);
1865
0
        if (request->all()) {
1866
0
            int size = ExecEnv::GetInstance()->brpc_internal_client_cache()->size();
1867
0
            if (size > 0) {
1868
0
                std::vector<std::string> endpoints;
1869
0
                ExecEnv::GetInstance()->brpc_internal_client_cache()->get_all(&endpoints);
1870
0
                ExecEnv::GetInstance()->brpc_internal_client_cache()->clear();
1871
0
                *response->mutable_channels() = {endpoints.begin(), endpoints.end()};
1872
0
            }
1873
0
        } else {
1874
0
            for (const std::string& endpoint : request->endpoints()) {
1875
0
                if (!ExecEnv::GetInstance()->brpc_internal_client_cache()->exist(endpoint)) {
1876
0
                    response->mutable_status()->add_error_msgs(endpoint + ": not found.");
1877
0
                    continue;
1878
0
                }
1879
1880
0
                if (ExecEnv::GetInstance()->brpc_internal_client_cache()->erase(endpoint)) {
1881
0
                    response->add_channels(endpoint);
1882
0
                } else {
1883
0
                    response->mutable_status()->add_error_msgs(endpoint + ": reset failed.");
1884
0
                }
1885
0
            }
1886
0
            if (request->endpoints_size() != response->channels_size()) {
1887
0
                response->mutable_status()->set_status_code(1);
1888
0
            }
1889
0
        }
1890
0
    });
1891
0
    if (!ret) {
1892
0
        offer_failed(response, done, _light_work_pool);
1893
0
        return;
1894
0
    }
1895
0
}
1896
1897
void PInternalService::hand_shake(google::protobuf::RpcController* controller,
1898
                                  const PHandShakeRequest* request, PHandShakeResponse* response,
1899
3.34k
                                  google::protobuf::Closure* done) {
1900
    // The light pool may be full. Handshake is used to check the connection state of brpc.
1901
    // Should not be interfered by the thread pool logic.
1902
3.34k
    brpc::ClosureGuard closure_guard(done);
1903
3.34k
    if (request->has_hello()) {
1904
3.34k
        response->set_hello(request->hello());
1905
3.34k
    }
1906
3.34k
    response->mutable_status()->set_status_code(0);
1907
3.34k
}
1908
1909
constexpr char HttpProtocol[] = "http://";
1910
constexpr char DownloadApiPath[] = "/api/_tablet/_download?token=";
1911
constexpr char FileParam[] = "&file=";
1912
1913
static std::string construct_url(const std::string& host_port, const std::string& token,
1914
0
                                 const std::string& path) {
1915
0
    return fmt::format("{}{}{}{}{}{}", HttpProtocol, host_port, DownloadApiPath, token, FileParam,
1916
0
                       path);
1917
0
}
1918
1919
static Status download_file_action(std::string& remote_file_url, std::string& local_file_path,
1920
0
                                   uint64_t estimate_timeout, uint64_t file_size) {
1921
0
    auto download_cb = [remote_file_url, estimate_timeout, local_file_path,
1922
0
                        file_size](HttpClient* client) {
1923
0
        RETURN_IF_ERROR(client->init(remote_file_url));
1924
0
        client->set_timeout_ms(estimate_timeout * 1000);
1925
0
        RETURN_IF_ERROR(client->download(local_file_path));
1926
1927
0
        if (file_size > 0) {
1928
            // Check file length
1929
0
            uint64_t local_file_size = std::filesystem::file_size(local_file_path);
1930
0
            if (local_file_size != file_size) {
1931
0
                LOG(WARNING) << "failed to pull rowset for slave replica. download file "
1932
0
                                "length error"
1933
0
                             << ", remote_path=" << remote_file_url << ", file_size=" << file_size
1934
0
                             << ", local_file_size=" << local_file_size;
1935
0
                return Status::InternalError("downloaded file size is not equal");
1936
0
            }
1937
0
        }
1938
1939
0
        return io::global_local_filesystem()->permission(local_file_path,
1940
0
                                                         io::LocalFileSystem::PERMS_OWNER_RW);
1941
0
    };
1942
0
    return HttpClient::execute_with_retry(DOWNLOAD_FILE_MAX_RETRY, 1, download_cb);
1943
0
}
1944
1945
void PInternalServiceImpl::request_slave_tablet_pull_rowset(
1946
        google::protobuf::RpcController* controller, const PTabletWriteSlaveRequest* request,
1947
0
        PTabletWriteSlaveResult* response, google::protobuf::Closure* done) {
1948
0
    brpc::ClosureGuard closure_guard(done);
1949
0
    const RowsetMetaPB& rowset_meta_pb = request->rowset_meta();
1950
0
    const std::string& rowset_path = request->rowset_path();
1951
0
    google::protobuf::Map<int64_t, int64_t> segments_size = request->segments_size();
1952
0
    google::protobuf::Map<int64_t, PTabletWriteSlaveRequest_IndexSizeMap> indices_size =
1953
0
            request->inverted_indices_size();
1954
0
    std::string host = request->host();
1955
0
    int64_t http_port = request->http_port();
1956
0
    int64_t brpc_port = request->brpc_port();
1957
0
    std::string token = request->token();
1958
0
    int64_t node_id = request->node_id();
1959
0
    bool ret = _heavy_work_pool.try_offer([rowset_meta_pb, host, brpc_port, node_id, segments_size,
1960
0
                                           indices_size, http_port, token, rowset_path, this]() {
1961
0
        TabletSharedPtr tablet = _engine.tablet_manager()->get_tablet(
1962
0
                rowset_meta_pb.tablet_id(), rowset_meta_pb.tablet_schema_hash());
1963
0
        if (tablet == nullptr) {
1964
0
            LOG(WARNING) << "failed to pull rowset for slave replica. tablet ["
1965
0
                         << rowset_meta_pb.tablet_id()
1966
0
                         << "] is not exist. txn_id=" << rowset_meta_pb.txn_id();
1967
0
            _response_pull_slave_rowset(host, brpc_port, rowset_meta_pb.txn_id(),
1968
0
                                        rowset_meta_pb.tablet_id(), node_id, false);
1969
0
            return;
1970
0
        }
1971
1972
0
        RowsetMetaSharedPtr rowset_meta(new RowsetMeta());
1973
0
        std::string rowset_meta_str;
1974
0
        bool ret = rowset_meta_pb.SerializeToString(&rowset_meta_str);
1975
0
        if (!ret) {
1976
0
            LOG(WARNING) << "failed to pull rowset for slave replica. serialize rowset meta "
1977
0
                            "failed. rowset_id="
1978
0
                         << rowset_meta_pb.rowset_id()
1979
0
                         << ", tablet_id=" << rowset_meta_pb.tablet_id()
1980
0
                         << ", txn_id=" << rowset_meta_pb.txn_id();
1981
0
            _response_pull_slave_rowset(host, brpc_port, rowset_meta_pb.txn_id(),
1982
0
                                        rowset_meta_pb.tablet_id(), node_id, false);
1983
0
            return;
1984
0
        }
1985
0
        bool parsed = rowset_meta->init(rowset_meta_str);
1986
0
        if (!parsed) {
1987
0
            LOG(WARNING) << "failed to pull rowset for slave replica. parse rowset meta string "
1988
0
                            "failed. rowset_id="
1989
0
                         << rowset_meta_pb.rowset_id()
1990
0
                         << ", tablet_id=" << rowset_meta_pb.tablet_id()
1991
0
                         << ", txn_id=" << rowset_meta_pb.txn_id();
1992
            // return false will break meta iterator, return true to skip this error
1993
0
            _response_pull_slave_rowset(host, brpc_port, rowset_meta->txn_id(),
1994
0
                                        rowset_meta->tablet_id(), node_id, false);
1995
0
            return;
1996
0
        }
1997
0
        RowsetId remote_rowset_id = rowset_meta->rowset_id();
1998
        // change rowset id because it maybe same as other local rowset
1999
0
        RowsetId new_rowset_id = _engine.next_rowset_id();
2000
0
        auto pending_rs_guard = _engine.pending_local_rowsets().add(new_rowset_id);
2001
0
        rowset_meta->set_rowset_id(new_rowset_id);
2002
0
        rowset_meta->set_tablet_uid(tablet->tablet_uid());
2003
0
        VLOG_CRITICAL << "succeed to init rowset meta for slave replica. rowset_id="
2004
0
                      << rowset_meta->rowset_id() << ", tablet_id=" << rowset_meta->tablet_id()
2005
0
                      << ", txn_id=" << rowset_meta->txn_id();
2006
2007
0
        auto tablet_scheme = rowset_meta->tablet_schema();
2008
0
        for (const auto& segment : segments_size) {
2009
0
            uint64_t file_size = segment.second;
2010
0
            uint64_t estimate_timeout = file_size / config::download_low_speed_limit_kbps / 1024;
2011
0
            if (estimate_timeout < config::download_low_speed_time) {
2012
0
                estimate_timeout = config::download_low_speed_time;
2013
0
            }
2014
2015
0
            std::string remote_file_path =
2016
0
                    local_segment_path(rowset_path, remote_rowset_id.to_string(), segment.first);
2017
0
            std::string remote_file_url =
2018
0
                    construct_url(get_host_port(host, http_port), token, remote_file_path);
2019
2020
0
            std::string local_file_path = local_segment_path(
2021
0
                    tablet->tablet_path(), rowset_meta->rowset_id().to_string(), segment.first);
2022
2023
0
            auto st = download_file_action(remote_file_url, local_file_path, estimate_timeout,
2024
0
                                           file_size);
2025
0
            if (!st.ok()) {
2026
0
                LOG(WARNING) << "failed to pull rowset for slave replica. failed to download "
2027
0
                                "file. url="
2028
0
                             << remote_file_url << ", local_path=" << local_file_path
2029
0
                             << ", txn_id=" << rowset_meta->txn_id();
2030
0
                _response_pull_slave_rowset(host, brpc_port, rowset_meta->txn_id(),
2031
0
                                            rowset_meta->tablet_id(), node_id, false);
2032
0
                return;
2033
0
            }
2034
0
            VLOG_CRITICAL << "succeed to download file for slave replica. url=" << remote_file_url
2035
0
                          << ", local_path=" << local_file_path
2036
0
                          << ", txn_id=" << rowset_meta->txn_id();
2037
0
            if (indices_size.find(segment.first) != indices_size.end()) {
2038
0
                PTabletWriteSlaveRequest_IndexSizeMap segment_indices_size =
2039
0
                        indices_size.at(segment.first);
2040
2041
0
                for (auto index_size : segment_indices_size.index_sizes()) {
2042
0
                    auto index_id = index_size.indexid();
2043
0
                    auto size = index_size.size();
2044
0
                    auto suffix_path = index_size.suffix_path();
2045
0
                    std::string remote_inverted_index_file;
2046
0
                    std::string local_inverted_index_file;
2047
0
                    std::string remote_inverted_index_file_url;
2048
0
                    if (tablet_scheme->get_inverted_index_storage_format() ==
2049
0
                        InvertedIndexStorageFormatPB::V1) {
2050
0
                        remote_inverted_index_file =
2051
0
                                InvertedIndexDescriptor::get_index_file_path_v1(
2052
0
                                        InvertedIndexDescriptor::get_index_file_path_prefix(
2053
0
                                                remote_file_path),
2054
0
                                        index_id, suffix_path);
2055
0
                        remote_inverted_index_file_url = construct_url(
2056
0
                                get_host_port(host, http_port), token, remote_inverted_index_file);
2057
2058
0
                        local_inverted_index_file = InvertedIndexDescriptor::get_index_file_path_v1(
2059
0
                                InvertedIndexDescriptor::get_index_file_path_prefix(
2060
0
                                        local_file_path),
2061
0
                                index_id, suffix_path);
2062
0
                    } else {
2063
0
                        remote_inverted_index_file =
2064
0
                                InvertedIndexDescriptor::get_index_file_path_v2(
2065
0
                                        InvertedIndexDescriptor::get_index_file_path_prefix(
2066
0
                                                remote_file_path));
2067
0
                        remote_inverted_index_file_url = construct_url(
2068
0
                                get_host_port(host, http_port), token, remote_inverted_index_file);
2069
2070
0
                        local_inverted_index_file = InvertedIndexDescriptor::get_index_file_path_v2(
2071
0
                                InvertedIndexDescriptor::get_index_file_path_prefix(
2072
0
                                        local_file_path));
2073
0
                    }
2074
0
                    st = download_file_action(remote_inverted_index_file_url,
2075
0
                                              local_inverted_index_file, estimate_timeout, size);
2076
0
                    if (!st.ok()) {
2077
0
                        LOG(WARNING) << "failed to pull rowset for slave replica. failed to "
2078
0
                                        "download "
2079
0
                                        "file. url="
2080
0
                                     << remote_inverted_index_file_url
2081
0
                                     << ", local_path=" << local_inverted_index_file
2082
0
                                     << ", txn_id=" << rowset_meta->txn_id();
2083
0
                        _response_pull_slave_rowset(host, brpc_port, rowset_meta->txn_id(),
2084
0
                                                    rowset_meta->tablet_id(), node_id, false);
2085
0
                        return;
2086
0
                    }
2087
2088
0
                    VLOG_CRITICAL
2089
0
                            << "succeed to download inverted index file for slave replica. url="
2090
0
                            << remote_inverted_index_file_url
2091
0
                            << ", local_path=" << local_inverted_index_file
2092
0
                            << ", txn_id=" << rowset_meta->txn_id();
2093
0
                }
2094
0
            }
2095
0
        }
2096
2097
0
        RowsetSharedPtr rowset;
2098
0
        Status create_status = RowsetFactory::create_rowset(
2099
0
                tablet->tablet_schema(), tablet->tablet_path(), rowset_meta, &rowset);
2100
0
        if (!create_status) {
2101
0
            LOG(WARNING) << "failed to create rowset from rowset meta for slave replica"
2102
0
                         << ". rowset_id: " << rowset_meta->rowset_id()
2103
0
                         << ", rowset_type: " << rowset_meta->rowset_type()
2104
0
                         << ", rowset_state: " << rowset_meta->rowset_state()
2105
0
                         << ", tablet_id=" << rowset_meta->tablet_id()
2106
0
                         << ", txn_id=" << rowset_meta->txn_id();
2107
0
            _response_pull_slave_rowset(host, brpc_port, rowset_meta->txn_id(),
2108
0
                                        rowset_meta->tablet_id(), node_id, false);
2109
0
            return;
2110
0
        }
2111
0
        if (rowset_meta->rowset_state() != RowsetStatePB::COMMITTED) {
2112
0
            LOG(WARNING) << "could not commit txn for slave replica because master rowset state is "
2113
0
                            "not committed, rowset_state="
2114
0
                         << rowset_meta->rowset_state()
2115
0
                         << ", tablet_id=" << rowset_meta->tablet_id()
2116
0
                         << ", txn_id=" << rowset_meta->txn_id();
2117
0
            _response_pull_slave_rowset(host, brpc_port, rowset_meta->txn_id(),
2118
0
                                        rowset_meta->tablet_id(), node_id, false);
2119
0
            return;
2120
0
        }
2121
0
        Status commit_txn_status = _engine.txn_manager()->commit_txn(
2122
0
                tablet->data_dir()->get_meta(), rowset_meta->partition_id(), rowset_meta->txn_id(),
2123
0
                rowset_meta->tablet_id(), tablet->tablet_uid(), rowset_meta->load_id(), rowset,
2124
0
                std::move(pending_rs_guard), false);
2125
0
        if (!commit_txn_status && !commit_txn_status.is<PUSH_TRANSACTION_ALREADY_EXIST>()) {
2126
0
            LOG(WARNING) << "failed to add committed rowset for slave replica. rowset_id="
2127
0
                         << rowset_meta->rowset_id() << ", tablet_id=" << rowset_meta->tablet_id()
2128
0
                         << ", txn_id=" << rowset_meta->txn_id();
2129
0
            _response_pull_slave_rowset(host, brpc_port, rowset_meta->txn_id(),
2130
0
                                        rowset_meta->tablet_id(), node_id, false);
2131
0
            return;
2132
0
        }
2133
0
        VLOG_CRITICAL << "succeed to pull rowset for slave replica. successfully to add committed "
2134
0
                         "rowset: "
2135
0
                      << rowset_meta->rowset_id()
2136
0
                      << " to tablet, tablet_id=" << rowset_meta->tablet_id()
2137
0
                      << ", schema_hash=" << rowset_meta->tablet_schema_hash()
2138
0
                      << ", txn_id=" << rowset_meta->txn_id();
2139
0
        _response_pull_slave_rowset(host, brpc_port, rowset_meta->txn_id(),
2140
0
                                    rowset_meta->tablet_id(), node_id, true);
2141
0
    });
2142
0
    if (!ret) {
2143
0
        offer_failed(response, closure_guard.release(), _heavy_work_pool);
2144
0
        return;
2145
0
    }
2146
0
    Status::OK().to_protobuf(response->mutable_status());
2147
0
}
2148
2149
void PInternalServiceImpl::_response_pull_slave_rowset(const std::string& remote_host,
2150
                                                       int64_t brpc_port, int64_t txn_id,
2151
                                                       int64_t tablet_id, int64_t node_id,
2152
0
                                                       bool is_succeed) {
2153
0
    std::shared_ptr<PBackendService_Stub> stub =
2154
0
            ExecEnv::GetInstance()->brpc_internal_client_cache()->get_client(remote_host,
2155
0
                                                                             brpc_port);
2156
0
    if (stub == nullptr) {
2157
0
        LOG(WARNING) << "failed to response result of slave replica to master replica. get rpc "
2158
0
                        "stub failed, master host="
2159
0
                     << remote_host << ", port=" << brpc_port << ", tablet_id=" << tablet_id
2160
0
                     << ", txn_id=" << txn_id;
2161
0
        return;
2162
0
    }
2163
2164
0
    auto request = std::make_shared<PTabletWriteSlaveDoneRequest>();
2165
0
    request->set_txn_id(txn_id);
2166
0
    request->set_tablet_id(tablet_id);
2167
0
    request->set_node_id(node_id);
2168
0
    request->set_is_succeed(is_succeed);
2169
0
    auto pull_rowset_callback = DummyBrpcCallback<PTabletWriteSlaveDoneResult>::create_shared();
2170
0
    auto closure = AutoReleaseClosure<
2171
0
            PTabletWriteSlaveDoneRequest,
2172
0
            DummyBrpcCallback<PTabletWriteSlaveDoneResult>>::create_unique(request,
2173
0
                                                                           pull_rowset_callback);
2174
0
    closure->cntl_->set_timeout_ms(config::slave_replica_writer_rpc_timeout_sec * 1000);
2175
0
    closure->cntl_->ignore_eovercrowded();
2176
0
    stub->response_slave_tablet_pull_rowset(closure->cntl_.get(), closure->request_.get(),
2177
0
                                            closure->response_.get(), closure.get());
2178
0
    closure.release();
2179
2180
0
    pull_rowset_callback->join();
2181
0
    if (pull_rowset_callback->cntl_->Failed()) {
2182
0
        LOG(WARNING) << "failed to response result of slave replica to master replica, error="
2183
0
                     << berror(pull_rowset_callback->cntl_->ErrorCode())
2184
0
                     << ", error_text=" << pull_rowset_callback->cntl_->ErrorText()
2185
0
                     << ", master host: " << remote_host << ", tablet_id=" << tablet_id
2186
0
                     << ", txn_id=" << txn_id;
2187
0
    }
2188
0
    VLOG_CRITICAL << "succeed to response the result of slave replica pull rowset to master "
2189
0
                     "replica. master host: "
2190
0
                  << remote_host << ". is_succeed=" << is_succeed << ", tablet_id=" << tablet_id
2191
0
                  << ", slave server=" << node_id << ", txn_id=" << txn_id;
2192
0
}
2193
2194
void PInternalServiceImpl::response_slave_tablet_pull_rowset(
2195
        google::protobuf::RpcController* controller, const PTabletWriteSlaveDoneRequest* request,
2196
0
        PTabletWriteSlaveDoneResult* response, google::protobuf::Closure* done) {
2197
0
    bool ret = _heavy_work_pool.try_offer([txn_mgr = _engine.txn_manager(), request, response,
2198
0
                                           done]() {
2199
0
        brpc::ClosureGuard closure_guard(done);
2200
0
        VLOG_CRITICAL << "receive the result of slave replica pull rowset from slave replica. "
2201
0
                         "slave server="
2202
0
                      << request->node_id() << ", is_succeed=" << request->is_succeed()
2203
0
                      << ", tablet_id=" << request->tablet_id() << ", txn_id=" << request->txn_id();
2204
0
        txn_mgr->finish_slave_tablet_pull_rowset(request->txn_id(), request->tablet_id(),
2205
0
                                                 request->node_id(), request->is_succeed());
2206
0
        Status::OK().to_protobuf(response->mutable_status());
2207
0
    });
2208
0
    if (!ret) {
2209
0
        offer_failed(response, done, _heavy_work_pool);
2210
0
        return;
2211
0
    }
2212
0
}
2213
2214
void PInternalService::multiget_data(google::protobuf::RpcController* controller,
2215
                                     const PMultiGetRequest* request, PMultiGetResponse* response,
2216
8
                                     google::protobuf::Closure* done) {
2217
8
    bool ret = _heavy_work_pool.try_offer([request, response, done]() {
2218
8
        signal::SignalTaskIdKeeper keeper(request->query_id());
2219
        // multi get data by rowid
2220
8
        MonotonicStopWatch watch;
2221
8
        watch.start();
2222
8
        brpc::ClosureGuard closure_guard(done);
2223
8
        response->mutable_status()->set_status_code(0);
2224
8
        SCOPED_ATTACH_TASK(ExecEnv::GetInstance()->rowid_storage_reader_tracker());
2225
8
        Status st = RowIdStorageReader::read_by_rowids(*request, response);
2226
8
        st.to_protobuf(response->mutable_status());
2227
8
        LOG(INFO) << "multiget_data finished, cost(us):" << watch.elapsed_time() / 1000;
2228
8
    });
2229
8
    if (!ret) {
2230
0
        offer_failed(response, done, _heavy_work_pool);
2231
0
        return;
2232
0
    }
2233
8
}
2234
2235
void PInternalService::multiget_data_v2(google::protobuf::RpcController* controller,
2236
                                        const PMultiGetRequestV2* request,
2237
                                        PMultiGetResponseV2* response,
2238
2.93k
                                        google::protobuf::Closure* done) {
2239
2.93k
    std::vector<uint64_t> id_set;
2240
2.93k
    id_set.push_back(request->wg_id());
2241
2.93k
    auto wg = ExecEnv::GetInstance()->workload_group_mgr()->get_group(id_set);
2242
2.93k
    Status st = Status::OK();
2243
2244
2.93k
    if (!wg) [[unlikely]] {
2245
0
        brpc::ClosureGuard closure_guard(done);
2246
0
        st = Status::Error<TStatusCode::CANCELLED>("fail to find wg: wg id:" +
2247
0
                                                   std::to_string(request->wg_id()));
2248
0
        st.to_protobuf(response->mutable_status());
2249
0
        return;
2250
0
    }
2251
2252
2.93k
    doris::TaskScheduler* exec_sched = nullptr;
2253
2.93k
    ScannerScheduler* scan_sched = nullptr;
2254
2.93k
    ScannerScheduler* remote_scan_sched = nullptr;
2255
2.93k
    wg->get_query_scheduler(&exec_sched, &scan_sched, &remote_scan_sched);
2256
2.93k
    DCHECK(remote_scan_sched);
2257
2258
2.93k
    st = remote_scan_sched->submit_scan_task(
2259
2.93k
            SimplifiedScanTask(
2260
2.93k
                    [request, response, done]() {
2261
2.93k
                        SCOPED_ATTACH_TASK(ExecEnv::GetInstance()->rowid_storage_reader_tracker());
2262
2.93k
                        signal::set_signal_task_id(request->query_id());
2263
                        // multi get data by rowid
2264
2.93k
                        MonotonicStopWatch watch;
2265
2.93k
                        watch.start();
2266
2.93k
                        brpc::ClosureGuard closure_guard(done);
2267
2.93k
                        response->mutable_status()->set_status_code(0);
2268
2.93k
                        Status st = RowIdStorageReader::read_by_rowids(*request, response);
2269
2.93k
                        st.to_protobuf(response->mutable_status());
2270
2.93k
                        LOG(INFO) << "multiget_data finished, cost(us):"
2271
2.93k
                                  << watch.elapsed_time() / 1000;
2272
2.93k
                        return true;
2273
2.93k
                    },
2274
2.93k
                    nullptr, nullptr),
2275
2.93k
            fmt::format("{}-multiget_data_v2", print_id(request->query_id())));
2276
2277
2.93k
    if (!st.ok()) {
2278
0
        brpc::ClosureGuard closure_guard(done);
2279
0
        st.to_protobuf(response->mutable_status());
2280
0
    }
2281
2.93k
}
2282
2283
void PInternalServiceImpl::get_tablet_rowset_versions(google::protobuf::RpcController* cntl_base,
2284
                                                      const PGetTabletVersionsRequest* request,
2285
                                                      PGetTabletVersionsResponse* response,
2286
0
                                                      google::protobuf::Closure* done) {
2287
0
    brpc::ClosureGuard closure_guard(done);
2288
0
    VLOG_DEBUG << "receive get tablet versions request: " << request->DebugString();
2289
0
    _engine.get_tablet_rowset_versions(request, response);
2290
0
}
2291
2292
void PInternalService::glob(google::protobuf::RpcController* controller,
2293
                            const PGlobRequest* request, PGlobResponse* response,
2294
429
                            google::protobuf::Closure* done) {
2295
429
    bool ret = _heavy_work_pool.try_offer([request, response, done]() {
2296
429
        brpc::ClosureGuard closure_guard(done);
2297
429
        std::vector<io::FileInfo> files;
2298
429
        Status st = io::global_local_filesystem()->safe_glob(request->pattern(), &files);
2299
429
        if (st.ok()) {
2300
424
            for (auto& file : files) {
2301
424
                PGlobResponse_PFileInfo* pfile = response->add_files();
2302
424
                pfile->set_file(file.file_name);
2303
424
                pfile->set_size(file.file_size);
2304
424
            }
2305
414
        }
2306
429
        st.to_protobuf(response->mutable_status());
2307
429
    });
2308
429
    if (!ret) {
2309
0
        offer_failed(response, done, _heavy_work_pool);
2310
0
        return;
2311
0
    }
2312
429
}
2313
2314
void PInternalService::group_commit_insert(google::protobuf::RpcController* controller,
2315
                                           const PGroupCommitInsertRequest* request,
2316
                                           PGroupCommitInsertResponse* response,
2317
29
                                           google::protobuf::Closure* done) {
2318
29
    TUniqueId load_id;
2319
29
    load_id.__set_hi(request->load_id().hi());
2320
29
    load_id.__set_lo(request->load_id().lo());
2321
29
    std::shared_ptr<std::mutex> lock = std::make_shared<std::mutex>();
2322
29
    std::shared_ptr<bool> is_done = std::make_shared<bool>(false);
2323
29
    bool ret = _heavy_work_pool.try_offer([this, request, response, done, load_id, lock,
2324
29
                                           is_done]() {
2325
29
        brpc::ClosureGuard closure_guard(done);
2326
29
        std::shared_ptr<StreamLoadContext> ctx = std::make_shared<StreamLoadContext>(_exec_env);
2327
29
        auto pipe = std::make_shared<io::StreamLoadPipe>(
2328
29
                io::kMaxPipeBufferedBytes /* max_buffered_bytes */, 64 * 1024 /* min_chunk_size */,
2329
29
                -1 /* total_length */, true /* use_proto */);
2330
29
        ctx->pipe = pipe;
2331
29
        Status st = _exec_env->new_load_stream_mgr()->put(load_id, ctx);
2332
29
        if (st.ok()) {
2333
29
            try {
2334
29
                st = _exec_plan_fragment_impl(
2335
29
                        request->exec_plan_fragment_request().request(),
2336
29
                        request->exec_plan_fragment_request().version(),
2337
29
                        request->exec_plan_fragment_request().compact(),
2338
29
                        [&, response, done, load_id, lock, is_done](RuntimeState* state,
2339
29
                                                                    Status* status) {
2340
29
                            std::lock_guard<std::mutex> lock1(*lock);
2341
29
                            if (*is_done) {
2342
0
                                return;
2343
0
                            }
2344
29
                            *is_done = true;
2345
29
                            brpc::ClosureGuard cb_closure_guard(done);
2346
29
                            response->set_label(state->import_label());
2347
29
                            response->set_txn_id(state->wal_id());
2348
29
                            response->set_loaded_rows(state->num_rows_load_success());
2349
29
                            response->set_filtered_rows(state->num_rows_load_filtered());
2350
29
                            status->to_protobuf(response->mutable_status());
2351
29
                            if (!state->get_error_log_file_path().empty()) {
2352
0
                                response->set_error_url(
2353
0
                                        to_load_error_http_path(state->get_error_log_file_path()));
2354
0
                            }
2355
29
                            if (!state->get_first_error_msg().empty()) {
2356
0
                                response->set_first_error_msg(state->get_first_error_msg());
2357
0
                            }
2358
29
                            _exec_env->new_load_stream_mgr()->remove(load_id);
2359
29
                        });
2360
29
            } catch (const Exception& e) {
2361
0
                st = e.to_status();
2362
0
            } catch (const std::exception& e) {
2363
0
                st = Status::Error(ErrorCode::INTERNAL_ERROR, e.what());
2364
0
            } catch (...) {
2365
0
                st = Status::Error(ErrorCode::INTERNAL_ERROR,
2366
0
                                   "_exec_plan_fragment_impl meet unknown error");
2367
0
            }
2368
29
            if (!st.ok()) {
2369
0
                LOG(WARNING) << "exec plan fragment failed, load_id=" << print_id(load_id)
2370
0
                             << ", errmsg=" << st;
2371
0
                std::lock_guard<std::mutex> lock1(*lock);
2372
0
                if (*is_done) {
2373
0
                    closure_guard.release();
2374
0
                } else {
2375
0
                    *is_done = true;
2376
0
                    st.to_protobuf(response->mutable_status());
2377
0
                    _exec_env->new_load_stream_mgr()->remove(load_id);
2378
0
                }
2379
29
            } else {
2380
29
                closure_guard.release();
2381
66
                for (int i = 0; i < request->data().size(); ++i) {
2382
37
                    std::unique_ptr<PDataRow> row(new PDataRow());
2383
37
                    row->CopyFrom(request->data(i));
2384
37
                    st = pipe->append(std::move(row));
2385
37
                    if (!st.ok()) {
2386
0
                        break;
2387
0
                    }
2388
37
                }
2389
29
                if (st.ok()) {
2390
29
                    static_cast<void>(pipe->finish());
2391
29
                }
2392
29
            }
2393
29
        }
2394
29
    });
2395
29
    if (!ret) {
2396
0
        _exec_env->new_load_stream_mgr()->remove(load_id);
2397
0
        offer_failed(response, done, _heavy_work_pool);
2398
0
        return;
2399
0
    }
2400
29
};
2401
2402
void PInternalService::get_wal_queue_size(google::protobuf::RpcController* controller,
2403
                                          const PGetWalQueueSizeRequest* request,
2404
                                          PGetWalQueueSizeResponse* response,
2405
1.14k
                                          google::protobuf::Closure* done) {
2406
1.15k
    bool ret = _heavy_work_pool.try_offer([this, request, response, done]() {
2407
1.15k
        brpc::ClosureGuard closure_guard(done);
2408
1.15k
        Status st = Status::OK();
2409
1.15k
        auto table_id = request->table_id();
2410
1.15k
        auto count = _exec_env->wal_mgr()->get_wal_queue_size(table_id);
2411
1.15k
        response->set_size(count);
2412
1.15k
        response->mutable_status()->set_status_code(st.code());
2413
1.15k
    });
2414
1.14k
    if (!ret) {
2415
0
        offer_failed(response, done, _heavy_work_pool);
2416
0
    }
2417
1.14k
}
2418
2419
void PInternalService::get_be_resource(google::protobuf::RpcController* controller,
2420
                                       const PGetBeResourceRequest* request,
2421
                                       PGetBeResourceResponse* response,
2422
0
                                       google::protobuf::Closure* done) {
2423
0
    bool ret = _heavy_work_pool.try_offer([response, done]() {
2424
0
        brpc::ClosureGuard closure_guard(done);
2425
0
        int64_t mem_limit = MemInfo::mem_limit();
2426
0
        int64_t mem_usage = PerfCounters::get_vm_rss();
2427
2428
0
        PGlobalResourceUsage* global_resource_usage = response->mutable_global_be_resource_usage();
2429
0
        global_resource_usage->set_mem_limit(mem_limit);
2430
0
        global_resource_usage->set_mem_usage(mem_usage);
2431
2432
0
        Status st = Status::OK();
2433
0
        response->mutable_status()->set_status_code(st.code());
2434
0
    });
2435
0
    if (!ret) {
2436
0
        offer_failed(response, done, _heavy_work_pool);
2437
0
    }
2438
0
}
2439
2440
void PInternalService::delete_dictionary(google::protobuf::RpcController* controller,
2441
                                         const PDeleteDictionaryRequest* request,
2442
                                         PDeleteDictionaryResponse* response,
2443
3
                                         google::protobuf::Closure* done) {
2444
3
    brpc::ClosureGuard closure_guard(done);
2445
3
    Status st = ExecEnv::GetInstance()->dict_factory()->delete_dict(request->dictionary_id());
2446
3
    st.to_protobuf(response->mutable_status());
2447
3
}
2448
2449
void PInternalService::commit_refresh_dictionary(google::protobuf::RpcController* controller,
2450
                                                 const PCommitRefreshDictionaryRequest* request,
2451
                                                 PCommitRefreshDictionaryResponse* response,
2452
86
                                                 google::protobuf::Closure* done) {
2453
86
    brpc::ClosureGuard closure_guard(done);
2454
86
    Status st = ExecEnv::GetInstance()->dict_factory()->commit_refresh_dict(
2455
86
            request->dictionary_id(), request->version_id());
2456
86
    st.to_protobuf(response->mutable_status());
2457
86
}
2458
2459
void PInternalService::abort_refresh_dictionary(google::protobuf::RpcController* controller,
2460
                                                const PAbortRefreshDictionaryRequest* request,
2461
                                                PAbortRefreshDictionaryResponse* response,
2462
3
                                                google::protobuf::Closure* done) {
2463
3
    brpc::ClosureGuard closure_guard(done);
2464
3
    Status st = ExecEnv::GetInstance()->dict_factory()->abort_refresh_dict(request->dictionary_id(),
2465
3
                                                                           request->version_id());
2466
3
    st.to_protobuf(response->mutable_status());
2467
3
}
2468
2469
void PInternalService::get_tablet_rowsets(google::protobuf::RpcController* controller,
2470
                                          const PGetTabletRowsetsRequest* request,
2471
                                          PGetTabletRowsetsResponse* response,
2472
0
                                          google::protobuf::Closure* done) {
2473
0
    DCHECK(config::is_cloud_mode());
2474
0
    auto start_time = GetMonoTimeMicros();
2475
0
    Defer defer {
2476
0
            [&]() { g_process_remote_fetch_rowsets_latency << GetMonoTimeMicros() - start_time; }};
2477
0
    brpc::ClosureGuard closure_guard(done);
2478
0
    LOG(INFO) << "process get tablet rowsets, request=" << request->ShortDebugString();
2479
0
    if (!request->has_tablet_id() || !request->has_version_start() || !request->has_version_end()) {
2480
0
        Status::InvalidArgument("missing params tablet/version_start/version_end")
2481
0
                .to_protobuf(response->mutable_status());
2482
0
        return;
2483
0
    }
2484
0
    CloudStorageEngine& storage = ExecEnv::GetInstance()->storage_engine().to_cloud();
2485
2486
0
    auto maybe_tablet =
2487
0
            storage.tablet_mgr().get_tablet(request->tablet_id(), /*warmup data*/ false,
2488
0
                                            /*syn_delete_bitmap*/ false, /*delete_bitmap*/ nullptr,
2489
0
                                            /*local_only*/ true);
2490
0
    if (!maybe_tablet) {
2491
0
        maybe_tablet.error().to_protobuf(response->mutable_status());
2492
0
        return;
2493
0
    }
2494
0
    auto tablet = maybe_tablet.value();
2495
0
    Result<CaptureRowsetResult> ret;
2496
0
    {
2497
0
        std::shared_lock l(tablet->get_header_lock());
2498
0
        ret = tablet->capture_consistent_rowsets_unlocked(
2499
0
                {request->version_start(), request->version_end()},
2500
0
                CaptureRowsetOps {.enable_fetch_rowsets_from_peers = false});
2501
0
    }
2502
0
    if (!ret) {
2503
0
        ret.error().to_protobuf(response->mutable_status());
2504
0
        return;
2505
0
    }
2506
0
    auto rowsets = std::move(ret.value().rowsets);
2507
0
    for (const auto& rs : rowsets) {
2508
0
        RowsetMetaPB meta;
2509
0
        rs->rowset_meta()->to_rowset_pb(&meta);
2510
0
        response->mutable_rowsets()->Add(std::move(meta));
2511
0
    }
2512
0
    if (request->has_delete_bitmap_keys()) {
2513
0
        DCHECK(tablet->enable_unique_key_merge_on_write());
2514
0
        auto delete_bitmap = std::move(ret.value().delete_bitmap);
2515
0
        auto keys_pb = request->delete_bitmap_keys();
2516
0
        size_t len = keys_pb.rowset_ids().size();
2517
0
        DCHECK_EQ(len, keys_pb.segment_ids().size());
2518
0
        DCHECK_EQ(len, keys_pb.versions().size());
2519
0
        std::set<DeleteBitmap::BitmapKey> keys;
2520
0
        for (size_t i = 0; i < len; ++i) {
2521
0
            RowsetId rs_id;
2522
0
            rs_id.init(keys_pb.rowset_ids(i));
2523
0
            keys.emplace(rs_id, keys_pb.segment_ids(i), keys_pb.versions(i));
2524
0
        }
2525
0
        auto diffset = delete_bitmap->diffset(keys).to_pb();
2526
0
        *response->mutable_delete_bitmap() = std::move(diffset);
2527
0
    }
2528
0
    Status::OK().to_protobuf(response->mutable_status());
2529
0
}
2530
2531
void PInternalService::request_cdc_client(google::protobuf::RpcController* controller,
2532
                                          const PRequestCdcClientRequest* request,
2533
                                          PRequestCdcClientResult* result,
2534
1.06k
                                          google::protobuf::Closure* done) {
2535
1.06k
    bool ret = _heavy_work_pool.try_offer([this, request, result, done]() {
2536
1.06k
        _exec_env->cdc_client_mgr()->request_cdc_client_impl(request, result, done);
2537
1.06k
    });
2538
2539
1.06k
    if (!ret) {
2540
0
        offer_failed(result, done, _heavy_work_pool);
2541
0
        return;
2542
0
    }
2543
1.06k
}
2544
2545
#include "common/compile_check_avoid_end.h"
2546
} // namespace doris