Coverage Report

Created: 2026-09-17 18:54

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