be/src/storage/tablet/tablet_manager.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 <butil/macros.h> |
21 | | #include <gen_cpp/BackendService_types.h> |
22 | | #include <gen_cpp/Types_types.h> |
23 | | #include <stddef.h> |
24 | | #include <stdint.h> |
25 | | |
26 | | #include <functional> |
27 | | #include <list> |
28 | | #include <map> |
29 | | #include <memory> |
30 | | #include <mutex> |
31 | | #include <set> |
32 | | #include <shared_mutex> |
33 | | #include <string> |
34 | | #include <string_view> |
35 | | #include <unordered_map> |
36 | | #include <unordered_set> |
37 | | #include <utility> |
38 | | #include <vector> |
39 | | |
40 | | #include "common/status.h" |
41 | | #include "storage/olap_common.h" |
42 | | #include "storage/tablet/tablet.h" |
43 | | #include "storage/tablet/tablet_meta.h" |
44 | | |
45 | | namespace doris { |
46 | | |
47 | | class DataDir; |
48 | | class CumulativeCompactionPolicy; |
49 | | class MemTracker; |
50 | | class TCreateTabletReq; |
51 | | class TTablet; |
52 | | class TTabletInfo; |
53 | | |
54 | | // TabletManager provides get, add, delete tablet method for storage engine |
55 | | // NOTE: If you want to add a method that needs to hold meta-lock before you can call it, |
56 | | // please uniformly name the method in "xxx_unlocked()" mode |
57 | | class TabletManager { |
58 | | public: |
59 | | TabletManager(StorageEngine& engine, int32_t tablet_map_lock_shard_size); |
60 | | ~TabletManager(); |
61 | | |
62 | | #ifdef BE_TEST |
63 | | friend class TabletMgrTest; |
64 | | #endif |
65 | | |
66 | | bool check_tablet_id_exist(TTabletId tablet_id); |
67 | | |
68 | | // The param stores holds all candidate data_dirs for this tablet. |
69 | | // NOTE: If the request is from a schema-changing tablet, The directory selected by the |
70 | | // new tablet should be the same as the directory of origin tablet. Because the |
71 | | // linked-schema-change type requires Linux hard-link, which does not support cross disk. |
72 | | // TODO(lingbin): Other schema-change type do not need to be on the same disk. Because |
73 | | // there may be insufficient space on the current disk, which will lead the schema-change |
74 | | // task to be fail, even if there is enough space on other disks |
75 | | Status create_tablet(const TCreateTabletReq& request, std::vector<DataDir*> stores, |
76 | | RuntimeProfile* profile); |
77 | | |
78 | | // Drop a tablet by description. |
79 | | // If `is_drop_table_or_partition` is true, we need to remove all remote rowsets in this tablet. |
80 | | Status drop_tablet(TTabletId tablet_id, TReplicaId replica_id, bool is_drop_table_or_partition); |
81 | | |
82 | | // Find two tablets. |
83 | | // One with the highest score to execute single compaction, |
84 | | // the other with the highest score to execute cumu or base compaction. |
85 | | // Single compaction needs to be completed successfully after the peer completes it. |
86 | | // We need to generate two types of tasks separately to avoid continuously generating |
87 | | // single compaction tasks for the tablet. |
88 | | std::vector<TabletCompactionContext> find_best_tablets_to_compaction( |
89 | | CompactionType compaction_type, DataDir* data_dir, |
90 | | const std::unordered_set<TabletSharedPtr>& tablet_submitted_compaction, uint32_t* score, |
91 | | const std::unordered_map<std::string_view, std::shared_ptr<CumulativeCompactionPolicy>>& |
92 | | all_cumulative_compaction_policies); |
93 | | |
94 | | TabletSharedPtr get_tablet(TTabletId tablet_id, bool include_deleted = false, |
95 | | std::string* err = nullptr); |
96 | | |
97 | | TabletSharedPtr get_tablet(TTabletId tablet_id, TabletUid tablet_uid, |
98 | | bool include_deleted = false, std::string* err = nullptr); |
99 | | |
100 | | std::vector<TabletSharedPtr> get_all_tablet( |
101 | | std::function<bool(Tablet*)>&& filter = filter_used_tablets); |
102 | | |
103 | | // Handler not hold the shard lock. |
104 | | void for_each_tablet(std::function<void(const TabletSharedPtr&)>&& handler, |
105 | | std::function<bool(Tablet*)>&& filter = filter_used_tablets); |
106 | | |
107 | 115 | static bool filter_all_tablets(Tablet* tablet) { return true; } |
108 | 0 | static bool filter_used_tablets(Tablet* tablet) { return tablet->is_used(); } |
109 | | |
110 | | uint64_t get_rowset_nums(); |
111 | | uint64_t get_segment_nums(); |
112 | | |
113 | | // Extract tablet_id and schema_hash from given path. |
114 | | // |
115 | | // The normal path pattern is like "/data/{shard_id}/{tablet_id}/{schema_hash}/xxx.data". |
116 | | // Besides that, this also support empty tablet path, which path looks like |
117 | | // "/data/{shard_id}/{tablet_id}" |
118 | | // |
119 | | // Return true when the path matches the path pattern, and tablet_id and schema_hash is |
120 | | // saved in input params. When input path is an empty tablet directory, schema_hash will |
121 | | // be set to 0. Return false if the path don't match valid pattern. |
122 | | static bool get_tablet_id_and_schema_hash_from_path(const std::string& path, |
123 | | TTabletId* tablet_id, |
124 | | TSchemaHash* schema_hash); |
125 | | |
126 | | static bool get_rowset_id_from_path(const std::string& path, RowsetId* rowset_id); |
127 | | |
128 | | void get_tablet_stat(TTabletStatResult* result); |
129 | | |
130 | | // parse tablet header msg to generate tablet object |
131 | | // - restore: whether the request is from restore tablet action, |
132 | | // where we should change tablet status from shutdown back to running |
133 | | Status load_tablet_from_meta(DataDir* data_dir, TTabletId tablet_id, TSchemaHash schema_hash, |
134 | | std::string_view header, bool update_meta, bool force = false, |
135 | | bool restore = false, bool check_path = true); |
136 | | |
137 | | Status load_tablet_from_dir(DataDir* data_dir, TTabletId tablet_id, SchemaHash schema_hash, |
138 | | const std::string& schema_hash_path, bool force = false, |
139 | | bool restore = false); |
140 | | |
141 | | // 获取所有tables的名字 |
142 | | // |
143 | | // Return OK, if run ok |
144 | | // Status::Error<INVALID_ARGUMENT>(), if tables is null |
145 | | Status report_tablet_info(TTabletInfo* tablet_info); |
146 | | |
147 | | void build_all_report_tablets_info(std::map<TTabletId, TTablet>* tablets_info); |
148 | | |
149 | | Status start_trash_sweep(); |
150 | | |
151 | | void try_delete_unused_tablet_path(DataDir* data_dir, TTabletId tablet_id, |
152 | | SchemaHash schema_hash, const std::string& schema_hash_path, |
153 | | int16_t shard_id); |
154 | | |
155 | | void update_root_path_info(std::map<std::string, DataDirInfo>* path_map, |
156 | | size_t* tablet_counter); |
157 | | |
158 | | void get_partition_related_tablets(int64_t partition_id, std::set<TabletInfo>* tablet_infos); |
159 | | |
160 | | void get_partitions_visible_version(std::map<int64_t, int64_t>* partitions_version); |
161 | | |
162 | | void update_partitions_visible_version(const std::map<int64_t, int64_t>& partitions_version); |
163 | | |
164 | | void do_tablet_meta_checkpoint(DataDir* data_dir); |
165 | | |
166 | | void obtain_specific_quantity_tablets(std::vector<TabletInfo>& tablets_info, int64_t num); |
167 | | |
168 | | // return `true` if register success |
169 | | Status register_transition_tablet(int64_t tablet_id, std::string reason); |
170 | | void unregister_transition_tablet(int64_t tablet_id, std::string reason); |
171 | | |
172 | | void get_tablets_distribution_on_different_disks( |
173 | | std::map<int64_t, std::map<DataDir*, int64_t>>& tablets_num_on_disk, |
174 | | std::map<int64_t, std::map<DataDir*, std::vector<TabletSize>>>& tablets_info_on_disk); |
175 | | void get_cooldown_tablets(std::vector<TabletSharedPtr>* tables, |
176 | | std::vector<RowsetSharedPtr>* rowsets, |
177 | | std::function<bool(const TabletSharedPtr&)> skip_tablet); |
178 | | |
179 | | void get_all_tablets_storage_format(TCheckStorageFormatResult* result); |
180 | | |
181 | | std::set<int64_t> check_all_tablet_segment(bool repair); |
182 | | |
183 | | bool update_tablet_partition_id(::doris::TPartitionId partition_id, |
184 | | ::doris::TTabletId tablet_id); |
185 | | |
186 | | void get_topn_tablet_delete_bitmap_score(uint64_t* max_delete_bitmap_score, |
187 | | uint64_t* max_base_rowset_delete_bitmap_score); |
188 | | |
189 | | private: |
190 | | using ShutdownTabletIter = std::list<TabletSharedPtr>::iterator; |
191 | | |
192 | | struct FetchResult { |
193 | | std::vector<TabletSharedPtr> tablets; |
194 | | int scanned_count = 0; |
195 | | bool reached_end = false; |
196 | | }; |
197 | | |
198 | | struct RoundResult { |
199 | | int resolved_count = 0; |
200 | | int failed_count = 0; |
201 | | int64_t elapsed_ms = 0; |
202 | | bool need_continue = false; |
203 | | }; |
204 | | |
205 | | // Add a tablet pointer to StorageEngine |
206 | | // If force, drop the existing tablet add this new one |
207 | | // |
208 | | // Return OK, if run ok |
209 | | // OLAP_ERR_TABLE_INSERT_DUPLICATION_ERROR, if find duplication |
210 | | // Status::Error<UNINITIALIZED>(), if not inited |
211 | | Status _add_tablet_unlocked(TTabletId tablet_id, const TabletSharedPtr& tablet, |
212 | | bool update_meta, bool force, RuntimeProfile* profile); |
213 | | |
214 | | Status _add_tablet_to_map_unlocked(TTabletId tablet_id, const TabletSharedPtr& tablet, |
215 | | bool update_meta, bool keep_files, bool drop_old, |
216 | | RuntimeProfile* profile); |
217 | | |
218 | | bool _check_tablet_id_exist_unlocked(TTabletId tablet_id); |
219 | | |
220 | | Status _drop_tablet(TTabletId tablet_id, TReplicaId replica_id, bool keep_files, |
221 | | bool is_drop_table_or_partition, bool had_held_shard_lock); |
222 | | |
223 | | TabletSharedPtr _get_tablet_unlocked(TTabletId tablet_id); |
224 | | TabletSharedPtr _get_tablet_unlocked(TTabletId tablet_id, bool include_deleted, |
225 | | std::string* err); |
226 | | |
227 | | TabletSharedPtr _internal_create_tablet_unlocked(const TCreateTabletReq& request, |
228 | | const bool is_schema_change, |
229 | | const Tablet* base_tablet, |
230 | | const std::vector<DataDir*>& data_dirs, |
231 | | RuntimeProfile* profile); |
232 | | TabletSharedPtr _create_tablet_meta_and_dir_unlocked(const TCreateTabletReq& request, |
233 | | const bool is_schema_change, |
234 | | const Tablet* base_tablet, |
235 | | const std::vector<DataDir*>& data_dirs, |
236 | | RuntimeProfile* profile); |
237 | | Status _create_tablet_meta_unlocked(const TCreateTabletReq& request, DataDir* store, |
238 | | const bool is_schema_change_tablet, |
239 | | const Tablet* base_tablet, |
240 | | TabletMetaSharedPtr* tablet_meta); |
241 | | |
242 | | void _add_tablet_to_partition(const TabletSharedPtr& tablet); |
243 | | |
244 | | void _remove_tablet_from_partition(const TabletSharedPtr& tablet); |
245 | | |
246 | | std::shared_mutex& _get_tablets_shard_lock(TTabletId tabletId); |
247 | | |
248 | | // Fetch a bounded batch of shutdown tablets while limiting lock hold time. |
249 | | FetchResult _fetch_shutdown_tablets(ShutdownTabletIter& last_it, int max_to_fetch, |
250 | | int scan_chunk); |
251 | | |
252 | | // Delete one round of shutdown tablets under the configured success budget. |
253 | | RoundResult _delete_shutdown_tablets_one_round( |
254 | | ShutdownTabletIter& last_it, std::list<TabletSharedPtr>& failed_tablets, |
255 | | const std::function<bool(const TabletSharedPtr&)>& move_tablet, int round_budget, |
256 | | int fetch_chunk, int scan_chunk); |
257 | | |
258 | | // Sweep shutdown tablets with round-based throttling and retry preservation. |
259 | | Status _sweep_shutdown_tablets(const std::function<bool(const TabletSharedPtr&)>& move_tablet, |
260 | | const std::function<void(int)>& wait_next_round); |
261 | | |
262 | | // Add a tablet to the shutdown cleanup backlog. |
263 | | void _enqueue_shutdown_tablet(const TabletSharedPtr& tablet); |
264 | | |
265 | | // Adjust the shutdown backlog metric by delta for queue lifecycle changes. |
266 | | void _adjust_shutdown_tablet_backlog(int64_t delta); |
267 | | |
268 | | #ifdef BE_TEST |
269 | | // Read shutdown sweep metric values for test isolation. |
270 | | int64_t _shutdown_tablet_backlog_value() const; |
271 | | int64_t _shutdown_tablet_last_sweep_ms_value() const; |
272 | | #endif |
273 | | |
274 | | bool _move_tablet_to_trash(const TabletSharedPtr& tablet); |
275 | | |
276 | | private: |
277 | | DISALLOW_COPY_AND_ASSIGN(TabletManager); |
278 | | |
279 | | using tablet_map_t = std::unordered_map<int64_t, TabletSharedPtr>; |
280 | | |
281 | | struct tablets_shard { |
282 | 16.0k | tablets_shard() = default; |
283 | 0 | tablets_shard(tablets_shard&& shard) { |
284 | 0 | tablet_map = std::move(shard.tablet_map); |
285 | 0 | tablets_under_transition = std::move(shard.tablets_under_transition); |
286 | 0 | } |
287 | | mutable std::shared_mutex lock; |
288 | | tablet_map_t tablet_map; |
289 | | std::mutex lock_for_transition; |
290 | | // tablet do clone, path gc, move to trash, disk migrate will record in tablets_under_transition |
291 | | // tablet <reason, thread_id, lock_times> |
292 | | std::map<int64_t, std::tuple<std::string, std::thread::id, int64_t>> |
293 | | tablets_under_transition; |
294 | | }; |
295 | | |
296 | | struct Partition { |
297 | | std::set<TabletInfo> tablets; |
298 | | std::shared_ptr<VersionWithTime> visible_version {new VersionWithTime}; |
299 | | }; |
300 | | |
301 | | StorageEngine& _engine; |
302 | | |
303 | | const int32_t _tablets_shards_size; |
304 | | const int32_t _tablets_shards_mask; |
305 | | std::vector<tablets_shard> _tablets_shards; |
306 | | |
307 | | // Protect _partitions, should not be obtained before _tablet_map_lock to avoid dead lock |
308 | | std::shared_mutex _partitions_lock; |
309 | | // partition_id => partition |
310 | | std::map<int64_t, Partition> _partitions; |
311 | | |
312 | | // Protect _shutdown_tablets, should not be obtained before _tablet_map_lock to avoid dead lock |
313 | | std::shared_mutex _shutdown_tablets_lock; |
314 | | // the delete tablets. notice only allow function `start_trash_sweep` can erase tablets in _shutdown_tablets |
315 | | std::list<TabletSharedPtr> _shutdown_tablets; |
316 | | std::mutex _gc_tablets_lock; |
317 | | |
318 | | std::mutex _tablet_stat_cache_mutex; |
319 | | std::shared_ptr<std::vector<TTabletStat>> _tablet_stat_list_cache = |
320 | | std::make_shared<std::vector<TTabletStat>>(); |
321 | | |
322 | | tablet_map_t& _get_tablet_map(TTabletId tablet_id); |
323 | | |
324 | | tablets_shard& _get_tablets_shard(TTabletId tabletId); |
325 | | |
326 | | std::mutex _two_tablet_mtx; |
327 | | }; |
328 | | |
329 | | } // namespace doris |