Coverage Report

Created: 2026-07-15 03:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
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
11.7k
        : Rowset(schema, rowset_meta, std::move(tablet_path)) {}
68
69
11.7k
BetaRowset::~BetaRowset() = default;
70
71
6.43k
Status BetaRowset::init() {
72
6.43k
    return Status::OK(); // no op
73
6.43k
}
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
2
                                     const io::IOContext* io_ctx) {
80
2
    SegmentCacheHandle segment_cache_handle;
81
2
    RETURN_IF_ERROR(SegmentLoader::instance()->load_segments(
82
2
            rowset, &segment_cache_handle, enable_segment_cache, false, read_stats, io_ctx));
83
0
    for (const auto& segment : segment_cache_handle.get_segments()) {
84
0
        segment_rows->emplace_back(segment->num_rows());
85
0
    }
86
0
    return Status::OK();
87
2
}
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
0
                                      int64_t tablet_id, const std::string& rowset_id) {
92
0
    DCHECK_EQ(rows_from_footer.size(), rows_from_meta.size());
93
0
    for (size_t i = 0; i < rows_from_footer.size(); i++) {
94
0
        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
0
    }
105
0
    return Status::OK();
106
0
}
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
498
                                        const io::IOContext* io_ctx) {
112
#ifndef BE_TEST
113
    // `ROWSET_UNLOADING` is state for closed() called but owned by some readers.
114
    // So here `ROWSET_UNLOADING` is allowed.
115
    DCHECK_NE(_rowset_state_machine.rowset_state(), ROWSET_UNLOADED);
116
#endif
117
498
    RETURN_IF_ERROR(_load_segment_rows_once.call([this, enable_segment_cache, read_stats, io_ctx] {
118
498
        auto segment_count = num_segments();
119
498
        if (segment_count == 0) {
120
498
            return Status::OK();
121
498
        }
122
123
498
        if (!_rowset_meta->get_num_segment_rows().empty()) {
124
498
            if (_rowset_meta->get_num_segment_rows().size() == segment_count) {
125
                // use segment rows in rowset meta if eligible
126
498
                TEST_SYNC_POINT("BetaRowset::get_segment_num_rows:use_segment_rows_from_meta");
127
498
                _segments_rows.assign(_rowset_meta->get_num_segment_rows().cbegin(),
128
498
                                      _rowset_meta->get_num_segment_rows().cend());
129
498
                if (config::enable_segment_rows_consistency_check) {
130
                    // verify segment rows from meta match segment footer
131
498
                    std::vector<uint32_t> rows_from_footer;
132
498
                    auto self = std::dynamic_pointer_cast<BetaRowset>(shared_from_this());
133
498
                    auto load_status = load_segment_rows_from_footer(
134
498
                            self, &rows_from_footer, enable_segment_cache, read_stats, io_ctx);
135
498
                    if (load_status.ok()) {
136
498
                        return check_segment_rows_consistency(
137
498
                                _segments_rows, rows_from_footer, _rowset_meta->tablet_id(),
138
498
                                _rowset_meta->rowset_id().to_string());
139
498
                    }
140
498
                }
141
498
                return Status::OK();
142
498
            } else {
143
498
                auto msg = fmt::format(
144
498
                        "[verbose] corrupted segment rows info in rowset meta. "
145
498
                        "segment count: {}, segment rows size: {}, tablet={}, rowset={}",
146
498
                        segment_count, _rowset_meta->get_num_segment_rows().size(),
147
498
                        _rowset_meta->tablet_id(), _rowset_meta->rowset_id().to_string());
148
498
                if (config::enable_segment_rows_check_core) {
149
498
                    CHECK(false) << msg;
150
498
                }
151
498
                LOG_EVERY_SECOND(WARNING) << msg;
152
498
            }
153
498
        }
154
498
        if (config::fail_when_segment_rows_not_in_rowset_meta) {
155
498
            CHECK(false) << "[verbose] segment rows info not found in rowset meta. tablet="
156
498
                         << _rowset_meta->tablet_id()
157
498
                         << ", rowset=" << _rowset_meta->rowset_id().to_string()
158
498
                         << ", version=" << _rowset_meta->version()
159
498
                         << ", debug_string=" << _rowset_meta->debug_string()
160
498
                         << ", stack=" << Status::InternalError("error");
161
498
        }
162
        // otherwise, read it from segment footer
163
498
        TEST_SYNC_POINT("BetaRowset::get_segment_num_rows:load_from_segment_footer");
164
498
        auto self = std::dynamic_pointer_cast<BetaRowset>(shared_from_this());
165
498
        return load_segment_rows_from_footer(self, &_segments_rows, enable_segment_cache,
166
498
                                             read_stats, io_ctx);
167
498
    }));
168
496
    segment_rows->assign(_segments_rows.cbegin(), _segments_rows.cend());
169
496
    return Status::OK();
170
498
}
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
10.4k
void BetaRowset::clear_inverted_index_cache() {
208
10.4k
    for (int i = 0; i < num_segments(); ++i) {
209
9
        auto seg_path = segment_path(i);
210
9
        if (!seg_path) {
211
0
            continue;
212
0
        }
213
214
9
        auto index_path_prefix = InvertedIndexDescriptor::get_index_file_path_prefix(*seg_path);
215
50
        for (const auto& column : tablet_schema()->columns()) {
216
50
            auto index_metas = tablet_schema()->inverted_indexs(*column);
217
50
            for (const auto& index_meta : index_metas) {
218
0
                auto inverted_index_file_cache_key =
219
0
                        InvertedIndexDescriptor::get_index_file_cache_key(
220
0
                                index_path_prefix, index_meta->index_id(),
221
0
                                index_meta->get_index_suffix());
222
0
                (void)segment_v2::InvertedIndexSearcherCache::instance()->erase(
223
0
                        inverted_index_file_cache_key);
224
0
            }
225
50
        }
226
9
    }
227
10.4k
}
228
229
87
Status BetaRowset::get_segments_size(std::vector<size_t>* segments_size) {
230
87
    auto fs = _rowset_meta->fs();
231
87
    if (!fs) {
232
0
        return Status::Error<INIT_FAILED>("get fs failed, resource_id={}",
233
0
                                          _rowset_meta->resource_id());
234
0
    }
235
236
184
    for (int seg_id = 0; seg_id < num_segments(); ++seg_id) {
237
98
        auto seg_path = DORIS_TRY(segment_path(seg_id));
238
98
        int64_t file_size;
239
98
        RETURN_IF_ERROR(fs->file_size(seg_path, &file_size));
240
97
        segments_size->push_back(file_size);
241
97
    }
242
86
    return Status::OK();
243
87
}
244
245
219
Status BetaRowset::load_segments(std::vector<segment_v2::SegmentSharedPtr>* segments) {
246
219
    return load_segments(0, num_segments(), segments);
247
219
}
248
249
Status BetaRowset::load_segments(int64_t seg_id_begin, int64_t seg_id_end,
250
282
                                 std::vector<segment_v2::SegmentSharedPtr>* segments) {
251
282
    int64_t seg_id = seg_id_begin;
252
663
    while (seg_id < seg_id_end) {
253
384
        std::shared_ptr<segment_v2::Segment> segment;
254
384
        RETURN_IF_ERROR(load_segment(seg_id, nullptr, &segment));
255
381
        segments->push_back(std::move(segment));
256
381
        seg_id++;
257
381
    }
258
279
    return Status::OK();
259
282
}
260
261
Status BetaRowset::load_segment(int64_t seg_id, OlapReaderStatistics* stats,
262
                                segment_v2::SegmentSharedPtr* segment,
263
3.65k
                                const io::IOContext* io_ctx) {
264
3.65k
    auto fs = _rowset_meta->fs();
265
3.65k
    if (!fs) {
266
1
        return Status::Error<INIT_FAILED>("get fs failed");
267
1
    }
268
269
3.65k
    DCHECK(seg_id >= 0);
270
3.65k
    auto seg_path = DORIS_TRY(segment_path(seg_id));
271
3.65k
    io::FileReaderOptions reader_options {
272
3.65k
            .cache_type = config::enable_file_cache ? io::FileCachePolicy::FILE_BLOCK_CACHE
273
3.65k
                                                    : io::FileCachePolicy::NO_CACHE,
274
3.65k
            .is_doris_table = true,
275
3.65k
            .cache_base_path = "",
276
3.65k
            .file_size = _rowset_meta->segment_file_size(static_cast<int>(seg_id)),
277
3.65k
            .tablet_id = _rowset_meta->tablet_id(),
278
3.65k
            .storage_resource_id = _rowset_meta->resource_id(),
279
3.65k
    };
280
281
3.65k
    auto s = segment_v2::Segment::open(
282
3.65k
            fs, seg_path, _rowset_meta->tablet_id(), static_cast<uint32_t>(seg_id), rowset_id(),
283
3.65k
            _schema, reader_options, segment,
284
3.65k
            _rowset_meta->inverted_index_file_info(static_cast<int>(seg_id)), stats, io_ctx);
285
3.65k
    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
3.65k
    return Status::OK();
291
3.65k
}
292
293
1.06k
Status BetaRowset::create_reader(RowsetReaderSharedPtr* result) {
294
    // NOTE: We use std::static_pointer_cast for performance
295
1.06k
    result->reset(new BetaRowsetReader(std::static_pointer_cast<BetaRowset>(shared_from_this())));
296
1.06k
    return Status::OK();
297
1.06k
}
298
299
10
Status BetaRowset::remove() {
300
10
    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
10
    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
10
    clear_cache();
311
312
10
    bool success = true;
313
10
    Status st;
314
10
    const auto& fs = io::global_local_filesystem();
315
12
    for (int i = 0; i < num_segments(); ++i) {
316
2
        auto seg_path = local_segment_path(_tablet_path, rowset_id().to_string(), i);
317
2
        LOG(INFO) << "deleting " << seg_path;
318
2
        st = fs->delete_file(seg_path);
319
2
        if (!st.ok()) {
320
0
            LOG(WARNING) << st.to_string();
321
0
            success = false;
322
0
        }
323
324
2
        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
2
        } else {
340
2
            if (_schema->has_inverted_index() || _schema->has_ann_index()) {
341
0
                std::string inverted_index_file = InvertedIndexDescriptor::get_index_file_path_v2(
342
0
                        InvertedIndexDescriptor::get_index_file_path_prefix(seg_path));
343
0
                st = fs->delete_file(inverted_index_file);
344
0
                if (!st.ok()) {
345
0
                    LOG(WARNING) << st.to_string();
346
0
                    success = false;
347
0
                }
348
0
            }
349
2
        }
350
2
    }
