Coverage Report

Created: 2026-08-04 11:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/agent/agent_server.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 "agent/agent_server.h"
19
20
#include <gen_cpp/AgentService_types.h>
21
#include <gen_cpp/HeartbeatService_types.h>
22
#include <gen_cpp/Types_types.h>
23
#include <stdint.h>
24
#include <thrift/protocol/TDebugProtocol.h>
25
26
#include <filesystem>
27
#include <memory>
28
#include <ostream>
29
#include <string>
30
31
#include "agent/task_worker_pool.h"
32
#include "agent/topic_subscriber.h"
33
#include "agent/utils.h"
34
#include "agent/workload_group_listener.h"
35
#include "agent/workload_sched_policy_listener.h"
36
#include "cloud/config.h"
37
#include "common/config.h"
38
#include "common/logging.h"
39
#include "common/status.h"
40
#include "runtime/cluster_info.h"
41
#include "runtime/exec_env.h"
42
#include "storage/olap_define.h"
43
#include "storage/options.h"
44
#include "storage/snapshot/snapshot_manager.h"
45
#include "storage/storage_engine.h"
46
#include "util/work_thread_pool.hpp"
47
48
namespace doris {
49
50
AgentServer::AgentServer(ExecEnv* exec_env, const ClusterInfo* cluster_info)
51
6
        : _cluster_info(cluster_info), _topic_subscriber(new TopicSubscriber()) {
52
6
    MasterServerClient::create(cluster_info);
53
54
6
#if !defined(BE_TEST) && !defined(__APPLE__)
55
    // Add subscriber here and register listeners
56
6
    std::unique_ptr<TopicListener> wg_listener = std::make_unique<WorkloadGroupListener>(exec_env);
57
6
    LOG(INFO) << "Register workload group listener";
58
6
    _topic_subscriber->register_listener(doris::TTopicInfoType::type::WORKLOAD_GROUP,
59
6
                                         std::move(wg_listener));
60
61
6
    std::unique_ptr<TopicListener> policy_listener =
62
6
            std::make_unique<WorkloadschedPolicyListener>(exec_env);
63
6
    LOG(INFO) << "Register workload scheduler policy listener";
64
6
    _topic_subscriber->register_listener(doris::TTopicInfoType::type::WORKLOAD_SCHED_POLICY,
65
6
                                         std::move(policy_listener));
66
67
6
#endif
68
6
}
69
70
2
AgentServer::~AgentServer() = default;
71
72
class PushTaskWorkerPool final : public TaskWorkerPoolIf {
73
public:
74
    PushTaskWorkerPool(StorageEngine& engine)
75
            : _push_delete_workers(
76
5
                      TaskWorkerPool("DELETE", config::delete_worker_count,
77
22
                                     [&engine](auto&& task) { push_callback(engine, task); })),
78
5
              _push_load_workers(PriorTaskWorkerPool(
79
5
                      "PUSH", config::push_worker_count_normal_priority,
80
5
                      config::push_worker_count_high_priority,
81
5
                      [&engine](auto&& task) { push_callback(engine, task); })) {}
82
83
2
    ~PushTaskWorkerPool() override { stop(); }
84
85
2
    void stop() {
86
2
        _push_delete_workers.stop();
87
2
        _push_load_workers.stop();
88
2
    }
89
90
22
    Status submit_task(const TAgentTaskRequest& task) override {
91
22
        if (task.push_req.push_type == TPushType::LOAD_V2) {
92
0
            return _push_load_workers.submit_task(task);
93
22
        } else if (task.push_req.push_type == TPushType::DELETE) {
94
22
            return _push_delete_workers.submit_task(task);
95
22
        } else {
96
0
            return Status::InvalidArgument(
97
0
                    "task(signature={}, type={}, push_type={}) has wrong push_type", task.signature,
98
0
                    task.task_type, task.push_req.push_type);
99
0
        }
100
22
    }
101
102
private:
103
    TaskWorkerPool _push_delete_workers;
104
    PriorTaskWorkerPool _push_load_workers;
105
};
106
107
5
void AgentServer::start_workers(StorageEngine& engine, ExecEnv* exec_env) {
108
8
    for (const auto& path : exec_env->store_paths()) {
109
8
        try {
110
8
            std::string dpp_download_path_str = path.path + "/" + DPP_PREFIX;
111
8
            std::filesystem::path dpp_download_path(dpp_download_path_str);
112
8
            if (std::filesystem::exists(dpp_download_path)) {
113
0
                std::filesystem::remove_all(dpp_download_path);
114
0
            }
115
8
        } catch (...) {
116
0
            LOG(WARNING) << "boost exception when remove dpp download path. path=" << path.path;
117
0
        }
118
8
    }
119
120
    // clang-format off
121
5
    _workers[TTaskType::ALTER_INVERTED_INDEX] = std::make_unique<TaskWorkerPool>(
122
5
        "ALTER_INVERTED_INDEX", config::alter_index_worker_count, [&engine](auto&& task) { return alter_inverted_index_callback(engine, task); });
123
124
5
    _workers[TTaskType::CHECK_CONSISTENCY] = std::make_unique<TaskWorkerPool>(
125
5
        "CHECK_CONSISTENCY", config::check_consistency_worker_count, [&engine](auto&& task) { return check_consistency_callback(engine, task); });
126
127
5
    _workers[TTaskType::UPLOAD] = std::make_unique<TaskWorkerPool>(
128
16
            "UPLOAD", config::upload_worker_count, [&engine, exec_env](auto&& task) { return upload_callback(engine, exec_env, task); });
129
130
5
    _workers[TTaskType::DOWNLOAD] = std::make_unique<TaskWorkerPool>(
131
22
            "DOWNLOAD", config::download_worker_count, [&engine, exec_env](auto&& task) { return download_callback(engine, exec_env, task); });
132
133
5
    _workers[TTaskType::MAKE_SNAPSHOT] = std::make_unique<TaskWorkerPool>(
134
320
            "MAKE_SNAPSHOT", config::make_snapshot_worker_count, [&engine](auto&& task) { return make_snapshot_callback(engine, task); });
135
136
5
    _workers[TTaskType::RELEASE_SNAPSHOT] = std::make_unique<TaskWorkerPool>(
137
320
            "RELEASE_SNAPSHOT", config::release_snapshot_worker_count, [&engine](auto&& task) { return release_snapshot_callback(engine, task); });
138
139
5
    _workers[TTaskType::MOVE] = std::make_unique<TaskWorkerPool>(
140
172
            "MOVE", 1, [&engine, exec_env](auto&& task) { return move_dir_callback(engine, exec_env, task); });
141
142
5
    _workers[TTaskType::COMPACTION] = std::make_unique<TaskWorkerPool>(
143
5
            "SUBMIT_TABLE_COMPACTION", 1, [&engine](auto&& task) { return submit_table_compaction_callback(engine, task); });
144
145
5
    _workers[TTaskType::PUSH_STORAGE_POLICY] = std::make_unique<TaskWorkerPool>(
146
11
            "PUSH_STORAGE_POLICY", 1, [&engine](auto&& task) { return push_storage_policy_callback(engine, task); });
147
148
5
    _workers[TTaskType::PUSH_INDEX_POLICY] = std::make_unique<TaskWorkerPool>(
149
5
            "PUSH_INDEX_POLICY", 1, [](auto&& task) { return push_index_policy_callback(task); });
150
151
5
    _workers[TTaskType::PUSH_COOLDOWN_CONF] = std::make_unique<TaskWorkerPool>(
152
5
            "PUSH_COOLDOWN_CONF", 1, [&engine](auto&& task) { return push_cooldown_conf_callback(engine, task); });
153
154
5
    _workers[TTaskType::CREATE] = std::make_unique<TaskWorkerPool>(
155
8.10k
            "CREATE_TABLE", config::create_tablet_worker_count, [&engine](auto&& task) { return create_tablet_callback(engine, task); });
156
157
5
    _workers[TTaskType::DROP] = std::make_unique<TaskWorkerPool>(
158
5.60k
            "DROP_TABLE", config::drop_tablet_worker_count, [&engine](auto&& task) { return drop_tablet_callback(engine, task); });
159
160
5
    _workers[TTaskType::PUBLISH_VERSION] = std::make_unique<PublishVersionWorkerPool>(engine);
161
162
5
    _workers[TTaskType::CLEAR_TRANSACTION_TASK] = std::make_unique<TaskWorkerPool>(
163
28
            "CLEAR_TRANSACTION_TASK", config::clear_transaction_task_worker_count, [&engine](auto&& task) { return clear_transaction_task_callback(engine, task); });
164
165
5
    _workers[TTaskType::PUSH] = std::make_unique<PushTaskWorkerPool>(engine);
166
167
5
    _workers[TTaskType::UPDATE_TABLET_META_INFO] = std::make_unique<TaskWorkerPool>(
168
5
            "UPDATE_TABLET_META_INFO", 1, [&engine](auto&& task) { return update_tablet_meta_callback(engine, task); });
169
170
5
    _workers[TTaskType::ALTER] = std::make_unique<TaskWorkerPool>(
171
20
            "ALTER_TABLE", config::alter_tablet_worker_count, [&engine](auto&& task) { return alter_tablet_callback(engine, task); });
172
173
5
    _workers[TTaskType::CLONE] = std::make_unique<PriorTaskWorkerPool>(
174
5
            "CLONE", config::clone_worker_count,config::clone_worker_count, [&engine, &cluster_info = _cluster_info](auto&& task) { return clone_callback(engine, cluster_info, task); });
175
176
5
    _workers[TTaskType::STORAGE_MEDIUM_MIGRATE] = std::make_unique<TaskWorkerPool>(
177
5
            "STORAGE_MEDIUM_MIGRATE", config::storage_medium_migrate_count, [&engine](auto&& task) { return storage_medium_migrate_callback(engine, task); });
178
179
5
    _workers[TTaskType::GC_BINLOG] = std::make_unique<TaskWorkerPool>(
180
5
            "GC_BINLOG", 1, [&engine](auto&& task) { return gc_binlog_callback(engine, task); });
181
182
5
    _workers[TTaskType::CLEAN_TRASH] = std::make_unique<TaskWorkerPool>(
183
5
            "CLEAN_TRASH", 1, [&engine](auto&& task) {return clean_trash_callback(engine, task); });
184
185
5
    _workers[TTaskType::CLEAN_UDF_CACHE] = std::make_unique<TaskWorkerPool>(
186
5
            "CLEAN_UDF_CACHE", 1, [](auto&& task) {return clean_udf_cache_callback(task); });
187
188
5
    _workers[TTaskType::UPDATE_VISIBLE_VERSION] = std::make_unique<TaskWorkerPool>(
189
6.04k
            "UPDATE_VISIBLE_VERSION", 1, [&engine](auto&& task) { return visible_version_callback(engine, task); });
190
191
5
    _report_workers.push_back(std::make_unique<ReportWorker>(
192
882
            "REPORT_TASK", _cluster_info, config::report_task_interval_seconds, [&cluster_info = _cluster_info] { report_task_callback(cluster_info); }));
193
194
5
    _report_workers.push_back(std::make_unique<ReportWorker>(
195
386
            "REPORT_DISK_STATE", _cluster_info, config::report_disk_state_interval_seconds, [&engine, &cluster_info = _cluster_info] { report_disk_callback(engine, cluster_info); }));
196
197
5
    _report_workers.push_back(std::make_unique<ReportWorker>(
198
185
            "REPORT_OLAP_TABLET", _cluster_info, config::report_tablet_interval_seconds,[&engine, &cluster_info = _cluster_info] { report_tablet_callback(engine, cluster_info); }));
199
200
5
    _report_workers.push_back(std::make_unique<ReportWorker>(
201
1.14k
            "REPORT_INDEX_POLICY", _cluster_info, config::report_index_policy_interval_seconds,[&cluster_info = _cluster_info] { report_index_policy_callback(cluster_info); }));
202
    // clang-format on
203
204
5
    exec_env->storage_engine().to_local().workers = &_workers;
205
5
}
206
207
1
void AgentServer::cloud_start_workers(CloudStorageEngine& engine, ExecEnv* exec_env) {
208
1
    _workers[TTaskType::PUSH] = std::make_unique<TaskWorkerPool>(
209
1
            "PUSH", config::delete_worker_count,
210
3.18k
            [&engine](auto&& task) { cloud_push_callback(engine, task); });
211
212
1
    _workers[TTaskType::COMPACTION] = std::make_unique<TaskWorkerPool>(
213
1
            "SUBMIT_TABLE_COMPACTION", 1,
214
3
            [&engine](auto&& task) { cloud_submit_table_compaction_callback(engine, task); });
215
216
1
    _workers[TTaskType::ALTER] = std::make_unique<TaskWorkerPool>(
217
1
            "ALTER_TABLE", config::alter_tablet_worker_count,
218
11.2k
            [&engine](auto&& task) { return alter_cloud_tablet_callback(engine, task); },
219
11.2k
            [&engine](auto&& task) { set_alter_version_before_enqueue(engine, task); });
220
221
1
    _workers[TTaskType::CALCULATE_DELETE_BITMAP] = std::make_unique<TaskWorkerPool>(
222
1
            "CALC_DBM_TASK", config::calc_delete_bitmap_worker_count,
223
8.65k
            [&engine](auto&& task) { return calc_delete_bitmap_callback(engine, task); });
224
225
    // cloud, drop tablet just clean clear_cache, so just one thread do it
226
1
    _workers[TTaskType::DROP] = std::make_unique<TaskWorkerPool>(
227
1
            "DROP_TABLE", 1, [&engine](auto&& task) { return drop_tablet_callback(engine, task); });
228
229
1
    _workers[TTaskType::PUSH_INDEX_POLICY] = std::make_unique<TaskWorkerPool>(
230
15
            "PUSH_INDEX_POLICY", 1, [](auto&& task) { return push_index_policy_callback(task); });
231
232
1
    _workers[TTaskType::DOWNLOAD] = std::make_unique<TaskWorkerPool>(
233
1
            "DOWNLOAD", config::download_worker_count,
234
1
            [&engine, exec_env](auto&& task) { return download_callback(engine, exec_env, task); });
235
236
1
    _workers[TTaskType::MOVE] = std::make_unique<TaskWorkerPool>(
237
1
            "MOVE", 1,
238
1
            [&engine, exec_env](auto&& task) { return move_dir_callback(engine, exec_env, task); });
239
240
1
    _workers[TTaskType::RELEASE_SNAPSHOT] = std::make_unique<TaskWorkerPool>(
241
1
            "RELEASE_SNAPSHOT", config::release_snapshot_worker_count,
242
1
            [&engine](auto&& task) { return release_snapshot_callback(engine, task); });
243
244
1
    _workers[TTaskType::ALTER_INVERTED_INDEX] = std::make_unique<TaskWorkerPool>(
245
1
            "ALTER_INVERTED_INDEX", config::alter_index_worker_count,
246
586
            [&engine](auto&& task) { return alter_cloud_index_callback(engine, task); });
247
248
1
    _workers[TTaskType::MAKE_CLOUD_COMMITTED_RS_VISIBLE] = std::make_unique<TaskWorkerPool>(
249
1
            "MAKE_CLOUD_COMMITTED_RS_VISIBLE", config::cloud_make_committed_rs_visible_worker_count,
250
27.4k
            [&engine](auto&& task) {
251
27.4k
                return make_cloud_committed_rs_visible_callback(engine, task);
252
27.4k
            });
253
254
1
    _report_workers.push_back(std::make_unique<ReportWorker>(
255
1
            "REPORT_TASK", _cluster_info, config::report_task_interval_seconds,
256
293
            [&cluster_info = _cluster_info] { report_task_callback(cluster_info); }));
257
258
1
    _report_workers.push_back(std::make_unique<ReportWorker>(
259
1
            "REPORT_DISK_STATE", _cluster_info, config::report_disk_state_interval_seconds,
260
116
            [&engine, &cluster_info = _cluster_info] {
261
116
                report_disk_callback(engine, cluster_info);
262
116
            }));
263
264
1
    if (config::enable_cloud_tablet_report) {
265
1
        _report_workers.push_back(std::make_unique<ReportWorker>(
266
1
                "REPORT_OLAP_TABLET", _cluster_info, config::report_tablet_interval_seconds,
267
61
                [&engine, &cluster_info = _cluster_info] {
268
61
                    report_tablet_callback(engine, cluster_info);
269
61
                }));
270
1
    }
271
272
1
    _report_workers.push_back(std::make_unique<ReportWorker>(
273
1
            "REPORT_INDEX_POLICY", _cluster_info, config::report_index_policy_interval_seconds,
274
380
            [&cluster_info = _cluster_info] { report_index_policy_callback(cluster_info); }));
275
1
}
276
277
// TODO(lingbin): each task in the batch may have it own status or FE must check and
278
// resend request when something is wrong(BE may need some logic to guarantee idempotence.
279
void AgentServer::submit_tasks(TAgentResult& agent_result,
280
54.0k
                               const std::vector<TAgentTaskRequest>& tasks) {
281
54.0k
    Status ret_st;
282
283
    // TODO check cluster_info here if it is the same with that of heartbeat rpc
284
54.0k
    if (_cluster_info->master_fe_addr.hostname.empty() || _cluster_info->master_fe_addr.port == 0) {
285
0
        Status st = Status::Cancelled("Have not get FE Master heartbeat yet");
286
0
        st.to_thrift(&agent_result.status);
287
0
        return;
288
0
    }
289
290
81.5k
    for (auto&& task : tasks) {
291
81.5k
        VLOG_RPC << "submit one task: " << apache::thrift::ThriftDebugString(task).c_str();
292
81.5k
        auto task_type = task.task_type;
293
81.5k
        if (task_type == TTaskType::REALTIME_PUSH) {
294
3.24k
            task_type = TTaskType::PUSH;
295
3.24k
        }
296
81.5k
        int64_t signature = task.signature;
297
81.5k
        if (auto it = _workers.find(task_type); it != _workers.end()) {
298
80.1k
            auto& worker = it->second;
299
80.1k
            ret_st = worker->submit_task(task);
300
80.1k
        } else {
301
1.39k
            ret_st = Status::InvalidArgument("task(signature={}, type={}) has wrong task type",
302
1.39k
                                             signature, task.task_type);
303
1.39k
        }
304
305
81.5k
        if (!ret_st.ok()) {
306
1.40k
            LOG_WARNING("failed to submit task").tag("task", task).error(ret_st);
307
            // For now, all tasks in the batch share one status, so if any task
308
            // was failed to submit, we can only return error to FE(even when some
309
            // tasks have already been successfully submitted).
310
            // However, Fe does not check the return status of submit_tasks() currently,
311
            // and it is not sure that FE will retry when something is wrong, so here we
312
            // only print an warning log and go on(i.e. do not break current loop),
313
            // to ensure every task can be submitted once. It is OK for now, because the
314
            // ret_st can be error only when it encounters an wrong task_type and
315
            // req-member in TAgentTaskRequest, which is basically impossible.
316
            // TODO(lingbin): check the logic in FE again later.
317
1.40k
        }
318
81.5k
    }
319
320
54.0k
    ret_st.to_thrift(&agent_result.status);
321
54.0k
}
322
323
void AgentServer::publish_cluster_state(TAgentResult& t_agent_result,
324
0
                                        const TAgentPublishRequest& request) {
325
0
    Status status = Status::NotSupported("deprecated method(publish_cluster_state) was invoked");
326
0
    status.to_thrift(&t_agent_result.status);
327
0
}
328
329
0
void AgentServer::stop_report_workers() {
330
0
    for (auto& work : _report_workers) {
331
0
        work->stop();
332
0
    }
333
0
}
334
335
} // namespace doris