Coverage Report

Created: 2026-09-23 11:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/runtime/fragment_mgr.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <brpc/closure_guard.h>
21
#include <gen_cpp/FrontendService_types.h>
22
#include <gen_cpp/QueryPlanExtra_types.h>
23
#include <gen_cpp/Types_types.h>
24
#include <gen_cpp/types.pb.h>
25
26
#include <cstdint>
27
#include <functional>
28
#include <iosfwd>
29
#include <map>
30
#include <memory>
31
#include <mutex>
32
#include <set>
33
#include <string>
34
#include <unordered_map>
35
#include <vector>
36
37
#include "common/be_mock_util.h"
38
#include "common/metrics/metrics.h"
39
#include "common/status.h"
40
#include "exec/runtime_filter/runtime_filter_mgr.h"
41
#include "runtime/query_context.h"
42
#include "service/http/rest_monitor_iface.h"
43
#include "util/countdown_latch.h"
44
#include "util/hash_util.hpp" // IWYU pragma: keep
45
46
namespace butil {
47
class IOBufAsZeroCopyInputStream;
48
}
49
50
namespace doris {
51
class PipelineFragmentContext;
52
class QueryContext;
53
class DescriptorTbl;
54
class ExecEnv;
55
struct FrontendInfo;
56
class ThreadPool;
57
class PExecPlanFragmentStartRequest;
58
class PMergeFilterRequest;
59
class RuntimeProfile;
60
class RuntimeState;
61
class TPipelineFragmentParams;
62
class TPipelineInstanceParams;
63
class TScanColumnDesc;
64
class TScanOpenParams;
65
class Thread;
66
class WorkloadQueryInfo;
67
68
std::string to_load_error_http_path(const std::string& file_name);
69
70
template <typename Key, typename Value, typename ValueType>
71
class ConcurrentContextMap {
72
public:
73
    using ApplyFunction = std::function<Status(phmap::flat_hash_map<Key, Value>&)>;
74
    ConcurrentContextMap();
75
    Value find(const Key& query_id);
76
    void insert(const Key& query_id, std::shared_ptr<ValueType>);
77
    void clear();
78
    bool erase(const Key& query_id);
79
492
    size_t num_items() const {
80
492
        size_t n = 0;
81
62.9k
        for (auto& pair : _internal_map) {
82
62.9k
            std::shared_lock lock(*pair.first);
83
62.9k
            auto& map = pair.second;
84
62.9k
            n += map.size();
85
62.9k
        }
86
492
        return n;
87
492
    }
_ZNK5doris20ConcurrentContextMapINS_9TUniqueIdESt8weak_ptrINS_12QueryContextEES3_E9num_itemsEv
Line
Count
Source
79
444
    size_t num_items() const {
80
444
        size_t n = 0;
81
56.8k
        for (auto& pair : _internal_map) {
82
56.8k
            std::shared_lock lock(*pair.first);
83
56.8k
            auto& map = pair.second;
84
56.8k
            n += map.size();
85
56.8k
        }
86
444
        return n;
87
444
    }
_ZNK5doris20ConcurrentContextMapISt4pairINS_9TUniqueIdEiESt10shared_ptrINS_23PipelineFragmentContextEES5_E9num_itemsEv
Line
Count
Source
79
48
    size_t num_items() const {
80
48
        size_t n = 0;
81
6.14k
        for (auto& pair : _internal_map) {
82
6.14k
            std::shared_lock lock(*pair.first);
83
6.14k
            auto& map = pair.second;
84
6.14k
            n += map.size();
85
6.14k
        }
86
48
        return n;
87
48
    }
88
23.2k
    void apply(ApplyFunction&& function) {
89
2.97M
        for (auto& pair : _internal_map) {
90
            // TODO: Now only the cancel worker do the GC the _query_ctx_map. each query must
91
            // do erase the finish query unless in _query_ctx_map. Rethink the logic is ok
92
2.97M
            std::unique_lock lock(*pair.first);
93
2.97M
            static_cast<void>(function(pair.second));
94
2.97M
        }
95
23.2k
    }
_ZN5doris20ConcurrentContextMapISt4pairINS_9TUniqueIdEiESt10shared_ptrINS_23PipelineFragmentContextEES5_E5applyEOSt8functionIFNS_6StatusERN5phmap13flat_hash_mapIS3_S6_NSA_4HashIS3_EENSA_7EqualToIS3_EESaIS1_IKS3_S6_EEEEEE
Line
Count
Source
88
4.69k
    void apply(ApplyFunction&& function) {
89
601k
        for (auto& pair : _internal_map) {
90
            // TODO: Now only the cancel worker do the GC the _query_ctx_map. each query must
91
            // do erase the finish query unless in _query_ctx_map. Rethink the logic is ok
92
601k
            std::unique_lock lock(*pair.first);
93
601k
            static_cast<void>(function(pair.second));
94
601k
        }
95
4.69k
    }
_ZN5doris20ConcurrentContextMapINS_9TUniqueIdESt8weak_ptrINS_12QueryContextEES3_E5applyEOSt8functionIFNS_6StatusERN5phmap13flat_hash_mapIS1_S4_NS8_4HashIS1_EENS8_7EqualToIS1_EESaISt4pairIKS1_S4_EEEEEE
Line
Count
Source
88
18.5k
    void apply(ApplyFunction&& function) {
89
2.37M
        for (auto& pair : _internal_map) {
90
            // TODO: Now only the cancel worker do the GC the _query_ctx_map. each query must
91
            // do erase the finish query unless in _query_ctx_map. Rethink the logic is ok
92
2.37M
            std::unique_lock lock(*pair.first);
93
2.37M
            static_cast<void>(function(pair.second));
94
2.37M
        }
95
18.5k
    }
96
97
    Status apply_if_not_exists(const Key& query_id, std::shared_ptr<ValueType>& query_ctx,
98
                               ApplyFunction&& function);
99
100
private:
101
    // The lock should only be used to protect the structures in fragment manager. Has to be
102
    // used in a very small scope because it may dead lock. For example, if the _lock is used
103
    // in prepare stage, the call path is  prepare --> expr prepare --> may call allocator
104
    // when allocate failed, allocator may call query_is_cancelled, query is callced will also
105
    // call _lock, so that there is dead lock.
106
    std::vector<std::pair<std::unique_ptr<std::shared_mutex>, phmap::flat_hash_map<Key, Value>>>
107
            _internal_map;
108
};
109
110
// This class used to manage all the fragment execute in this instance
111
class FragmentMgr : public RestMonitorIface {
112
public:
113
    using FinishCallback = std::function<void(RuntimeState*, Status*)>;
114
115
    FragmentMgr(ExecEnv* exec_env);
116
    ~FragmentMgr() override;
117
118
    void stop();
119
120
    // execute one plan fragment
121
122
    Status exec_plan_fragment(const TPipelineFragmentParams& params, const QuerySource query_type,
123
                              const TPipelineFragmentParamsList& parent);
124
125
    void remove_pipeline_context(std::pair<TUniqueId, int> key);
126
    void remove_query_context(const TUniqueId& key);
127
128
    // `is_prepare_success` is used by invoker to ensure callback can be handle correctly (eg. stream_load_executor)
129
    Status exec_plan_fragment(const TPipelineFragmentParams& params, const QuerySource query_type,
130
                              const FinishCallback& cb, const TPipelineFragmentParamsList& parent,
131
                              std::shared_ptr<bool> is_prepare_success = nullptr);
132
133
    Status start_query_execution(const PExecPlanFragmentStartRequest* request);
134
135
    // Can be used in both version.
136
    MOCK_FUNCTION void cancel_query(const TUniqueId query_id, const Status reason);
137
138
    void cancel_worker();
139
140
    void debug(std::stringstream& ss) override;
141
142
    // input: TQueryPlanInfo fragment_instance_id
143
    // output: selected_columns
144
    // execute external query, all query info are packed in TScanOpenParams
145
    Status exec_external_plan_fragment(const TScanOpenParams& params,
146
                                       const TQueryPlanInfo& t_query_plan_info,
147
                                       const TUniqueId& query_id,
148
                                       const TUniqueId& fragment_instance_id,
149
                                       std::vector<TScanColumnDesc>* selected_columns);
150
151
    Status apply_filterv2(const PPublishFilterRequestV2* request,
152
                          butil::IOBufAsZeroCopyInputStream* attach_data);
153
154
    Status merge_filter(const PMergeFilterRequest* request,
155
                        butil::IOBufAsZeroCopyInputStream* attach_data);
156
157
    Status send_filter_size(const PSendFilterSizeRequest* request);
158
159
    Status sync_filter_size(const PSyncFilterSizeRequest* request);
160
161
97.8k
    ThreadPool* get_thread_pool() { return _thread_pool.get(); }
162
163
    // When fragment mgr is going to stop, the _stop_background_threads_latch is set to 0
164
    // and other module that use fragment mgr's thread pool should get this signal and exit.
165
113k
    bool shutting_down() { return _stop_background_threads_latch.count() == 0; }
166
167
356
    int32_t running_query_num() { return cast_set<int32_t>(_query_ctx_map.num_items()); }
168
169
    std::string dump_pipeline_tasks(int64_t duration = 0);
170
    std::string dump_pipeline_tasks(TUniqueId& query_id);
171
172
    void get_runtime_query_info(std::vector<std::weak_ptr<ResourceContext>>* _resource_ctx_list);
173
174
    Status get_realtime_exec_status(const TUniqueId& query_id,
175
                                    TReportExecStatusParams* exec_status);
176
    // get the query statistics of with a given query id
177
    Status get_query_statistics(const TUniqueId& query_id, TQueryStatistics* query_stats);
178
179
    std::shared_ptr<QueryContext> get_query_ctx(const TUniqueId& query_id);
180
181
    Status transmit_rec_cte_block(const TUniqueId& query_id, const TUniqueId& instance_id,
182
                                  int node_id,
183
                                  const google::protobuf::RepeatedPtrField<PBlock>& pblocks,
184
                                  bool eos);
185
186
    Status rerun_fragment(const std::shared_ptr<brpc::ClosureGuard>& guard,
187
                          const TUniqueId& query_id, int fragment,
188
                          PRerunFragmentParams_Opcode stage);
189
190
    Status reset_global_rf(const TUniqueId& query_id,
191
                           const google::protobuf::RepeatedField<int32_t>& filter_ids);
192
193
private:
194
    struct BrpcItem {
195
        TNetworkAddress network_address;
196
        std::vector<std::weak_ptr<QueryContext>> queries;
197
    };
198
199
    Status _get_or_create_query_ctx(const TPipelineFragmentParams& params,
200
                                    const TPipelineFragmentParamsList& parent,
201
                                    QuerySource query_type,
202
                                    std::shared_ptr<QueryContext>& query_ctx);
203
204
    void _collect_timeout_queries_and_brpc_items(
205
            std::vector<TUniqueId>& queries_timeout,
206
            std::unordered_map<std::shared_ptr<PBackendService_Stub>, BrpcItem>&
207
                    brpc_stub_with_queries,
208
            timespec now);
209
210
    void _collect_invalid_queries(
211
            std::vector<TUniqueId>& queries_lost_coordinator,
212
            std::vector<TUniqueId>& queries_pipeline_task_leak,
213
            const std::map<int64_t, std::unordered_set<TUniqueId>>& running_queries_on_all_fes,
214
            const std::map<TNetworkAddress, FrontendInfo>& running_fes,
215
            timespec check_invalid_query_last_timestamp);
216
217
    void _check_brpc_available(const std::shared_ptr<PBackendService_Stub>& brpc_stub,
218
                               const BrpcItem& brpc_item);
219
220
    static Status _build_external_scan_selected_columns(
221
            const TPlanFragment& plan_fragment, const DescriptorTbl& desc_tbl,
222
            std::vector<TScanColumnDesc>* selected_columns);
223
224
    // This is input params
225
    ExecEnv* _exec_env = nullptr;
226
227
    // (QueryID, FragmentID) -> PipelineFragmentContext
228
    ConcurrentContextMap<std::pair<TUniqueId, int>, std::shared_ptr<PipelineFragmentContext>,
229
                         PipelineFragmentContext>
230
            _pipeline_map;
231
232
    // Saved params and callback for rerunnable (recursive CTE) fragments.
233
    // Only populated when need_notify_close == true during exec_plan_fragment.
234
    // Lifecycle: created in exec_plan_fragment(), retained across wait/rebuild/submit rounds,
235
    // and removed after a successful final_close. remove_query_context() and stop() provide
236
    // fallback cleanup. Entries are detached under _rerunnable_params_lock and destroyed afterward;
237
    // releasing their last QueryContext reference can call FragmentMgr::remove_query_context().
238
    struct RerunableFragmentInfo {
239
        // Runtime filter IDs registered by the old PFC, collected during wait_for_destroy.
240
        // These are deregistered from the RuntimeFilterMgr before the new PFC is created.
241
        std::set<int> deregister_runtime_filter_ids;
242
        // Original params from FE, used to recreate the PFC each round.
243
        TPipelineFragmentParams params;
244
        TPipelineFragmentParamsList parent;
245
        FinishCallback finish_callback;
246
        // Hold query_ctx to prevent it from being destroyed while rerunnable fragments exist.
247
        std::shared_ptr<QueryContext> query_ctx;
248
        // Monotonically increasing stage counter, stamps runtime filter RPCs.
249
        uint32_t stage = 0;
250
    };
251
    std::mutex _rerunnable_params_lock;
252
    std::map<std::pair<TUniqueId, int>, RerunableFragmentInfo> _rerunnable_params_map;
253
254
    // query id -> QueryContext
255
    ConcurrentContextMap<TUniqueId, std::weak_ptr<QueryContext>, QueryContext> _query_ctx_map;
256
    // keep query ctx do not delete immediately to make rf coordinator merge filter work well after query eos
257
    ConcurrentContextMap<TUniqueId, std::shared_ptr<QueryContext>, QueryContext>
258
            _query_ctx_map_delay_delete;
259
260
    CountDownLatch _stop_background_threads_latch;
261
    std::shared_ptr<Thread> _cancel_thread;
262
    // This pool is used as global async task pool
263
    std::unique_ptr<ThreadPool> _thread_pool;
264
265
    std::shared_ptr<MetricEntity> _entity;
266
    UIntGauge* timeout_canceled_fragment_count = nullptr;
267
};
268
269
uint64_t get_fragment_executing_count();
270
uint64_t get_fragment_last_active_time();
271
void increment_fragment_executing_count();
272
void decrement_fragment_executing_count();
273
} // namespace doris