351
10
    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
10
    return Status::OK();
356
10
}
357
358
4
void BetaRowset::do_close() {
359
    // do nothing.
360
4
}
361
362
Status BetaRowset::link_files_to(const std::string& dir, RowsetId new_rowset_id,
363
                                 size_t new_rowset_start_seg_id,
364
76
                                 std::set<int64_t>* without_index_uids) {
365
76
    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
76
    const auto& local_fs = io::global_local_filesystem();
372
76
    Status status;
373
76
    std::vector<std::string> linked_success_files;
374
76
    Defer remove_linked_files {[&]() { // clear linked files if errors happen
375
76
        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
76
    }};
386
387
155
    for (int i = 0; i < num_segments(); ++i) {
388
79
        auto dst_path =
389
79
                local_segment_path(dir, new_rowset_id.to_string(), i + new_rowset_start_seg_id);
390
79
        bool dst_path_exist = false;
391
79
        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
79
        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
79
        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
79
        linked_success_files.push_back(dst_path);
405
79
        DBUG_EXECUTE_IF("fault_inject::BetaRowset::link_files_to::_link_inverted_index_file", {
406
79
            status = Status::Error<OS_ERROR>("fault_inject link_file error");
407
79
            return status;
408
79
        });
409
79
        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
40
        } else {
452
39
            if ((_schema->has_inverted_index() || _schema->has_ann_index()) &&
453
39
                (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
39
        }
478
79
    }
479
76
    return Status::OK();
480
76
}
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
0
Status BetaRowset::check_file_exist() {
602
0
    const auto& fs = _rowset_meta->fs();
603
0
    if (!fs) {
604
0
        return Status::InternalError("fs is not initialized, resource_id={}",
605
0
                                     _rowset_meta->resource_id());
606
0
    }
607
608
0
    for (int i = 0; i < num_segments(); ++i) {
609
0
        auto seg_path = DORIS_TRY(segment_path(i));
610
0
        bool seg_file_exist = false;
611
0
        RETURN_IF_ERROR(fs->exists(seg_path, &seg_file_exist));
612
0
        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
0
    }
617
618
0
    return Status::OK();
619
0
}
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
0
Status BetaRowset::calc_file_crc(uint32_t* crc_value, int64_t* file_count) {
755
0
    const auto& fs = _rowset_meta->fs();
756
0
    DBUG_EXECUTE_IF("fault_inject::BetaRowset::calc_file_crc",
757
0
                    { return Status::Error<OS_ERROR>("fault_inject calc_file_crc error"); });
758
0
    if (num_segments() < 1) {
759
0
        *crc_value = 0x92a8fc17; // magic code from crc32c table
760
0
        return Status::OK();
761
0
    }
762
763
    // 1. pick up all the files including dat file and idx file
764
0
    std::vector<io::Path> file_paths;
765
0
    for (int seg_id = 0; seg_id < num_segments(); ++seg_id) {
766
0
        auto seg_path = DORIS_TRY(segment_path(seg_id));
767
0
        file_paths.emplace_back(seg_path);
768
0
        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
0
        } else {
780
0
            if (_schema->has_inverted_index() || _schema->has_ann_index()) {
781
0
                std::string inverted_index_file = InvertedIndexDescriptor::get_index_file_path_v2(
782
0
                        InvertedIndexDescriptor::get_index_file_path_prefix(seg_path));
783
0
                file_paths.emplace_back(std::move(inverted_index_file));
784
0
            }
785
0
        }
786
0
    }
787
0
    *crc_value = 0;
788
0
    *file_count = file_paths.size();
789
0
    if (!is_local()) {
790
0
        return Status::OK();
791
0
    }
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
0
                                          rapidjson::Document::AllocatorType& allocator) {
821
0
    const auto& fs = _rowset_meta->fs();
822
0
    auto storage_format = _schema->get_inverted_index_storage_format();
823
0
    std::string format_str;
824
0
    switch (storage_format) {
825
0
    case InvertedIndexStorageFormatPB::V1:
826
0
        format_str = "V1";
827
0
        break;
828
0
    case InvertedIndexStorageFormatPB::V2:
829
0
        format_str = "V2";
830
0
        break;
831
0
    case InvertedIndexStorageFormatPB::V3:
832
0
        format_str = "V3";
833
0
        break;
834
0
    default:
835
0
        return Status::InternalError("inverted index storage format error");
836
0
        break;
837
0
    }
838
0
    auto rs_id = rowset_id().to_string();
839
0
    rowset_value->AddMember("rowset_id", rapidjson::Value(rs_id.c_str(), allocator), allocator);
840
0
    rowset_value->AddMember("index_storage_format", rapidjson::Value(format_str.c_str(), allocator),
841
0
                            allocator);
842
0
    rapidjson::Value segments(rapidjson::kArrayType);
843
0
    for (int seg_id = 0; seg_id < num_segments(); ++seg_id) {
844
0
        rapidjson::Value segment(rapidjson::kObjectType);
845
0
        segment.AddMember("segment_id", rapidjson::Value(seg_id).Move(), allocator);
846
847
0
        auto seg_path = DORIS_TRY(segment_path(seg_id));
848
0
        auto index_file_path_prefix = InvertedIndexDescriptor::get_index_file_path_prefix(seg_path);
849
0
        auto index_file_reader = std::make_unique<IndexFileReader>(
850
0
                fs, std::string(index_file_path_prefix), storage_format, InvertedIndexFileInfo(),
851
0
                _rowset_meta->tablet_id());
852
0
        RETURN_IF_ERROR(index_file_reader->init());
853
0
        auto dirs = index_file_reader->get_all_directories();
854
855
0
        auto add_file_info_to_json = [&](const std::string& path,
856
0
                                         rapidjson::Value& json_value) -> Status {
857
0
            json_value.AddMember("idx_file_path", rapidjson::Value(path.c_str(), allocator),
858
0
                                 allocator);
859
0
            int64_t idx_file_size = 0;
860
0
            auto st = fs->file_size(path, &idx_file_size);
861
0
            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
0
            json_value.AddMember("idx_file_size", rapidjson::Value(idx_file_size).Move(),
867
0
                                 allocator);
868
0
            return Status::OK();
869
0
        };
870
871
0
        auto process_files = [&allocator, &index_file_reader](auto& index_meta,
872
0
                                                              rapidjson::Value& indices,
873
0
                                                              rapidjson::Value& index) -> Status {
874
0
            rapidjson::Value files_value(rapidjson::kArrayType);
875
0
            std::vector<std::string> files;
876
0
            auto ret = index_file_reader->open(&index_meta);
877
0
            if (!ret.has_value()) {
878
0
                LOG(INFO) << "IndexFileReader open error:" << ret.error();
879
0
                return Status::InternalError("IndexFileReader open error");
880
0
            }
881
0
            using T = std::decay_t<decltype(ret)>;
882
0
            auto reader = std::forward<T>(ret).value();
883
0
            reader->list(&files);
884
0
            for (auto& file : files) {
885
0
                rapidjson::Value file_value(rapidjson::kObjectType);
886
0
                auto size = reader->fileLength(file.c_str());
887
0
                file_value.AddMember("name", rapidjson::Value(file.c_str(), allocator), allocator);
888
0
                file_value.AddMember("size", rapidjson::Value(size).Move(), allocator);
889
0
                files_value.PushBack(file_value, allocator);
890
0
            }
891
0
            index.AddMember("files", files_value, allocator);
892
0
            indices.PushBack(index, allocator);
893
0
            return Status::OK();
894
0
        };
Unexecuted instantiation: beta_rowset.cpp:_ZZN5doris10BetaRowset22show_nested_index_fileEPN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERS7_ENK3$_0clINS_11TabletIndexEEENS_6StatusERT_RS8_SH_
Unexecuted instantiation: beta_rowset.cpp:_ZZN5doris10BetaRowset22show_nested_index_fileEPN9rapidjson12GenericValueINS1_4UTF8IcEENS1_19MemoryPoolAllocatorINS1_12CrtAllocatorEEEEERS7_ENK3$_0clIKNS_11TabletIndexEEENS_6StatusERT_RS8_SI_
895
896
0
        if (storage_format != InvertedIndexStorageFormatPB::V1) {
897
0
            auto path = InvertedIndexDescriptor::get_index_file_path_v2(index_file_path_prefix);
898
0
            auto st = add_file_info_to_json(path, segment);
899
0
            if (!st.ok()) {
900
0
                return st;
901
0
            }
902
0
            rapidjson::Value indices(rapidjson::kArrayType);
903
0
            for (auto& dir : *dirs) {
904
0
                rapidjson::Value index(rapidjson::kObjectType);
905
0
                auto index_id = dir.first.first;
906
0
                auto index_suffix = dir.first.second;
907
0
                index.AddMember("index_id", rapidjson::Value(index_id).Move(), allocator);
908
0
                index.AddMember("index_suffix", rapidjson::Value(index_suffix.c_str(), allocator),
909
0
                                allocator);
910
911
0
                rapidjson::Value files_value(rapidjson::kArrayType);
912
0
                std::vector<std::string> files;
913
0
                doris::TabletIndexPB index_pb;
914
0
                index_pb.set_index_id(index_id);
915
0
                index_pb.set_index_suffix_name(index_suffix);
916
0
                TabletIndex index_meta;
917
0
                index_meta.init_from_pb(index_pb);
918
919
0
                auto status = process_files(index_meta, indices, index);
920
0
                if (!status.ok()) {
921
0
                    return status;
922
0
                }
923
0
            }
924
0
            segment.AddMember("indices", indices, allocator);
925
0
            segments.PushBack(segment, allocator);
926
0
        } else {
927
0
            rapidjson::Value indices(rapidjson::kArrayType);
928
0
            for (auto column : _rowset_meta->tablet_schema()->columns()) {
929
0
                auto index_metas = _rowset_meta->tablet_schema()->inverted_indexs(*column);
930
0
                for (const auto& index_meta : index_metas) {
931
0
                    rapidjson::Value index(rapidjson::kObjectType);
932
0
                    auto index_id = index_meta->index_id();
933
0
                    auto index_suffix = index_meta->get_index_suffix();
934
0
                    index.AddMember("index_id", rapidjson::Value(index_id).Move(), allocator);
935
0
                    index.AddMember("index_suffix",
936
0
                                    rapidjson::Value(index_suffix.c_str(), allocator), allocator);
937
0
                    auto path = InvertedIndexDescriptor::get_index_file_path_v1(
938
0
                            index_file_path_prefix, index_id, index_suffix);
939
0
                    RETURN_IF_ERROR(add_file_info_to_json(path, index));
940
0
                    RETURN_IF_ERROR(process_files(*index_meta, indices, index));
941
0
                }
942
0
            }
943
0
            segment.AddMember("indices", indices, allocator);
944
0
            segments.PushBack(segment, allocator);
945
0
        }
946
0
    }
947
0
    rowset_value->AddMember("segments", segments, allocator);
948
0
    return Status::OK();
949
0
}
950
} // namespace doris