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 |