Coverage Report

Created: 2026-08-06 08:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/runtime/exec_env.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 "runtime/exec_env.h"
19
20
#include <gen_cpp/HeartbeatService_types.h>
21
#include <glog/logging.h>
22
23
#include <mutex>
24
#include <set>
25
#include <utility>
26
27
#include "common/config.h"
28
#include "common/logging.h"
29
#include "exec/exchange/vdata_stream_mgr.h"
30
#include "exec/sink/delta_writer_v2_pool.h"
31
#include "exec/sink/load_stream_map_pool.h"
32
#include "io/cache/fs_file_cache_storage.h"
33
#include "load/channel/load_stream_mgr.h"
34
#include "load/memtable/memtable_memory_limiter.h"
35
#include "runtime/cluster_info.h"
36
#include "runtime/fragment_mgr.h"
37
#include "runtime/frontend_info.h"
38
#include "storage/index/index_writer.h" // TmpFileDirs, completed here rather than in the header
39
#include "storage/olap_define.h"
40
#include "storage/storage_engine.h"
41
#include "storage/tablet/tablet_manager.h"
42
#include "util/debug_util.h"
43
#include "util/threadpool.h" // ThreadPool must be complete: unique_ptr member assignment
44
#include "util/time.h"
45
46
namespace doris {
47
48
#ifdef BE_TEST
49
void ExecEnv::set_inverted_index_searcher_cache(
50
        segment_v2::InvertedIndexSearcherCache* inverted_index_searcher_cache) {
51
    _inverted_index_searcher_cache = inverted_index_searcher_cache;
52
}
53
void ExecEnv::set_tmp_file_dir(std::unique_ptr<segment_v2::TmpFileDirs> tmp_file_dirs) {
54
    _tmp_file_dirs = std::move(tmp_file_dirs);
55
}
56
void ExecEnv::set_storage_engine(std::unique_ptr<BaseStorageEngine>&& engine) {
57
    _storage_engine = std::move(engine);
58
}
59
void ExecEnv::set_write_cooldown_meta_executors() {
60
    _write_cooldown_meta_executors = std::make_unique<WriteCooldownMetaExecutors>();
61
}
62
void ExecEnv::set_memtable_memory_limiter(MemTableMemoryLimiter* limiter) {
63
    _memtable_memory_limiter.reset(limiter);
64
}
65
void ExecEnv::set_file_cache_open_fd_cache(std::unique_ptr<io::FDCache>&& fd_cache) {
66
    _file_cache_open_fd_cache = std::move(fd_cache);
67
}
68
void ExecEnv::set_non_block_close_thread_pool(std::unique_ptr<ThreadPool>&& pool) {
69
    _non_block_close_thread_pool = std::move(pool);
70
}
71
void ExecEnv::set_s3_file_upload_thread_pool(std::unique_ptr<ThreadPool>&& pool) {
72
    _s3_file_upload_thread_pool = std::move(pool);
73
}
74
#endif // BE_TEST
75
76
Result<BaseTabletSPtr> ExecEnv::get_tablet(int64_t tablet_id, SyncRowsetStats* sync_stats,
77
1.08M
                                           bool force_use_only_cached, bool cache_on_miss) {
78
1.08M
    auto storage_engine = GetInstance()->_storage_engine.get();
79
1.08M
    return storage_engine != nullptr
80
1.08M
                   ? storage_engine->get_tablet(tablet_id, sync_stats, force_use_only_cached,
81
1.08M
                                                cache_on_miss)
82
1.08M
                   : ResultError(Status::InternalError("failed to get tablet {}", tablet_id));
83
1.08M
}
84
85
Status ExecEnv::get_tablet_meta(int64_t tablet_id, TabletMetaSharedPtr* tablet_meta,
86
164k
                                bool force_use_only_cached) {
87
164k
    auto storage_engine = GetInstance()->_storage_engine.get();
88
164k
    if (storage_engine == nullptr) {
89
0
        return Status::InternalError("storage engine is not initialized");
90
0
    }
91
164k
    return storage_engine->get_tablet_meta(tablet_id, tablet_meta, force_use_only_cached);
92
164k
}
93
94
31
const std::string& ExecEnv::token() const {
95
31
    return _cluster_info->token;
96
31
}
97
98
0
void ExecEnv::clear_stream_mgr() {
99
0
    if (_vstream_mgr) {
100
0
        SAFE_DELETE(_vstream_mgr);
101
0
    }
102
0
}
103
104
0
std::vector<TFrontendInfo> ExecEnv::get_frontends() {
105
0
    std::lock_guard<std::mutex> lg(_frontends_lock);
106
0
    std::vector<TFrontendInfo> infos;
107
0
    for (const auto& cur_fe : *_frontends) {
108
0
        infos.push_back(cur_fe.second.info);
109
0
    }
110
0
    return infos;
111
0
}
112
113
440
void ExecEnv::update_frontends(const std::vector<TFrontendInfo>& new_fe_infos) {
114
440
    std::lock_guard<std::mutex> lg(_frontends_lock);
115
116
440
    std::set<TNetworkAddress> dropped_fes;
117
118
440
    for (const auto& cur_fe : *_frontends) {
119
430
        dropped_fes.insert(cur_fe.first);
120
430
    }
121
122
440
    for (const auto& coming_fe_info : new_fe_infos) {
123
436
        auto itr = _frontends->find(coming_fe_info.coordinator_address);
124
125
436
        if (itr == _frontends->end()) {
126
6
            LOG(INFO) << "A completely new frontend, " << PrintFrontendInfo(coming_fe_info);
127
128
6
            _frontends->insert(std::pair<TNetworkAddress, FrontendInfo>(
129
6
                    coming_fe_info.coordinator_address,
130
6
                    FrontendInfo {coming_fe_info, GetCurrentTimeMicros() / 1000, /*first time*/
131
6
                                  GetCurrentTimeMicros() / 1000 /*last time*/}));
132
133
6
            continue;
134
6
        }
135
136
430
        dropped_fes.erase(coming_fe_info.coordinator_address);
137
138
430
        if (coming_fe_info.process_uuid == 0) {
139
0
            LOG(WARNING) << "Frontend " << PrintFrontendInfo(coming_fe_info)
140
0
                         << " is in an unknown state.";
141
0
        }
142
143
430
        if (coming_fe_info.process_uuid == itr->second.info.process_uuid) {
144
427
            itr->second.last_reveiving_time_ms = GetCurrentTimeMicros() / 1000;
145
427
            continue;
146
427
        }
147
148
        // If we get here, means this frontend has already restarted.
149
3
        itr->second.info.process_uuid = coming_fe_info.process_uuid;
150
3
        itr->second.first_receiving_time_ms = GetCurrentTimeMicros() / 1000;
151
3
        itr->second.last_reveiving_time_ms = GetCurrentTimeMicros() / 1000;
152
3
        LOG(INFO) << "Update frontend " << PrintFrontendInfo(coming_fe_info);
153
3
    }
154
155
440
    for (const auto& dropped_fe : dropped_fes) {
156
0
        LOG(INFO) << "Frontend " << PrintThriftNetworkAddress(dropped_fe)
157
0
                  << " has already been dropped, remove it";
158
0
        _frontends->erase(dropped_fe);
159
0
    }
160
440
}
161
162
217k
std::map<TNetworkAddress, FrontendInfo> ExecEnv::get_running_frontends() {
163
217k
    std::lock_guard<std::mutex> lg(_frontends_lock);
164
217k
    std::map<TNetworkAddress, FrontendInfo> res;
165
217k
    const int expired_duration = config::fe_expire_duration_seconds * 1000;
166
217k
    const auto now = GetCurrentTimeMicros() / 1000;
167
168
217k
    for (const auto& pair : *_frontends) {
169
217k
        auto& brpc_addr = pair.first;
170
217k
        auto& fe_info = pair.second;
171
172
217k
        if (fe_info.info.process_uuid == 0) {
173
            // FE is in an unknown state, regart it as alive. conservative
174
54
            res[brpc_addr] = fe_info;
175
217k
        } else {
176
217k
            if (now - fe_info.last_reveiving_time_ms < expired_duration) {
177
                // If fe info has just been update in last expired_duration, regard it as running.
178
217k
                res[brpc_addr] = fe_info;
179
217k
            } else {
180
                // Fe info has not been udpate for more than expired_duration, regard it as an abnormal.
181
                // Abnormal means this fe can not connect to master, and it is not dropped from cluster.
182
                // or fe do not have master yet.
183
0
                LOG_EVERY_N(WARNING, 50) << fmt::format(
184
0
                        "Frontend {}:{} has not update its hb for more than {} secs, regard it as "
185
0
                        "abnormal",
186
0
                        brpc_addr.hostname, brpc_addr.port, config::fe_expire_duration_seconds);
187
0
            }
188
217k
        }
189
217k
    }
190
191
217k
    return res;
192
217k
}
193
194
2
void ExecEnv::wait_for_all_tasks_done() {
195
    // For graceful shutdown, need to wait for all running queries to stop
196
2
    int32_t wait_seconds_passed = 0;
197
2
    while (true) {
198
2
        int num_queries = _fragment_mgr->running_query_num();
199
2
        if (num_queries < 1) {
200
2
            break;
201
2
        }
202
0
        if (wait_seconds_passed > doris::config::grace_shutdown_wait_seconds) {
203
0
            LOG(INFO) << "There are still " << num_queries << " queries running, but "
204
0
                      << wait_seconds_passed << " seconds passed, has to exist now";
205
0
            break;
206
0
        }
207
0
        LOG(INFO) << "There are still " << num_queries << " queries running, waiting...";
208
0
        sleep(1);
209
0
        ++wait_seconds_passed;
210
0
    }
211
    // This is a conservative strategy.
212
    // Because a query might still have fragments running on other BE nodes.
213
    // In other words, the query hasn't truly terminated.
214
    // If the current BE is shut down at this point,
215
    // the FE will detect the downtime of a related BE and cancel the entire query,
216
    // defeating the purpose of a graceful stop.
217
2
    sleep(config::grace_shutdown_post_delay_seconds);
218
2
}
219
220
0
bool ExecEnv::check_auth_token(const std::string& auth_token) {
221
0
    return _cluster_info->curr_auth_token == auth_token ||
222
0
           _cluster_info->last_auth_token == auth_token;
223
0
}
224
225
} // namespace doris