Coverage Report

Created: 2026-10-28 17:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/index/index_file_reader.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
// CLucene is third-party code and is not clean under -Wconversion (which
21
// -Wshorten-64-to-32 belongs to). Whether its first expansion lands inside
22
// someone else's suppressed region depends on include order, so suppress it
23
// deliberately here (same pattern as index_common_impl.h).
24
#ifdef __clang__
25
#pragma clang diagnostic push
26
#pragma clang diagnostic ignored "-Wconversion"
27
#endif
28
#include <CLucene.h> // IWYU pragma: keep
29
#include <CLucene/store/IndexInput.h>
30
#ifdef __clang__
31
#pragma clang diagnostic pop
32
#endif
33
34
#include <gen_cpp/olap_file.pb.h>
35
36
#include <map>
37
#include <memory>
38
#include <mutex>
39
#include <shared_mutex>
40
#include <string>
41
#include <unordered_map>
42
#include <utility>
43
#include <vector>
44
45
#include "common/be_mock_util.h"
46
#include "common/config.h"
47
#include "io/fs/file_system.h"
48
#include "storage/index/index_file_writer.h"
49
#include "storage/index/inverted/common/inverted_index_desc.h"
50
#include "storage/index/inverted/snii/reader/logical_index_reader.h"
51
#include "storage/index/inverted/snii/reader/snii_segment_reader.h"
52
#include "storage/index/inverted/snii/snii_bkd_searcher.h"
53
#include "storage/index/inverted/snii/snii_doris_adapter.h"
54
55
namespace doris {
56
class TabletIndex;
57
namespace segment_v2 {
58
class ReaderFileEntry;
59
class DorisCompoundReader;
60
61
// A singleton class responsible for reading index files, managing file entries, and providing interfaces to access index data.
62
// The singleton object is at segment level, and it is shared by all threads that read the same segment (even across different queries).
63
// It is created when the first index reader is initialized, and destroyed when the segment is closed.
64
class IndexFileReader {
65
public:
66
    // Modern C++ using std::unordered_map with smart pointers for automatic memory management
67
    using EntriesType = std::unordered_map<std::string, std::unique_ptr<ReaderFileEntry>>;
68
    // Map to hold the file entries for each index ID.
69
    using IndicesEntriesMap =
70
            std::map<std::pair<int64_t, std::string>, std::unique_ptr<EntriesType>>;
71
72
    IndexFileReader(io::FileSystemSPtr fs, std::string index_path_prefix,
73
                    InvertedIndexStorageFormatPB storage_format,
74
                    InvertedIndexFileInfo idx_file_info = InvertedIndexFileInfo(),
75
                    int64_t tablet_id = -1)
76
3.65k
            : _fs(std::move(fs)),
77
3.65k
              _index_path_prefix(std::move(index_path_prefix)),
78
3.65k
              _storage_format(storage_format),
79
3.65k
              _idx_file_info(std::move(idx_file_info)),
80
3.65k
              _tablet_id(tablet_id) {}
81
3.65k
    virtual ~IndexFileReader() = default;
82
83
    MOCK_FUNCTION Status init(int32_t read_buffer_size = config::inverted_index_read_buffer_size,
84
                              const io::IOContext* io_ctx = nullptr);
85
    MOCK_FUNCTION Result<std::unique_ptr<DorisCompoundReader, DirectoryDeleter>> open(
86
            const TabletIndex* index_meta, const io::IOContext* io_ctx = nullptr) const;
87
    // Opens one BLOB logical index of kind kBkd: resolves its named sub-files
88
    // (bkd_data / bkd_index / bkd_nulls) into extents through the CONTAINER's own
89
    // directory and hands back a reader bound to this IndexFileReader's file.
90
    // The caller must keep this IndexFileReader alive for the reader's lifetime,
91
    // exactly as open_snii_index requires.
92
    Result<std::unique_ptr<doris::snii::bkd::BkdSearcher>> open_snii_bkd_index(
93
            const TabletIndex* index_meta, const io::IOContext* io_ctx) const;
94
    Result<std::unique_ptr<doris::snii::reader::LogicalIndexReader>> open_snii_index(
95
            const TabletIndex* index_meta, const io::IOContext* io_ctx = nullptr,
96
            doris::snii::reader::LogicalIndexOpenMode open_mode =
97
                    doris::snii::reader::LogicalIndexOpenMode::kQuery) const;
98
    // SNII only: opens one text logical index by its directory key.
99
    Result<std::unique_ptr<doris::snii::reader::LogicalIndexReader>> open_snii_logical_index(
100
            uint64_t index_id, std::string_view suffix, const io::IOContext* io_ctx,
101
            doris::snii::reader::LogicalIndexOpenMode open_mode) const;
102
    // SNII only: every entry of the container directory, text and blob kinds alike.
103
    Result<std::vector<doris::snii::format::LogicalIndexMetadataRef>> snii_logical_indexes() const;
104
    // SNII only: reads the CoreMetadata of one text logical index with the caller's IO context.
105
    Status snii_core_metadata(uint64_t index_id, std::string_view suffix,
106
                              doris::snii::format::CoreMetadata* out,
107
                              const io::IOContext* io_ctx = nullptr) const;
108
    // SNII only: builds the fully validated inheritance view of this container
109
    // for a BUILD INDEX rewrite. `segment_doc_count` is the segment's row count;
110
    // every kept logical index must agree with it.
111
    Status prepare_snii_rewrite_snapshot(
112
            const std::vector<doris::snii::reader::LogicalIndexKey>& keep,
113
            uint64_t segment_doc_count, doris::snii::reader::SniiRewriteSnapshot* out) const;
114
    // SNII only: the raw byte source backing this container, handed to
115
    // SniiCompoundWriter::inherit for the sequential prefix copy.
116
4
    doris::snii::io::FileReader* snii_io_reader() const { return _snii_file_reader.get(); }
117
    // SNII only: true when the opened container holds a blob logical index
118
    // (BKD / ANN). False when this reader opened no SNII container at all.
119
3
    bool snii_has_blob_index() const {
120
3
        std::shared_lock<std::shared_mutex> lock(_mutex);
121
3
        return _snii_segment_reader != nullptr && _snii_segment_reader->has_blob_index();
122
3
    }
123
    void debug_file_entries();
124
    std::string get_index_file_cache_key(const TabletIndex* index_meta) const;
125
    std::string get_index_file_path(const TabletIndex* index_meta) const;
126
    Status index_file_exist(const TabletIndex* index_meta, bool* res) const;
127
    Status has_null(const TabletIndex* index_meta, bool* res) const;
128
    Result<InvertedIndexDirectoryMap> get_all_directories();
129
    // open file v2, init _stream
130
19
    int64_t get_inverted_file_size() const {
131
19
        if (_storage_format == InvertedIndexStorageFormatPB::SNII) {
132
10
            return _snii_file_reader == nullptr ? 0 : _snii_file_reader->size();
133
10
        }
134
9
        return _stream == nullptr ? 0 : _stream->length();
135
19
    }
136
39
    const std::string& get_index_path_prefix() const { return _index_path_prefix; }
137
2.79k
    InvertedIndexStorageFormatPB get_storage_format() const { return _storage_format; }
138
    friend IndexFileWriter;
139
140
protected:
141
    Status _init_from(int32_t read_buffer_size, const io::IOContext* io_ctx);
142
    Status _init_snii(const io::IOContext* io_ctx);
143
    Result<std::unique_ptr<DorisCompoundReader, DirectoryDeleter>> _open(
144
            int64_t index_id, const std::string& index_suffix,
145
            const io::IOContext* io_ctx = nullptr) const;
146
147
private:
148
    IndicesEntriesMap _indices_entries;
149
    std::unique_ptr<CL_NS(store)::IndexInput> _stream = nullptr;
150
    std::shared_ptr<snii_doris::DorisSniiFileReader> _snii_file_reader;
151
    std::unique_ptr<doris::snii::reader::SniiSegmentReader> _snii_segment_reader;
152
    const io::FileSystemSPtr _fs;
153
    std::string _index_path_prefix;
154
    int32_t _read_buffer_size = -1;
155
    InvertedIndexStorageFormatPB _storage_format;
156
    mutable std::shared_mutex _mutex; // Use mutable for const read operations
157
    bool _inited = false;
158
    InvertedIndexFileInfo _idx_file_info;
159
    int64_t _tablet_id = -1;
160
};
161
162
} // namespace segment_v2
163
} // namespace doris