be/src/storage/rowset/beta_rowset.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 "storage/rowset/beta_rowset.h" |
19 | | |
20 | | #include <crc32c/crc32c.h> |
21 | | #include <ctype.h> |
22 | | #include <errno.h> |
23 | | #include <fmt/format.h> |
24 | | |
25 | | #include <algorithm> |
26 | | #include <filesystem> |
27 | | #include <memory> |
28 | | #include <ostream> |
29 | | #include <utility> |
30 | | |
31 | | #include "cloud/config.h" |
32 | | #include "common/config.h" |
33 | | #include "common/logging.h" |
34 | | #include "common/metrics/doris_metrics.h" |
35 | | #include "common/status.h" |
36 | | #include "cpp/sync_point.h" |
37 | | #include "io/fs/file_reader.h" |
38 | | #include "io/fs/file_system.h" |
39 | | #include "io/fs/local_file_system.h" |
40 | | #include "io/fs/path.h" |
41 | | #include "io/fs/remote_file_system.h" |
42 | | #include "storage/index/index_file_reader.h" |
43 | | #include "storage/index/inverted/inverted_index_cache.h" |
44 | | #include "storage/index/inverted/inverted_index_desc.h" |
45 | | #include "storage/olap_common.h" |
46 | | #include "storage/olap_define.h" |
47 | | #include "storage/rowset/beta_rowset.h" |
48 | | #include "storage/rowset/beta_rowset_reader.h" |
49 | | #include "storage/rowset/rowset.h" |
50 | | #include "storage/segment/segment_loader.h" |
51 | | #include "storage/tablet/tablet_schema.h" |
52 | | #include "storage/utils.h" |
53 | | #include "util/debug_points.h" |
54 | | |
55 | | namespace doris { |
56 | | using namespace ErrorCode; |
57 | | |
58 | | std::string BetaRowset::local_segment_path_segcompacted(const std::string& tablet_path, |
59 | | const RowsetId& rowset_id, int64_t begin, |
60 | 34 | int64_t end) { |
61 | | // {root_path}/data/{shard_id}/{tablet_id}/{schema_hash}/{rowset_id}_{begin_seg}-{end_seg}.dat |
62 | 34 | return fmt::format("{}/{}_{}-{}.dat", tablet_path, rowset_id.to_string(), begin, end); |
63 | 34 | } |
64 | | |
65 | | BetaRowset::BetaRowset(const TabletSchemaSPtr& schema, const RowsetMetaSharedPtr& rowset_meta, |
66 | | std::string tablet_path) |
67 | 1.08M | : Rowset(schema, rowset_meta, std::move(tablet_path)) {} |
68 | | |
69 | 623k | BetaRowset::~BetaRowset() = default; |
70 | | |
71 | 1.07M | Status BetaRowset::init() { |
72 | 1.07M | return Status::OK(); // no op |
73 | 1.07M | } |
74 | | |
75 | | namespace { |
76 | | Status load_segment_rows_from_footer(BetaRowsetSharedPtr rowset, |
77 | | std::vector<uint32_t>* segment_rows, bool enable_segment_cache, |
78 | | OlapReaderStatistics* read_stats, |
79 | 38.5k | const io::IOContext* io_ctx) { |
80 | 38.5k | SegmentCacheHandle segment_cache_handle; |
81 | 38.5k | RETURN_IF_ERROR(SegmentLoader::instance()->load_segments( |
82 | 38.5k | rowset, &segment_cache_handle, enable_segment_cache, false, read_stats, io_ctx)); |
83 | 38.5k | for (const auto& segment : segment_cache_handle.get_segments()) { |
84 | 38.5k | segment_rows->emplace_back(segment->num_rows()); |
85 | 38.5k | } |
86 | 38.5k | return Status::OK(); |
87 | 38.5k | } |
88 | | |
89 | | Status check_segment_rows_consistency(const std::vector<uint32_t>& rows_from_meta, |
90 | | const std::vector<uint32_t>& rows_from_footer, |
91 | 38.6k | int64_t tablet_id, const std::string& rowset_id) { |
92 | 38.6k | DCHECK_EQ(rows_from_footer.size(), rows_from_meta.size()); |
93 | 77.2k | for (size_t i = 0; i < rows_from_footer.size(); i++) { |
94 | 38.6k | if (rows_from_footer[i] != rows_from_meta[i]) { |
95 | 0 | auto msg = fmt::format( |
96 | 0 | "segment rows mismatch between rowset meta and segment footer. " |
97 | 0 | "segment index: {}, meta rows: {}, footer rows: {}, tablet={}, rowset={}", |
98 | 0 | i, rows_from_meta[i], rows_from_footer[i], tablet_id, rowset_id); |
99 | 0 | if (config::enable_segment_rows_check_core) { |
100 | 0 | CHECK(false) << msg; |
101 | 0 | } |
102 | 0 | return Status::InternalError(msg); |
103 | 0 | } |
104 | 38.6k | } |
105 | 38.6k | return Status::OK(); |
106 | 38.6k | } |
107 | | } // namespace |
108 | | |
109 | | Status BetaRowset::get_segment_num_rows(std::vector<uint32_t>* segment_rows, |
110 | | bool enable_segment_cache, OlapReaderStatistics* read_stats, |
111 | 3.61M | const io::IOContext* io_ctx) { |
112 | 3.61M | #ifndef BE_TEST |
113 | | // `ROWSET_UNLOADING` is state for closed() called but owned by some readers. |
114 | | // So here `ROWSET_UNLOADING` is allowed. |
115 | 3.61M | DCHECK_NE(_rowset_state_machine.rowset_state(), ROWSET_UNLOADED); |
116 | 3.61M | #endif |
117 | 3.61M | RETURN_IF_ERROR(_load_segment_rows_once.call([this, enable_segment_cache, read_stats, io_ctx] { |
118 | 3.61M | auto segment_count = num_segments(); |
119 | 3.61M | if (segment_count == 0) { |
120 | 3.61M | return Status::OK(); |
121 | 3.61M | } |
122 | | |
123 | 3.61M | if (!_rowset_meta->get_num_segment_rows().empty()) { |
124 | 3.61M | if (_rowset_meta->get_num_segment_rows().size() == segment_count) { |
125 | | // use segment rows in rowset meta if eligible |
126 | 3.61M | TEST_SYNC_POINT("BetaRowset::get_segment_num_rows:use_segment_rows_from_meta"); |
127 | 3.61M | _segments_rows.assign(_rowset_meta->get_num_segment_rows().cbegin(), |
128 | 3.61M | _rowset_meta->get_num_segment_rows().cend()); |
129 | 3.61M | if (config::enable_segment_rows_consistency_check) { |
130 | | // verify segment rows from meta match segment footer |
131 | 3.61M | std::vector<uint32_t> rows_from_footer; |
132 | 3.61M | auto self = std::dynamic_pointer_cast<BetaRowset>(shared_from_this()); |
133 | 3.61M | auto load_status = load_segment_rows_from_footer( |
134 | 3.61M | self, &rows_from_footer, enable_segment_cache, read_stats, io_ctx); |
135 | 3.61M | if (load_status.ok()) { |
136 | 3.61M | return check_segment_rows_consistency( |
137 | 3.61M | _segments_rows, rows_from_footer, _rowset_meta->tablet_id(), |
138 | 3.61M | _rowset_meta->rowset_id().to_string()); |
139 | 3.61M | } |
140 | 3.61M | } |
141 | 3.61M | return Status::OK(); |
142 | 3.61M | } else { |
143 | 3.61M | auto msg = fmt::format( |
144 | 3.61M | "[verbose] corrupted segment rows info in rowset meta. " |
145 | 3.61M | "segment count: {}, segment rows size: {}, tablet={}, rowset={}", |
146 | 3.61M | segment_count, _rowset_meta->get_num_segment_rows().size(), |
147 | 3.61M | _rowset_meta->tablet_id(), _rowset_meta->rowset_id().to_string()); |
148 | 3.61M | if (config::enable_segment_rows_check_core) { |
149 | 3.61M | CHECK(false) << msg; |
150 | 3.61M | } |
151 | 3.61M | LOG_EVERY_SECOND(WARNING) << msg; |
152 | 3.61M | } |
153 | 3.61M | } |
154 | 3.61M | if (config::fail_when_segment_rows_not_in_rowset_meta) { |
155 | 3.61M | CHECK(false) << "[verbose] segment rows info not found in rowset meta. tablet=" |
156 | 3.61M | << _rowset_meta->tablet_id() |
157 | 3.61M | << ", rowset=" << _rowset_meta->rowset_id().to_string() |
158 | 3.61M | << ", version=" << _rowset_meta->version() |
159 | 3.61M | << ", debug_string=" << _rowset_meta->debug_string() |
160 | 3.61M | << ", stack=" << Status::InternalError("error"); |
161 | 3.61M | } |
162 | | // otherwise, read it from segment footer |
163 | 3.61M | TEST_SYNC_POINT("BetaRowset::get_segment_num_rows:load_from_segment_footer"); |
164 | 3.61M | auto self = std::dynamic_pointer_cast<BetaRowset>(shared_from_this()); |
165 | 3.61M | return load_segment_rows_from_footer(self, &_segments_rows, enable_segment_cache, |
166 | 3.61M | read_stats, io_ctx); |
167 | 3.61M | })); |
168 | 3.61M | segment_rows->assign(_segments_rows.cbegin(), _segments_rows.cend()); |
169 | 3.61M | return Status::OK(); |
170 | 3.61M | } |
171 | | |
172 | 25 | Status BetaRowset::get_inverted_index_size(int64_t* index_size) { |
173 | 25 | const auto& fs = _rowset_meta->fs(); |
174 | 25 | if (!fs) { |
175 | 0 | return Status::Error<INIT_FAILED>("get fs failed, resource_id={}", |
176 | 0 | _rowset_meta->resource_id()); |
177 | 0 | } |
178 | | |
179 | 25 | if (_schema->get_inverted_index_storage_format() == InvertedIndexStorageFormatPB::V1) { |
180 | 7 | for (const auto& index : _schema->inverted_indexes()) { |
181 | 15 | for (int seg_id = 0; seg_id < num_segments(); ++seg_id) { |
182 | 9 | auto seg_path = DORIS_TRY(segment_path(seg_id)); |
183 | 9 | int64_t file_size = 0; |
184 | | |
185 | 9 | std::string inverted_index_file_path = |
186 | 9 | InvertedIndexDescriptor::get_index_file_path_v1( |
187 | 9 | InvertedIndexDescriptor::get_index_file_path_prefix(seg_path), |
188 | 9 | index->index_id(), index->get_index_suffix()); |
189 | 9 | RETURN_IF_ERROR(fs->file_size(inverted_index_file_path, &file_size)); |
190 | 9 | *index_size += file_size; |
191 | 9 | } |
192 | 6 | } |
193 | 18 | } else { |
194 | 25 | for (int seg_id = 0; seg_id < num_segments(); ++seg_id) { |
195 | 18 | auto seg_path = DORIS_TRY(segment_path(seg_id)); |
196 | 18 | int64_t file_size = 0; |
197 | | |
198 | 18 | std::string inverted_index_file_path = InvertedIndexDescriptor::get_index_file_path_v2( |
199 | 18 | InvertedIndexDescriptor::get_index_file_path_prefix(seg_path)); |
200 | 18 | RETURN_IF_ERROR(fs->file_size(inverted_index_file_path, &file_size)); |
201 | 7 | *index_size += file_size; |
202 | 7 | } |
203 | 18 | } |
204 | 14 | return Status::OK(); |
205 | 25 | } |
206 | | |
207 | 238k | void BetaRowset::clear_inverted_index_cache() { |
208 | 331k | for (int i = 0; i < num_segments(); ++i) { |
209 | 93.3k | auto seg_path = segment_path(i); |
210 | 93.3k | if (!seg_path) { |
211 | 0 | continue; |
212 | 0 | } |
213 | | |
214 | 93.3k | auto index_path_prefix = InvertedIndexDescriptor::get_index_file_path_prefix(*seg_path); |
215 | 882k | for (const auto& column : tablet_schema()->columns()) { |
216 | 882k | auto index_metas = tablet_schema()->inverted_indexs(*column); |
217 | 882k | for (const auto& index_meta : index_metas) { |
218 | 12.0k | auto inverted_index_file_cache_key = |
219 | 12.0k | InvertedIndexDescriptor::get_index_file_cache_key( |
220 | 12.0k | index_path_prefix, index_meta->index_id(), |
221 | 12.0k | index_meta->get_index_suffix()); |
222 | 12.0k | (void)segment_v2::InvertedIndexSearcherCache::instance()->erase( |
223 | 12.0k | inverted_index_file_cache_key); |
224 | 12.0k | } |
225 | 882k | } |
226 | 93.3k | } |
227 | 238k | } |
228 | | |
229 | 779 | Status BetaRowset::get_segments_size(std::vector<size_t>* segments_size) { |
230 | 779 | auto fs = _rowset_meta->fs(); |
231 | 779 | if (!fs) { |
232 | 0 | return Status::Error<INIT_FAILED>("get fs failed, resource_id={}", |
233 | 0 | _rowset_meta->resource_id()); |
234 | 0 | } |
235 | | |
236 | 1.56k | for (int seg_id = 0; seg_id < num_segments(); ++seg_id) { |
237 | 790 | auto seg_path = DORIS_TRY(segment_path(seg_id)); |
238 | 790 | int64_t file_size; |
239 | 790 | RETURN_IF_ERROR(fs->file_size(seg_path, &file_size)); |
240 | 789 | segments_size->push_back(file_size); |
241 | 789 | } |
242 | 778 | return Status::OK(); |
243 | 779 | } |
244 | | |
245 | 161k | Status BetaRowset::load_segments(std::vector<segment_v2::SegmentSharedPtr>* segments) { |
246 | 161k | return load_segments(0, num_segments(), segments); |
247 | 161k | } |
248 | | |
249 | | Status BetaRowset::load_segments(int64_t seg_id_begin, int64_t seg_id_end, |
250 | 196k | std::vector<segment_v2::SegmentSharedPtr>* segments) { |
251 | 196k | int64_t seg_id = seg_id_begin; |
252 | 352k | while (seg_id < seg_id_end) { |
253 | 155k | std::shared_ptr<segment_v2::Segment> segment; |
254 | 155k | RETURN_IF_ERROR(load_segment(seg_id, nullptr, &segment)); |
255 | 155k | segments->push_back(std::move(segment)); |
256 | 155k | seg_id++; |
257 | 155k | } |
258 | 196k | return Status::OK(); |
259 | 196k | } |
260 | | |
261 | | Status BetaRowset::load_segment(int64_t seg_id, OlapReaderStatistics* stats, |
262 | | segment_v2::SegmentSharedPtr* segment, |
263 | 989k | const io::IOContext* io_ctx) { |
264 | 989k | auto fs = _rowset_meta->fs(); |
265 | 989k | if (!fs) { |
266 | 1 | return Status::Error<INIT_FAILED>("get fs failed"); |
267 | 1 | } |
268 | | |
269 | 989k | DCHECK(seg_id >= 0); |
270 | 989k | auto seg_path = DORIS_TRY(segment_path(seg_id)); |
271 | 989k | io::FileReaderOptions reader_options { |
272 | 989k | .cache_type = config::enable_file_cache ? io::FileCachePolicy::FILE_BLOCK_CACHE |
273 | 989k | : io::FileCachePolicy::NO_CACHE, |
274 | 989k | .is_doris_table = true, |
275 | 989k | .cache_base_path = "", |
276 | 989k | .file_size = _rowset_meta->segment_file_size(static_cast<int>(seg_id)), |
277 | 989k | .tablet_id = _rowset_meta->tablet_id(), |
278 | 989k | .storage_resource_id = _rowset_meta->resource_id(), |
279 | 989k | }; |
280 | | |
281 | 989k | auto s = segment_v2::Segment::open( |
282 | 989k | fs, seg_path, _rowset_meta->tablet_id(), static_cast<uint32_t>(seg_id), rowset_id(), |
283 | 989k | _schema, reader_options, segment, |
284 | 989k | _rowset_meta->inverted_index_file_info(static_cast<int>(seg_id)), stats, io_ctx); |
285 | 989k | if (!s.ok()) { |
286 | 5 | LOG(WARNING) << "failed to open segment. " << seg_path << " under rowset " << rowset_id() |
287 | 5 | << " : " << s.to_string(); |
288 | 5 | return s; |
289 | 5 | } |
290 | 989k | return Status::OK(); |
291 | 989k | } |
292 | | |
293 | 6.04M | Status BetaRowset::create_reader(RowsetReaderSharedPtr* result) { |
294 | | // NOTE: We use std::static_pointer_cast for performance |
295 | 6.04M | result->reset(new BetaRowsetReader(std::static_pointer_cast<BetaRowset>(shared_from_this()))); |
296 | 6.04M | return Status::OK(); |
297 | 6.04M | } |
298 | | |
299 | 40.3k | Status BetaRowset::remove() { |
300 | 40.3k | if (!is_local()) { |
301 | 0 | DCHECK(false) << _rowset_meta->tablet_id() << ' ' << rowset_id(); |
302 | 0 | return Status::OK(); |
303 | 0 | } |
304 | | |
305 | | // TODO should we close and remove all segment reader first? |
306 | 40.3k | VLOG_NOTICE << "begin to remove files in rowset " << rowset_id() |
307 | 6 | << ", version:" << start_version() << "-" << end_version() |
308 | 6 | << ", tabletid:" << _rowset_meta->tablet_id(); |
309 | | // If the rowset was removed, it need to remove the fds in segment cache directly |
310 | 40.3k | clear_cache(); |
311 | | |
312 | 40.3k | bool success = true; |
313 | 40.3k | Status st; |
314 | 40.3k | const auto& fs = io::global_local_filesystem(); |
315 | 60.6k | for (int i = 0; i < num_segments(); ++i) { |
316 | 20.3k | auto seg_path = local_segment_path(_tablet_path, rowset_id().to_string(), i); |
317 | 20.3k | LOG(INFO) << "deleting " << seg_path; |
318 | 20.3k | st = fs->delete_file(seg_path); |
319 | 20.3k | if (!st.ok()) { |
320 | 0 | LOG(WARNING) << st.to_string(); |
321 | 0 | success = false; |
322 | 0 | } |
323 | | |
324 | 20.3k | if (_schema->get_inverted_index_storage_format() == InvertedIndexStorageFormatPB::V1) { |
325 | 0 | for (const auto& column : _schema->columns()) { |
326 | 0 | auto index_metas = _schema->inverted_indexs(*column); |
327 | 0 | for (const auto& index_meta : index_metas) { |
328 | 0 | std::string inverted_index_file = |
329 | 0 | InvertedIndexDescriptor::get_index_file_path_v1( |
330 | 0 | InvertedIndexDescriptor::get_index_file_path_prefix(seg_path), |
331 | 0 | index_meta->index_id(), index_meta->get_index_suffix()); |
332 | 0 | st = fs->delete_file(inverted_index_file); |
333 | 0 | if (!st.ok()) { |
334 | 0 | LOG(WARNING) << st.to_string(); |
335 | 0 | success = false; |
336 | 0 | } |
337 | 0 | } |
338 | 0 | } |
339 | 20.3k | } else { |
340 | 20.3k | if (_schema->has_inverted_index() || _schema->has_ann_index()) { |
341 | 110 | std::string inverted_index_file = InvertedIndexDescriptor::get_index_file_path_v2( |
342 | 110 | InvertedIndexDescriptor::get_index_file_path_prefix(seg_path)); |
343 | 110 | st = fs->delete_file(inverted_index_file); |
344 | 110 | if (!st.ok()) { |
345 | 0 | LOG(WARNING) << st.to_string(); |
346 | 0 | success = false; |
347 | 0 | } |
348 | 110 | } |
349 | 20.3k | } |
350 | 20.3k | } |
351 | 40.3k | if (!success) { |
352 | 0 | return Status::Error<ROWSET_DELETE_FILE_FAILED>("failed to remove files in rowset {}", |
353 | 0 | rowset_id().to_string()); |
354 | 0 | } |
355 | 40.3k | return Status::OK(); |
356 | 40.3k | } |
357 | | |
358 | 35.5k | void BetaRowset::do_close() { |
359 | | // do nothing. |
360 | 35.5k | } |
361 | | |
362 | | Status BetaRowset::link_files_to(const std::string& dir, RowsetId new_rowset_id, |
363 | | size_t new_rowset_start_seg_id, |
364 | 3.93k | std::set<int64_t>* without_index_uids) { |
365 | 3.93k | if (!is_local()) { |
366 | 0 | DCHECK(false) << _rowset_meta->tablet_id() << ' ' << rowset_id(); |
367 | 0 | return Status::InternalError("should be local rowset. tablet_id={} rowset_id={}", |
368 | 0 | _rowset_meta->tablet_id(), rowset_id().to_string()); |
369 | 0 | } |
370 | | |
371 | 3.93k | const auto& local_fs = io::global_local_filesystem(); |
372 | 3.93k | Status status; |
373 | 3.93k | std::vector<std::string> linked_success_files; |
374 | 3.93k | Defer remove_linked_files {[&]() { // clear linked files if errors happen |
375 | 3.93k | if (!status.ok()) { |
376 | 0 | LOG(WARNING) << "will delete linked success files due to error " << status; |
377 | 0 | std::vector<io::Path> paths; |
378 | 0 | for (auto& file : linked_success_files) { |
379 | 0 | paths.emplace_back(file); |
380 | 0 | LOG(WARNING) << "will delete linked success file " << file << " due to error"; |
381 | 0 | } |
382 | 0 | static_cast<void>(local_fs->batch_delete(paths)); |
383 | 0 | LOG(WARNING) << "done delete linked success files due to error " << status; |
384 | 0 | } |
385 | 3.93k | }}; |
386 | | |
387 | 4.08k | for (int i = 0; i < num_segments(); ++i) { |
388 | 147 | auto dst_path = |
389 | 147 | local_segment_path(dir, new_rowset_id.to_string(), i + new_rowset_start_seg_id); |
390 | 147 | bool dst_path_exist = false; |
391 | 147 | if (!local_fs->exists(dst_path, &dst_path_exist).ok() || dst_path_exist) { |
392 | 0 | status = Status::Error<FILE_ALREADY_EXIST>( |
393 | 0 | "failed to create hard link, file already exist: {}", dst_path); |
394 | 0 | return status; |
395 | 0 | } |
396 | 147 | auto src_path = local_segment_path(_tablet_path, rowset_id().to_string(), i); |
397 | | // TODO(lingbin): how external storage support link? |
398 | | // use copy? or keep refcount to avoid being delete? |
399 | 147 | if (!local_fs->link_file(src_path, dst_path).ok()) { |
400 | 0 | status = Status::Error<OS_ERROR>("fail to create hard link. from={}, to={}, errno={}", |
401 | 0 | src_path, dst_path, Errno::no()); |
402 | 0 | return status; |
403 | 0 | } |
404 | 147 | linked_success_files.push_back(dst_path); |
405 | 147 | DBUG_EXECUTE_IF("fault_inject::BetaRowset::link_files_to::_link_inverted_index_file", { |
406 | 147 | status = Status::Error<OS_ERROR>("fault_inject link_file error"); |
407 | 147 | return status; |
408 | 147 | }); |
409 | 147 | if (_schema->get_inverted_index_storage_format() == InvertedIndexStorageFormatPB::V1) { |
410 | 40 | for (const auto& index : _schema->inverted_indexes()) { |
411 | 9 | auto index_id = index->index_id(); |
412 | 9 | if (without_index_uids != nullptr && without_index_uids->count(index_id)) { |
413 | 1 | continue; |
414 | 1 | } |
415 | 8 | std::string inverted_index_src_file_path = |
416 | 8 | InvertedIndexDescriptor::get_index_file_path_v1( |
417 | 8 | InvertedIndexDescriptor::get_index_file_path_prefix(src_path), |
418 | 8 | index_id, index->get_index_suffix()); |
419 | 8 | std::string inverted_index_dst_file_path = |
420 | 8 | InvertedIndexDescriptor::get_index_file_path_v1( |
421 | 8 | InvertedIndexDescriptor::get_index_file_path_prefix(dst_path), |
422 | 8 | index_id, index->get_index_suffix()); |
423 | 8 | bool index_file_exists = true; |
424 | 8 | RETURN_IF_ERROR(local_fs->exists(inverted_index_src_file_path, &index_file_exists)); |
425 | 8 | if (index_file_exists) { |
426 | 8 | DBUG_EXECUTE_IF( |
427 | 8 | "fault_inject::BetaRowset::link_files_to::_link_inverted_index_file", { |
428 | 8 | status = Status::Error<OS_ERROR>( |
429 | 8 | "fault_inject link_file error from={}, to={}", |
430 | 8 | inverted_index_src_file_path, inverted_index_dst_file_path); |
431 | 8 | return status; |
432 | 8 | }); |
433 | 8 | if (!local_fs->link_file(inverted_index_src_file_path, |
434 | 8 | inverted_index_dst_file_path) |
435 | 8 | .ok()) { |
436 | 0 | status = Status::Error<OS_ERROR>( |
437 | 0 | "fail to create hard link. from={}, to={}, errno={}", |
438 | 0 | inverted_index_src_file_path, inverted_index_dst_file_path, |
439 | 0 | Errno::no()); |
440 | 0 | return status; |
441 | 0 | } |
442 | 8 | linked_success_files.push_back(inverted_index_dst_file_path); |
443 | 8 | LOG(INFO) << "success to create hard link. from=" |
444 | 8 | << inverted_index_src_file_path << ", " |
445 | 8 | << "to=" << inverted_index_dst_file_path; |
446 | 8 | } else { |
447 | 0 | LOG(WARNING) << "skip create hard link to not existed index file=" |
448 | 0 | << inverted_index_src_file_path; |
449 | 0 | } |
450 | 8 | } |
451 | 107 | } else { |
452 | 107 | if ((_schema->has_inverted_index() || _schema->has_ann_index()) && |
453 | 107 | (without_index_uids == nullptr || without_index_uids->empty())) { |
454 | 6 | std::string inverted_index_file_src = |
455 | 6 | InvertedIndexDescriptor::get_index_file_path_v2( |
456 | 6 | InvertedIndexDescriptor::get_index_file_path_prefix(src_path)); |
457 | 6 | std::string inverted_index_file_dst = |
458 | 6 | InvertedIndexDescriptor::get_index_file_path_v2( |
459 | 6 | InvertedIndexDescriptor::get_index_file_path_prefix(dst_path)); |
460 | 6 | bool index_dst_path_exist = false; |
461 | | |
462 | 6 | if (!local_fs->exists(inverted_index_file_dst, &index_dst_path_exist).ok() || |
463 | 6 | index_dst_path_exist) { |
464 | 0 | status = Status::Error<FILE_ALREADY_EXIST>( |
465 | 0 | "failed to create hard link, file already exist: {}", |
466 | 0 | inverted_index_file_dst); |
467 | 0 | return status; |
468 | 0 | } |
469 | 6 | if (!local_fs->link_file(inverted_index_file_src, inverted_index_file_dst).ok()) { |
470 | 0 | status = Status::Error<OS_ERROR>( |
471 | 0 | "fail to create hard link. from={}, to={}, errno={}", |
472 | 0 | inverted_index_file_src, inverted_index_file_dst, Errno::no()); |
473 | 0 | return status; |
474 | 0 | } |
475 | 6 | linked_success_files.push_back(inverted_index_file_dst); |
476 | 6 | } |
477 | 107 | } |
478 | 147 | } |
479 | 3.93k | return Status::OK(); |
480 | 3.93k | } |
481 | | |
482 | 4 | Status BetaRowset::copy_files_to(const std::string& dir, const RowsetId& new_rowset_id) { |
483 | 4 | if (!is_local()) { |
484 | 0 | DCHECK(false) << _rowset_meta->tablet_id() << ' ' << rowset_id(); |
485 | 0 | return Status::InternalError("should be local rowset. tablet_id={} rowset_id={}", |
486 | 0 | _rowset_meta->tablet_id(), rowset_id().to_string()); |
487 | 0 | } |
488 | | |
489 | 4 | bool exists = false; |
490 | 4 | for (int i = 0; i < num_segments(); ++i) { |
491 | 0 | auto dst_path = local_segment_path(dir, new_rowset_id.to_string(), i); |
492 | 0 | RETURN_IF_ERROR(io::global_local_filesystem()->exists(dst_path, &exists)); |
493 | 0 | if (exists) { |
494 | 0 | return Status::Error<FILE_ALREADY_EXIST>("file already exist: {}", dst_path); |
495 | 0 | } |
496 | 0 | auto src_path = local_segment_path(_tablet_path, rowset_id().to_string(), i); |
497 | 0 | RETURN_IF_ERROR(io::global_local_filesystem()->copy_path(src_path, dst_path)); |
498 | 0 | if (_schema->get_inverted_index_storage_format() == InvertedIndexStorageFormatPB::V1) { |
499 | 0 | for (const auto& column : _schema->columns()) { |
500 | | // if (column.has_inverted_index()) { |
501 | 0 | auto index_metas = _schema->inverted_indexs(*column); |
502 | 0 | for (const auto& index_meta : index_metas) { |
503 | 0 | std::string inverted_index_src_file_path = |
504 | 0 | InvertedIndexDescriptor::get_index_file_path_v1( |
505 | 0 | InvertedIndexDescriptor::get_index_file_path_prefix(src_path), |
506 | 0 | index_meta->index_id(), index_meta->get_index_suffix()); |
507 | 0 | std::string inverted_index_dst_file_path = |
508 | 0 | InvertedIndexDescriptor::get_index_file_path_v1( |
509 | 0 | InvertedIndexDescriptor::get_index_file_path_prefix(dst_path), |
510 | 0 | index_meta->index_id(), index_meta->get_index_suffix()); |
511 | 0 | RETURN_IF_ERROR(io::global_local_filesystem()->copy_path( |
512 | 0 | inverted_index_src_file_path, inverted_index_dst_file_path)); |
513 | 0 | LOG(INFO) << "success to copy file. from=" << inverted_index_src_file_path |
514 | 0 | << ", " |
515 | 0 | << "to=" << inverted_index_dst_file_path; |
516 | 0 | } |
517 | 0 | } |
518 | 0 | } else { |
519 | 0 | if (_schema->has_inverted_index() || _schema->has_ann_index()) { |
520 | 0 | std::string inverted_index_src_file = |
521 | 0 | InvertedIndexDescriptor::get_index_file_path_v2( |
522 | 0 | InvertedIndexDescriptor::get_index_file_path_prefix(src_path)); |
523 | 0 | std::string inverted_index_dst_file = |
524 | 0 | InvertedIndexDescriptor::get_index_file_path_v2( |
525 | 0 | InvertedIndexDescriptor::get_index_file_path_prefix(dst_path)); |
526 | 0 | RETURN_IF_ERROR(io::global_local_filesystem()->copy_path(inverted_index_src_file, |
527 | 0 | inverted_index_dst_file)); |
528 | 0 | LOG(INFO) << "success to copy file. from=" << inverted_index_src_file << ", " |
529 | 0 | << "to=" << inverted_index_dst_file; |
530 | 0 | } |
531 | 0 | } |
532 | 0 | } |
533 | 4 | return Status::OK(); |
534 | 4 | } |
535 | | |
536 | 5 | Status BetaRowset::upload_to(const StorageResource& dest_fs, const RowsetId& new_rowset_id) { |
537 | 5 | if (!is_local()) { |
538 | 0 | DCHECK(false) << _rowset_meta->tablet_id() << ' ' << rowset_id(); |
539 | 0 | return Status::InternalError("should be local rowset. tablet_id={} rowset_id={}", |
540 | 0 | _rowset_meta->tablet_id(), rowset_id().to_string()); |
541 | 0 | } |
542 | | |
543 | 5 | if (num_segments() < 1) { |
544 | 3 | return Status::OK(); |
545 | 3 | } |
546 | 2 | std::vector<io::Path> local_paths; |
547 | 2 | local_paths.reserve(num_segments()); |
548 | 2 | std::vector<io::Path> dest_paths; |
549 | 2 | dest_paths.reserve(num_segments()); |
550 | 4 | for (int i = 0; i < num_segments(); ++i) { |
551 | | // Note: Here we use relative path for remote. |
552 | 2 | auto remote_seg_path = dest_fs.remote_segment_path(_rowset_meta->tablet_id(), |
553 | 2 | new_rowset_id.to_string(), i); |
554 | 2 | auto local_seg_path = local_segment_path(_tablet_path, rowset_id().to_string(), i); |
555 | 2 | dest_paths.emplace_back(remote_seg_path); |
556 | 2 | local_paths.emplace_back(local_seg_path); |
557 | 2 | if (_schema->get_inverted_index_storage_format() == InvertedIndexStorageFormatPB::V1) { |
558 | 0 | for (const auto& column : _schema->columns()) { |
559 | | // if (column.has_inverted_index()) { |
560 | 0 | auto index_metas = _schema->inverted_indexs(*column); |
561 | 0 | for (const auto& index_meta : index_metas) { |
562 | 0 | std::string remote_inverted_index_file = |
563 | 0 | InvertedIndexDescriptor::get_index_file_path_v1( |
564 | 0 | InvertedIndexDescriptor::get_index_file_path_prefix( |
565 | 0 | remote_seg_path), |
566 | 0 | index_meta->index_id(), index_meta->get_index_suffix()); |
567 | 0 | std::string local_inverted_index_file = |
568 | 0 | InvertedIndexDescriptor::get_index_file_path_v1( |
569 | 0 | InvertedIndexDescriptor::get_index_file_path_prefix( |
570 | 0 | local_seg_path), |
571 | 0 | index_meta->index_id(), index_meta->get_index_suffix()); |
572 | 0 | dest_paths.emplace_back(remote_inverted_index_file); |
573 | 0 | local_paths.emplace_back(local_inverted_index_file); |
574 | 0 | } |
575 | 0 | } |
576 | 2 | } else { |
577 | 2 | if (_schema->has_inverted_index() || _schema->has_ann_index()) { |
578 | 0 | std::string remote_inverted_index_file = |
579 | 0 | InvertedIndexDescriptor::get_index_file_path_v2( |
580 | 0 | InvertedIndexDescriptor::get_index_file_path_prefix( |
581 | 0 | remote_seg_path)); |
582 | 0 | std::string local_inverted_index_file = |
583 | 0 | InvertedIndexDescriptor::get_index_file_path_v2( |
584 | 0 | InvertedIndexDescriptor::get_index_file_path_prefix( |
585 | 0 | local_seg_path)); |
586 | 0 | dest_paths.emplace_back(remote_inverted_index_file); |
587 | 0 | local_paths.emplace_back(local_inverted_index_file); |
588 | 0 | } |
589 | 2 | } |
590 | 2 | } |
591 | 2 | auto st = dest_fs.fs->batch_upload(local_paths, dest_paths); |
592 | 2 | if (st.ok()) { |
593 | 2 | DorisMetrics::instance()->upload_rowset_count->increment(1); |
594 | 2 | DorisMetrics::instance()->upload_total_byte->increment(total_disk_size()); |
595 | 2 | } else { |
596 | 0 | DorisMetrics::instance()->upload_fail_count->increment(1); |
597 | 0 | } |
598 | 2 | return st; |
599 | 5 | } |
600 | | |
601 | 40 | Status BetaRowset::check_file_exist() { |
602 | 40 | const auto& fs = _rowset_meta->fs(); |
603 | 40 | if (!fs) { |
604 | 0 | return Status::InternalError("fs is not initialized, resource_id={}", |
605 | 0 | _rowset_meta->resource_id()); |
606 | 0 | } |
607 | | |
608 | 42 | for (int i = 0; i < num_segments(); ++i) { |
609 | 2 | auto seg_path = DORIS_TRY(segment_path(i)); |
610 | 2 | bool seg_file_exist = false; |
611 | 2 | RETURN_IF_ERROR(fs->exists(seg_path, &seg_file_exist)); |
612 | 2 | if (!seg_file_exist) { |
613 | 0 | return Status::InternalError("data file not existed: {}, rowset_id={}", seg_path, |
614 | 0 | rowset_id().to_string()); |
615 | 0 | } |
616 | 2 | } |
617 | | |
618 | 40 | return Status::OK(); |
619 | 40 | } |
620 | | |
621 | 0 | Status BetaRowset::check_current_rowset_segment() { |
622 | 0 | const auto& fs = _rowset_meta->fs(); |
623 | 0 | if (!fs) { |
624 | 0 | return Status::InternalError("fs is not initialized, resource_id={}", |
625 | 0 | _rowset_meta->resource_id()); |
626 | 0 | } |
627 | | |
628 | 0 | for (int seg_id = 0; seg_id < num_segments(); ++seg_id) { |
629 | 0 | auto seg_path = DORIS_TRY(segment_path(seg_id)); |
630 | |
|
631 | 0 | std::shared_ptr<segment_v2::Segment> segment; |
632 | 0 | io::FileReaderOptions reader_options { |
633 | 0 | .cache_type = config::enable_file_cache ? io::FileCachePolicy::FILE_BLOCK_CACHE |
634 | 0 | : io::FileCachePolicy::NO_CACHE, |
635 | 0 | .is_doris_table = true, |
636 | 0 | .cache_base_path {}, |
637 | 0 | .file_size = _rowset_meta->segment_file_size(seg_id), |
638 | 0 | .tablet_id = _rowset_meta->tablet_id(), |
639 | 0 | .storage_resource_id = _rowset_meta->resource_id(), |
640 | 0 | }; |
641 | |
|
642 | 0 | auto s = segment_v2::Segment::open(fs, seg_path, _rowset_meta->tablet_id(), seg_id, |
643 | 0 | rowset_id(), _schema, reader_options, &segment, |
644 | 0 | _rowset_meta->inverted_index_file_info(seg_id)); |
645 | 0 | if (!s.ok()) { |
646 | 0 | LOG(WARNING) << "segment can not be opened. file=" << seg_path; |
647 | 0 | return s; |
648 | 0 | } |
649 | 0 | } |
650 | | |
651 | 0 | return Status::OK(); |
652 | 0 | } |
653 | | |
654 | 4 | Status BetaRowset::add_to_binlog() { |
655 | | // FIXME(Drogon): not only local file system |
656 | 4 | if (!is_local()) { |
657 | 0 | DCHECK(false) << _rowset_meta->tablet_id() << ' ' << rowset_id(); |
658 | 0 | return Status::InternalError("should be local rowset. tablet_id={} rowset_id={}", |
659 | 0 | _rowset_meta->tablet_id(), rowset_id().to_string()); |
660 | 0 | } |
661 | | |
662 | 4 | const auto& fs = io::global_local_filesystem(); |
663 | 4 | auto segments_num = num_segments(); |
664 | 4 | VLOG_DEBUG << fmt::format("add rowset to binlog. rowset_id={}, segments_num={}", |
665 | 0 | rowset_id().to_string(), segments_num); |
666 | | |
667 | 4 | Status status; |
668 | 4 | std::vector<std::string> linked_success_files; |
669 | 4 | Defer remove_linked_files {[&]() { // clear linked files if errors happen |
670 | 4 | if (!status.ok()) { |
671 | 0 | LOG(WARNING) << "will delete linked success files due to error " |
672 | 0 | << status.to_string_no_stack(); |
673 | 0 | std::vector<io::Path> paths; |
674 | 0 | for (auto& file : linked_success_files) { |
675 | 0 | paths.emplace_back(file); |
676 | 0 | LOG(WARNING) << "will delete linked success file " << file << " due to error"; |
677 | 0 | } |
678 | 0 | static_cast<void>(fs->batch_delete(paths)); |
679 | 0 | LOG(WARNING) << "done delete linked success files due to error " |
680 | 0 | << status.to_string_no_stack(); |
681 | 0 | } |
682 | 4 | }}; |
683 | | |
684 | | // The publish_txn might fail even if the add_to_binlog success, so we need to check |
685 | | // whether a file already exists before linking. |
686 | 4 | auto errno_is_file_exists = []() { return Errno::no() == EEXIST; }; |
687 | | |
688 | | // all segments are in the same directory, so cache binlog_dir without multi times check |
689 | 4 | std::string binlog_dir; |
690 | 6 | for (int i = 0; i < segments_num; ++i) { |
691 | 2 | auto seg_file = local_segment_path(_tablet_path, rowset_id().to_string(), i); |
692 | | |
693 | 2 | if (binlog_dir.empty()) { |
694 | 2 | binlog_dir = std::filesystem::path(seg_file).parent_path().append("_binlog").string(); |
695 | | |
696 | 2 | bool exists = true; |
697 | 2 | RETURN_IF_ERROR(fs->exists(binlog_dir, &exists)); |
698 | 2 | if (!exists) { |
699 | 2 | RETURN_IF_ERROR(fs->create_directory(binlog_dir)); |
700 | 2 | } |
701 | 2 | } |
702 | | |
703 | 2 | auto binlog_file = |
704 | 2 | (std::filesystem::path(binlog_dir) / std::filesystem::path(seg_file).filename()) |
705 | 2 | .string(); |
706 | 2 | VLOG_DEBUG << "link " << seg_file << " to " << binlog_file; |
707 | 2 | if (!fs->link_file(seg_file, binlog_file).ok() && !errno_is_file_exists()) { |
708 | 0 | status = Status::Error<OS_ERROR>("fail to create hard link. from={}, to={}, errno={}", |
709 | 0 | seg_file, binlog_file, Errno::no()); |
710 | 0 | return status; |
711 | 0 | } |
712 | 2 | linked_success_files.push_back(binlog_file); |
713 | | |
714 | 2 | if (_schema->get_inverted_index_storage_format() == InvertedIndexStorageFormatPB::V1) { |
715 | 2 | for (const auto& index : _schema->inverted_indexes()) { |
716 | 2 | auto index_id = index->index_id(); |
717 | 2 | auto index_file = InvertedIndexDescriptor::get_index_file_path_v1( |
718 | 2 | InvertedIndexDescriptor::get_index_file_path_prefix(seg_file), index_id, |
719 | 2 | index->get_index_suffix()); |
720 | 2 | auto binlog_index_file = (std::filesystem::path(binlog_dir) / |
721 | 2 | std::filesystem::path(index_file).filename()) |
722 | 2 | .string(); |
723 | 2 | VLOG_DEBUG << "link " << index_file << " to " << binlog_index_file; |
724 | 2 | if (!fs->link_file(index_file, binlog_index_file).ok() && !errno_is_file_exists()) { |
725 | 0 | status = Status::Error<OS_ERROR>( |
726 | 0 | "fail to create hard link. from={}, to={}, errno={}", index_file, |
727 | 0 | binlog_index_file, Errno::no()); |
728 | 0 | return status; |
729 | 0 | } |
730 | 2 | linked_success_files.push_back(binlog_index_file); |
731 | 2 | } |
732 | 1 | } else { |
733 | 1 | if (_schema->has_inverted_index() || _schema->has_ann_index()) { |
734 | 1 | auto index_file = InvertedIndexDescriptor::get_index_file_path_v2( |
735 | 1 | InvertedIndexDescriptor::get_index_file_path_prefix(seg_file)); |
736 | 1 | auto binlog_index_file = (std::filesystem::path(binlog_dir) / |
737 | 1 | std::filesystem::path(index_file).filename()) |
738 | 1 | .string(); |
739 | 1 | VLOG_DEBUG << "link " << index_file << " to " << binlog_index_file; |
740 | 1 | if (!fs->link_file(index_file, binlog_index_file).ok() && !errno_is_file_exists()) { |
741 | 0 | status = Status::Error<OS_ERROR>( |
742 | 0 | "fail to create hard link. from={}, to={}, errno={}", index_file, |
743 | 0 | binlog_index_file, Errno::no()); |
744 | 0 | return status; |
745 | 0 | } |
746 | 1 | linked_success_files.push_back(binlog_index_file); |
747 | 1 | } |
748 | 1 | } |
749 | 2 | } |
750 | | |
751 | 4 | return Status::OK(); |
752 | 4 | } |
753 | | |
754 | 10 | Status BetaRowset::calc_file_crc(uint32_t* crc_value, int64_t* file_count) { |
755 | 10 | const auto& fs = _rowset_meta->fs(); |
756 | 10 | DBUG_EXECUTE_IF("fault_inject::BetaRowset::calc_file_crc", |
757 | 10 | { return Status::Error<OS_ERROR>("fault_inject calc_file_crc error"); }); |
758 | 10 | if (num_segments() < 1) { |
759 | 2 | *crc_value = 0x92a8fc17; // magic code from crc32c table |
760 | 2 | return Status::OK(); |
761 | 2 | } |
762 | | |
763 | | // 1. pick up all the files including dat file and idx file |
764 | 8 | std::vector<io::Path> file_paths; |
765 | 16 | for (int seg_id = 0; seg_id < num_segments(); ++seg_id) { |
766 | 8 | auto seg_path = DORIS_TRY(segment_path(seg_id)); |
767 | 8 | file_paths.emplace_back(seg_path); |
768 | 8 | if (_schema->get_inverted_index_storage_format() == InvertedIndexStorageFormatPB::V1) { |
769 | 0 | for (const auto& column : _schema->columns()) { |
770 | 0 | auto index_metas = _schema->inverted_indexs(*column); |
771 | 0 | for (const auto& index_meta : index_metas) { |
772 | 0 | std::string inverted_index_file = |
773 | 0 | InvertedIndexDescriptor::get_index_file_path_v1( |
774 | 0 | InvertedIndexDescriptor::get_index_file_path_prefix(seg_path), |
775 | 0 | index_meta->index_id(), index_meta->get_index_suffix()); |
776 | 0 | file_paths.emplace_back(std::move(inverted_index_file)); |
777 | 0 | } |
778 | 0 | } |
779 | 8 | } else { |
780 | 8 | if (_schema->has_inverted_index() || _schema->has_ann_index()) { |
781 | 8 | std::string inverted_index_file = InvertedIndexDescriptor::get_index_file_path_v2( |
782 | 8 | InvertedIndexDescriptor::get_index_file_path_prefix(seg_path)); |
783 | 8 | file_paths.emplace_back(std::move(inverted_index_file)); |
784 | 8 | } |
785 | 8 | } |
786 | 8 | } |
787 | 8 | *crc_value = 0; |
788 | 8 | *file_count = file_paths.size(); |
789 | 8 | if (!is_local()) { |
790 | 8 | return Status::OK(); |
791 | 8 | } |
792 | | |
793 | | // 2. calculate the md5sum of each file |
794 | 0 | const auto& local_fs = io::global_local_filesystem(); |
795 | 0 | DCHECK(!file_paths.empty()); |
796 | 0 | std::vector<std::string> all_file_md5; |
797 | 0 | all_file_md5.reserve(file_paths.size()); |
798 | 0 | for (const auto& file_path : file_paths) { |
799 | 0 | std::string file_md5sum; |
800 | 0 | auto status = local_fs->md5sum(file_path, &file_md5sum); |
801 | 0 | if (!status.ok()) { |
802 | 0 | return status; |
803 | 0 | } |
804 | 0 | VLOG_CRITICAL << fmt::format("calc file_md5sum finished. file_path={}, md5sum={}", |
805 | 0 | file_path.string(), file_md5sum); |
806 | 0 | all_file_md5.emplace_back(std::move(file_md5sum)); |
807 | 0 | } |
808 | 0 | std::sort(all_file_md5.begin(), all_file_md5.end()); |
809 | | |
810 | | // 3. calculate the crc_value based on all_file_md5 |
811 | 0 | DCHECK(file_paths.size() == all_file_md5.size()); |
812 | 0 | for (auto& i : all_file_md5) { |
813 | 0 | *crc_value = crc32c::Extend(*crc_value, (const uint8_t*)i.data(), i.size()); |
814 | 0 | } |
815 | |
|
816 | 0 | return Status::OK(); |
817 | 0 | } |
818 | | |
819 | | Status BetaRowset::show_nested_index_file(rapidjson::Value* rowset_value, |
820 | 147 | rapidjson::Document::AllocatorType& allocator) { |
821 | 147 | const auto& fs = _rowset_meta->fs(); |
822 | 147 | auto storage_format = _schema->get_inverted_index_storage_format(); |
823 | 147 | std::string format_str; |
824 | 147 | switch (storage_format) { |
825 | 7 | case InvertedIndexStorageFormatPB::V1: |
826 | 7 | format_str = "V1"; |
827 | 7 | break; |
828 | 71 | case InvertedIndexStorageFormatPB::V2: |
829 | 71 | format_str = "V2"; |
830 | 71 | break; |
831 | 69 | case InvertedIndexStorageFormatPB::V3: |
832 | 69 | format_str = "V3"; |
833 | 69 | break; |
834 | 0 | default: |
835 | 0 | return Status::InternalError("inverted index storage format error"); |
836 | 0 | break; |
837 | 147 | } |
838 | 147 | auto rs_id = rowset_id().to_string(); |
839 | 147 | rowset_value->AddMember("rowset_id", rapidjson::Value(rs_id.c_str(), allocator), allocator); |
840 | 147 | rowset_value->AddMember("index_storage_format", rapidjson::Value(format_str.c_str(), allocator), |
841 | 147 | allocator); |
842 | 147 | rapidjson::Value segments(rapidjson::kArrayType); |
843 | 221 | for (int seg_id = 0; seg_id < num_segments(); ++seg_id) { |
844 | 75 | rapidjson::Value segment(rapidjson::kObjectType); |
845 | 75 | segment.AddMember("segment_id", rapidjson::Value(seg_id).Move(), allocator); |
846 | | |
847 | 75 | auto seg_path = DORIS_TRY(segment_path(seg_id)); |
848 | 75 | auto index_file_path_prefix = InvertedIndexDescriptor::get_index_file_path_prefix(seg_path); |
849 | 75 | auto index_file_reader = std::make_unique<IndexFileReader>( |
850 | 75 | fs, std::string(index_file_path_prefix), storage_format, InvertedIndexFileInfo(), |
851 | 75 | _rowset_meta->tablet_id()); |
852 | 75 | RETURN_IF_ERROR(index_file_reader->init()); |
853 | 74 | auto dirs = index_file_reader->get_all_directories(); |
854 | | |
855 | 74 | auto add_file_info_to_json = [&](const std::string& path, |
856 | 80 | rapidjson::Value& json_value) -> Status { |
857 | 80 | json_value.AddMember("idx_file_path", rapidjson::Value(path.c_str(), allocator), |
858 | 80 | allocator); |
859 | 80 | int64_t idx_file_size = 0; |
860 | 80 | auto st = fs->file_size(path, &idx_file_size); |
861 | 80 | if (st != Status::OK()) { |
862 | 0 | LOG(WARNING) << "show nested index file get file size error, file: " << path |
863 | 0 | << ", error: " << st.msg(); |
864 | 0 | return st; |
865 | 0 | } |
866 | 80 | json_value.AddMember("idx_file_size", rapidjson::Value(idx_file_size).Move(), |
867 | 80 | allocator); |
868 | 80 | return Status::OK(); |
869 | 80 | }; |
870 | | |
871 | 74 | auto process_files = [&allocator, &index_file_reader](auto& index_meta, |
872 | 74 | rapidjson::Value& indices, |
873 | 140 | rapidjson::Value& index) -> Status { |
874 | 140 | rapidjson::Value files_value(rapidjson::kArrayType); |
875 | 140 | std::vector<std::string> files; |
876 | 140 | auto ret = index_file_reader->open(&index_meta); |
877 | 140 | if (!ret.has_value()) { |
878 | 0 | LOG(INFO) << "IndexFileReader open error:" << ret.error(); |
879 | 0 | return Status::InternalError("IndexFileReader open error"); |
880 | 0 | } |
881 | 140 | using T = std::decay_t<decltype(ret)>; |
882 | 140 | auto reader = std::forward<T>(ret).value(); |
883 | 140 | reader->list(&files); |
884 | 860 | for (auto& file : files) { |
885 | 860 | rapidjson::Value file_value(rapidjson::kObjectType); |
886 | 860 | auto size = reader->fileLength(file.c_str()); |
887 | 860 | file_value.AddMember("name", rapidjson::Value(file.c_str(), allocator), allocator); |
888 | 860 | file_value.AddMember("size", rapidjson::Value(size).Move(), allocator); |
889 | 860 | files_value.PushBack(file_value, allocator); |
890 | 860 | } |
891 | 140 | index.AddMember("files", files_value, allocator); |
892 | 140 | indices.PushBack(index, allocator); |
893 | 140 | return Status::OK(); |
894 | 140 | }; beta_rowset.cpp:_ZZN5doris10BetaRowset22show_nested_index_fileEPN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERS7_ENK3$_0clINS_11TabletIndexEEENS_6StatusERT_RS8_SH_ Line | Count | Source | 873 | 128 | rapidjson::Value& index) -> Status { | 874 | 128 | rapidjson::Value files_value(rapidjson::kArrayType); | 875 | 128 | std::vector<std::string> files; | 876 | 128 | auto ret = index_file_reader->open(&index_meta); | 877 | 128 | if (!ret.has_value()) { | 878 | 0 | LOG(INFO) << "IndexFileReader open error:" << ret.error(); | 879 | 0 | return Status::InternalError("IndexFileReader open error"); | 880 | 0 | } | 881 | 128 | using T = std::decay_t<decltype(ret)>; | 882 | 128 | auto reader = std::forward<T>(ret).value(); | 883 | 128 | reader->list(&files); | 884 | 788 | for (auto& file : files) { | 885 | 788 | rapidjson::Value file_value(rapidjson::kObjectType); | 886 | 788 | auto size = reader->fileLength(file.c_str()); | 887 | 788 | file_value.AddMember("name", rapidjson::Value(file.c_str(), allocator), allocator); | 888 | 788 | file_value.AddMember("size", rapidjson::Value(size).Move(), allocator); | 889 | 788 | files_value.PushBack(file_value, allocator); | 890 | 788 | } | 891 | 128 | index.AddMember("files", files_value, allocator); | 892 | 128 | indices.PushBack(index, allocator); | 893 | 128 | return Status::OK(); | 894 | 128 | }; |
beta_rowset.cpp:_ZZN5doris10BetaRowset22show_nested_index_fileEPN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERS7_ENK3$_0clIKNS_11TabletIndexEEENS_6StatusERT_RS8_SI_ Line | Count | Source | 873 | 12 | rapidjson::Value& index) -> Status { | 874 | 12 | rapidjson::Value files_value(rapidjson::kArrayType); | 875 | 12 | std::vector<std::string> files; | 876 | 12 | auto ret = index_file_reader->open(&index_meta); | 877 | 12 | if (!ret.has_value()) { | 878 | 0 | LOG(INFO) << "IndexFileReader open error:" << ret.error(); | 879 | 0 | return Status::InternalError("IndexFileReader open error"); | 880 | 0 | } | 881 | 12 | using T = std::decay_t<decltype(ret)>; | 882 | 12 | auto reader = std::forward<T>(ret).value(); | 883 | 12 | reader->list(&files); | 884 | 72 | for (auto& file : files) { | 885 | 72 | rapidjson::Value file_value(rapidjson::kObjectType); | 886 | 72 | auto size = reader->fileLength(file.c_str()); | 887 | 72 | file_value.AddMember("name", rapidjson::Value(file.c_str(), allocator), allocator); | 888 | 72 | file_value.AddMember("size", rapidjson::Value(size).Move(), allocator); | 889 | 72 | files_value.PushBack(file_value, allocator); | 890 | 72 | } | 891 | 12 | index.AddMember("files", files_value, allocator); | 892 | 12 | indices.PushBack(index, allocator); | 893 | 12 | return Status::OK(); | 894 | 12 | }; |
|
895 | | |
896 | 74 | if (storage_format != InvertedIndexStorageFormatPB::V1) { |
897 | 68 | auto path = InvertedIndexDescriptor::get_index_file_path_v2(index_file_path_prefix); |
898 | 68 | auto st = add_file_info_to_json(path, segment); |
899 | 68 | if (!st.ok()) { |
900 | 0 | return st; |
901 | 0 | } |
902 | 68 | rapidjson::Value indices(rapidjson::kArrayType); |
903 | 128 | for (auto& dir : *dirs) { |
904 | 128 | rapidjson::Value index(rapidjson::kObjectType); |
905 | 128 | auto index_id = dir.first.first; |
906 | 128 | auto index_suffix = dir.first.second; |
907 | 128 | index.AddMember("index_id", rapidjson::Value(index_id).Move(), allocator); |
908 | 128 | index.AddMember("index_suffix", rapidjson::Value(index_suffix.c_str(), allocator), |
909 | 128 | allocator); |
910 | | |
911 | 128 | rapidjson::Value files_value(rapidjson::kArrayType); |
912 | 128 | std::vector<std::string> files; |
913 | 128 | doris::TabletIndexPB index_pb; |
914 | 128 | index_pb.set_index_id(index_id); |
915 | 128 | index_pb.set_index_suffix_name(index_suffix); |
916 | 128 | TabletIndex index_meta; |
917 | 128 | index_meta.init_from_pb(index_pb); |
918 | | |
919 | 128 | auto status = process_files(index_meta, indices, index); |
920 | 128 | if (!status.ok()) { |
921 | 0 | return status; |
922 | 0 | } |
923 | 128 | } |
924 | 68 | segment.AddMember("indices", indices, allocator); |
925 | 68 | segments.PushBack(segment, allocator); |
926 | 68 | } else { |
927 | 6 | rapidjson::Value indices(rapidjson::kArrayType); |
928 | 18 | for (auto column : _rowset_meta->tablet_schema()->columns()) { |
929 | 18 | auto index_metas = _rowset_meta->tablet_schema()->inverted_indexs(*column); |
930 | 18 | for (const auto& index_meta : index_metas) { |
931 | 12 | rapidjson::Value index(rapidjson::kObjectType); |
932 | 12 | auto index_id = index_meta->index_id(); |
933 | 12 | auto index_suffix = index_meta->get_index_suffix(); |
934 | 12 | index.AddMember("index_id", rapidjson::Value(index_id).Move(), allocator); |
935 | 12 | index.AddMember("index_suffix", |
936 | 12 | rapidjson::Value(index_suffix.c_str(), allocator), allocator); |
937 | 12 | auto path = InvertedIndexDescriptor::get_index_file_path_v1( |
938 | 12 | index_file_path_prefix, index_id, index_suffix); |
939 | 12 | RETURN_IF_ERROR(add_file_info_to_json(path, index)); |
940 | 12 | RETURN_IF_ERROR(process_files(*index_meta, indices, index)); |
941 | 12 | } |
942 | 18 | } |
943 | 6 | segment.AddMember("indices", indices, allocator); |
944 | 6 | segments.PushBack(segment, allocator); |
945 | 6 | } |
946 | 74 | } |
947 | 146 | rowset_value->AddMember("segments", segments, allocator); |
948 | 146 | return Status::OK(); |
949 | 147 | } |
950 | | } // namespace doris |